[object Object]

← back to Designer Wallcoverings

nightly runner: chain-aware quota probe (proceed if ANY chain model has quota, not just flash) + portable timeout (gtimeout/timeout/none — macOS has no /usr/bin/timeout)

6f9d054faf3542619a9c85f8bcb66f02a933c569 · 2026-06-12 15:55:58 -0700 · Steve Abrams

Files touched

Diff

commit 6f9d054faf3542619a9c85f8bcb66f02a933c569
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Jun 12 15:55:58 2026 -0700

    nightly runner: chain-aware quota probe (proceed if ANY chain model has quota, not just flash) + portable timeout (gtimeout/timeout/none — macOS has no /usr/bin/timeout)
---
 DW-Programming/nightly-color-clean.sh | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/DW-Programming/nightly-color-clean.sh b/DW-Programming/nightly-color-clean.sh
index 7dc22ece..a68f1780 100755
--- a/DW-Programming/nightly-color-clean.sh
+++ b/DW-Programming/nightly-color-clean.sh
@@ -26,18 +26,26 @@ GEMINI_API_KEY="$(grep -E '^GEMINI_API_KEY=' "$SECRETS" | head -1 | cut -d= -f2-
 
 echo "=== $(date) nightly color-clean start ===" >> "$LOG"
 
-# quota probe — one cheap call. If it 429s, the daily quota hasn't reset / is
-# already spent; skip tonight rather than grind on failures.
-PROBE=$(curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=${GEMINI_API_KEY}" \
-  -H 'Content-Type: application/json' \
-  -d '{"contents":[{"parts":[{"text":"ok"}]}],"generationConfig":{"thinkingConfig":{"thinkingBudget":0},"maxOutputTokens":10}}')
-if echo "$PROBE" | grep -q '"error"'; then
-  echo "$(date): gemini quota unavailable — $(echo "$PROBE" | grep -oE '\"code\": *[0-9]+' | head -1). Skipping." >> "$LOG"
-  exit 0
+# quota probe — the cleaner uses a MODEL CHAIN (each model has its own per-day
+# free quota), so proceed if ANY chain model has quota; only skip if ALL are 429.
+HAVE_QUOTA=0
+for M in gemini-2.5-flash-lite gemini-2.5-flash gemini-2.5-pro; do
+  PROBE=$(curl -s "https://generativelanguage.googleapis.com/v1beta/models/${M}:generateContent?key=${GEMINI_API_KEY}" \
+    -H 'Content-Type: application/json' \
+    -d '{"contents":[{"parts":[{"text":"ok"}]}],"generationConfig":{"thinkingConfig":{"thinkingBudget":0},"maxOutputTokens":10}}')
+  echo "$PROBE" | grep -q '"error"' || { HAVE_QUOTA=1; echo "$(date): $M has quota — proceeding" >> "$LOG"; break; }
+done
+if [ "$HAVE_QUOTA" -eq 0 ]; then
+  echo "$(date): all chain models 429 — skipping tonight" >> "$LOG"; exit 0
 fi
 
-# resumable sweep, gentle concurrency, hard 2h cap (kills post-quota grind)
-/usr/bin/timeout 7200 node color-collection-cleaner-v2.js --all --conc 3 >> "$LOG" 2>&1
+# resumable sweep, gentle concurrency. Optional 2h cap (portable: gtimeout/timeout
+# if present, else none — with the model-chain an all-capped verdict returns instantly,
+# so a post-quota grind no longer happens and the cap is just a belt-and-suspenders).
+if command -v gtimeout >/dev/null 2>&1; then CAP="gtimeout 7200"
+elif command -v timeout >/dev/null 2>&1; then CAP="timeout 7200"
+else CAP=""; fi
+$CAP node color-collection-cleaner-v2.js --all --conc 3 >> "$LOG" 2>&1
 echo "--- report ---" >> "$LOG"
 node color-clean-report.js >> "$LOG" 2>&1
 echo "=== $(date) nightly color-clean end ===" >> "$LOG"

← 3fd98379 color cleaner v2: model-fallback chain (flash-lite→flash→pro  ·  back to Designer Wallcoverings  ·  nightly runner: durable completion ping — check-complete.js 4d3e325e →