[object Object]

← back to Model Arena

fix judgeTimeout: 8min→35min, PARTIAL exits non-zero to trigger wrapper alert (contrarian gate)

2b08a6e5fff241933895620fa2b8e42bbf11b0e7 · 2026-08-05 04:20:31 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit 2b08a6e5fff241933895620fa2b8e42bbf11b0e7
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Wed Aug 5 04:20:31 2026 -0700

    fix judgeTimeout: 8min→35min, PARTIAL exits non-zero to trigger wrapper alert (contrarian gate)
---
 scripts/daily-challenge.js | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/scripts/daily-challenge.js b/scripts/daily-challenge.js
index 767ed2f..746c0a1 100644
--- a/scripts/daily-challenge.js
+++ b/scripts/daily-challenge.js
@@ -42,21 +42,29 @@ const sleep = ms => new Promise(r => setTimeout(r, ms));
   const c = await req('POST', '/api/challenges', { title: pick.t, prompt: pick.p, models: LOCAL });
   if (!c.id) { console.error('create failed', c); process.exit(1); }
   console.log('created', c.id, '—', pick.t);
-  // poll until settled + judged (cap ~40 min; reduce sleep to 3s after runs settle)
+  // poll until settled + judged (cap ~45 min; reduce sleep to 3s after runs settle)
+  // judgeTimeout: observed max judge duration was 32min (Aug-04, 3/4 models errored on Mac1 down)
+  // → wait 35min post-settle before giving up on judging (contrarian fix: was 8min, too short)
+  const JUDGE_PATIENCE_MS = 35 * 60 * 1000;
   let settledAt = null;
-  for (let i = 0; i < 300; i++) {
+  for (let i = 0; i < 340; i++) {
     await sleep(settledAt ? 3000 : 8000);
     const cur = await req('GET', '/api/challenges/' + c.id);
     const settled = Array.isArray(cur.runs) && cur.runs.length > 0 &&
       cur.runs.every(r => r.status === 'done' || r.status === 'error');
     if (settled && !settledAt) settledAt = Date.now();
-    // exit success once judged, OR after runs settled for 8+ min with no judge (partial result)
-    const judgeTimeout = settledAt && (Date.now() - settledAt) > 8 * 60 * 1000;
-    if (settled && (!cur.judging && cur.judged_at || judgeTimeout)) {
+    const judgeTimeout = settledAt && (Date.now() - settledAt) > JUDGE_PATIENCE_MS;
+    if (settled && ((!cur.judging && cur.judged_at) || judgeTimeout)) {
       const done = cur.runs.filter(r => r.status === 'done').length;
-      const entry = { ts: new Date().toISOString(), id: c.id, title: pick.t, done, aiPick: cur.aiPick || null, partial: judgeTimeout && !cur.judged_at };
+      const isPartial = judgeTimeout && !cur.judged_at;
+      const entry = { ts: new Date().toISOString(), id: c.id, title: pick.t, done, aiPick: cur.aiPick || null, partial: isPartial };
       try { fs.appendFileSync(LOG, JSON.stringify(entry) + '\n'); } catch (e) { console.error('LOG APPEND FAILED', e); }
-      console.log(judgeTimeout ? 'PARTIAL (judge timeout)' : 'DONE', JSON.stringify(entry));
+      if (isPartial) {
+        // exit non-zero so the wrapper fires its CNCP + email alert for PARTIAL outcomes
+        console.error('PARTIAL (judge did not complete in ' + JUDGE_PATIENCE_MS/60000 + 'min after settle)', JSON.stringify(entry));
+        process.exit(2);
+      }
+      console.log('DONE', JSON.stringify(entry));
       return;
     }
   }

← 78f2e7e fix daily-challenge timeout: 40min cap + fast-poll after set  ·  back to Model Arena  ·  auto-save: 2026-08-05T07:40:04 (3 files) — data/challenges.j 1dcc3dc →