← back to Rentv 2026
pr/jobs: cap convergence-controller re-ticks (runaway guard). The pending>0 branch re-enqueued the controller every 3min with tick+1 but never checked a max — a single job wedged in queued/running would re-tick FOREVER (none of the round/budget caps are reached while waiting), reintroducing exactly the unbounded-loop anti-pattern a prior Cody gate flagged. Added max_ticks (default 15 ≈ 45min) → stop('pending_stuck'). Verified bounded on a stuck job, normal drain unaffected
7c58dbc9e6bfc3fece683d06dfab7a74c512f3e4 · 2026-08-05 23:22:01 -0700 · Steve
Files touched
Diff
commit 7c58dbc9e6bfc3fece683d06dfab7a74c512f3e4
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Aug 5 23:22:01 2026 -0700
pr/jobs: cap convergence-controller re-ticks (runaway guard). The pending>0 branch re-enqueued the controller every 3min with tick+1 but never checked a max — a single job wedged in queued/running would re-tick FOREVER (none of the round/budget caps are reached while waiting), reintroducing exactly the unbounded-loop anti-pattern a prior Cody gate flagged. Added max_ticks (default 15 ≈ 45min) → stop('pending_stuck'). Verified bounded on a stuck job, normal drain unaffected
---
src/pr/jobs/index.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/pr/jobs/index.js b/src/pr/jobs/index.js
index d1023e10..b805f9b6 100644
--- a/src/pr/jobs/index.js
+++ b/src/pr/jobs/index.js
@@ -506,6 +506,7 @@ const handlers = {
const target = Number(p.target_pct) || 70;
const round = Number(p.round) || 1;
const maxRounds = Number(p.max_rounds) || 6;
+ const maxTicks = Number(p.max_ticks) || 15; // cap the "waiting for research to drain" re-ticks (~45 min) so a wedged job can't re-enqueue this controller forever
const gate = await settings.californiaGate();
const cov = gate.checks.contact_coverage;
const sweepCreated = Number((await db.one(
@@ -525,8 +526,11 @@ const handlers = {
return stateDoc;
};
if (pending > 0) { // research still draining — check again shortly, same round
+ // Bound the wait: a job wedged in queued/running would otherwise re-tick this controller
+ // every 3 min forever (none of the round/budget caps are reached while we're in this branch).
+ if ((p.tick || 0) >= maxTicks) return stop('pending_stuck');
await enqueue('convergence-controller', { ...p, tick: (p.tick || 0) + 1 }, { priority: 7, run_after: new Date(Date.now() + 3 * 60e3).toISOString() });
- return { waiting: pending, round, coverage_pct: cov.pct };
+ return { waiting: pending, round, tick: (p.tick || 0) + 1, coverage_pct: cov.pct };
}
if (cov.pass || cov.pct >= target) return stop('target_reached');
if (round > 1 && sweepCreated === 0) return stop('sweep_dry');
← f1d77cee auto-save: 2026-08-05T23:16:37 (7 files) — data/deals-regist
·
back to Rentv 2026
·
pr/jobs: Cody gate on convergence-controller — (1) singleton af6ccef9 →