[object Object]

← back to Rentv

pr/jobs: surface anomalous convergence halts as an admin task (Cody cycle-16 follow-up). pending_stuck / duplicate_controller stops would otherwise halt the whole research pipeline SILENTLY (only convergence_state + audit, which nobody reads in real time). Now creates a pr_tasks item so an admin notices + can unstick. Normal terminal reasons (target_reached/sweep_dry/round_cap/budget_exhausted) don't alert. Best-effort try/catch so it never blocks the stop. Internal task write — safe, non-customer-facing

35976af2685b9d6d1cf8985f375461b4ef63e115 · 2026-08-05 23:52:55 -0700 · Steve

Files touched

Diff

commit 35976af2685b9d6d1cf8985f375461b4ef63e115
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Aug 5 23:52:55 2026 -0700

    pr/jobs: surface anomalous convergence halts as an admin task (Cody cycle-16 follow-up). pending_stuck / duplicate_controller stops would otherwise halt the whole research pipeline SILENTLY (only convergence_state + audit, which nobody reads in real time). Now creates a pr_tasks item so an admin notices + can unstick. Normal terminal reasons (target_reached/sweep_dry/round_cap/budget_exhausted) don't alert. Best-effort try/catch so it never blocks the stop. Internal task write — safe, non-customer-facing
---
 src/pr/jobs/index.js | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/pr/jobs/index.js b/src/pr/jobs/index.js
index 8c2e633d..8ad723bb 100644
--- a/src/pr/jobs/index.js
+++ b/src/pr/jobs/index.js
@@ -524,6 +524,21 @@ const handlers = {
       const stateDoc = { stopped: true, reason, round, coverage_pct: cov.pct, queries_used: used, at: new Date().toISOString() };
       await settings.set('convergence_state', stateDoc, 'system:convergence-controller');
       await audit.log({ actor: 'system:convergence-controller', action: 'convergence.stop', detail: stateDoc });
+      // ANOMALOUS halts (a wedged job / parallel chains) would otherwise stop the whole research
+      // pipeline silently — nobody reads convergence_state in real time. Surface them as an admin
+      // task so a human notices and can unstick it. Normal terminal reasons (target_reached,
+      // sweep_dry, round_cap, budget_exhausted) don't create a task — they're not anomalies.
+      if (reason === 'pending_stuck' || reason === 'duplicate_controller') {
+        try {
+          await require('../services/tasks').create({
+            title: `Coverage research halted: ${reason} (round ${round}, ${cov.pct}% coverage)`,
+            detail: reason === 'pending_stuck'
+              ? 'A research job appears wedged in queued/running — check pr_jobs for a stuck job, then re-arm convergence from /admin/pr-intelligence/settings.'
+              : 'More than one convergence-controller was in flight; the extra was halted. Verify only one is running, then re-arm if needed.',
+            actor: 'system:convergence-controller',
+          });
+        } catch { /* task creation is best-effort — must never block the stop */ }
+      }
       return stateDoc;
     };
     // Singleton guard: the self-re-enqueue chain changes `tick` each hop, so it does NOT dedupe on

← d6396bdc auto-save: 2026-08-05T23:46:47 (7 files) — data/deals-regist  ·  back to Rentv  ·  pr/jobs: Cody gate — dedup the convergence-halt admin task. eed7cbc8 →