@overdeck/core 0.49.0 → 0.49.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/{build-info-Ck2TzOSQ.js → build-info-Bts-0E0B.js} +3 -3
  2. package/dist/{build-info-Ck2TzOSQ.js.map → build-info-Bts-0E0B.js.map} +1 -1
  3. package/dist/build-info-CD0O1MvT.js +2 -0
  4. package/dist/cli/index.js +4 -4
  5. package/dist/dashboard/{build-info-DXfOjbg3.js → build-info-DTX8JwVP.js} +3 -3
  6. package/dist/dashboard/{build-info-DXfOjbg3.js.map → build-info-DTX8JwVP.js.map} +1 -1
  7. package/dist/dashboard/build-info-PQlh_Rhb.js +2 -0
  8. package/dist/dashboard/{deacon-CeqVPw0o.js → deacon-BEH-IY0v.js} +2 -2
  9. package/dist/dashboard/{deacon-CQxv6Qwv.js → deacon-TPYssFYt.js} +8 -8
  10. package/dist/dashboard/{deacon-CQxv6Qwv.js.map → deacon-TPYssFYt.js.map} +1 -1
  11. package/dist/dashboard/{deacon-merge-ugZ7jekt.js → deacon-merge-BOGFEV8_.js} +5 -5
  12. package/dist/dashboard/{deacon-merge-ugZ7jekt.js.map → deacon-merge-BOGFEV8_.js.map} +1 -1
  13. package/dist/dashboard/{deacon-pending-lifecycle-Cxu6Rezs.js → deacon-pending-lifecycle-DVHjOLje.js} +2 -2
  14. package/dist/dashboard/{deacon-pending-lifecycle-Cxu6Rezs.js.map → deacon-pending-lifecycle-DVHjOLje.js.map} +1 -1
  15. package/dist/dashboard/deacon.js +2 -2
  16. package/dist/dashboard/{deploy-patrol-DxnpZcnl.js → deploy-patrol-BXjlvoV3.js} +2 -2
  17. package/dist/dashboard/{deploy-patrol-DxnpZcnl.js.map → deploy-patrol-BXjlvoV3.js.map} +1 -1
  18. package/dist/dashboard/{identity-BnxKo9-z.js → identity-Bwh6VGeL.js} +2 -2
  19. package/dist/dashboard/{identity-BnxKo9-z.js.map → identity-Bwh6VGeL.js.map} +1 -1
  20. package/dist/dashboard/{lifecycle-ozA4GZNs.js → lifecycle-B0rL38D3.js} +2 -2
  21. package/dist/dashboard/{lifecycle-ozA4GZNs.js.map → lifecycle-B0rL38D3.js.map} +1 -1
  22. package/dist/dashboard/{memory-governor-W8994ASc.js → memory-governor-A4O6vI9d.js} +3 -3
  23. package/dist/dashboard/{memory-governor-W8994ASc.js.map → memory-governor-A4O6vI9d.js.map} +1 -1
  24. package/dist/dashboard/{memory-pressure-patrol-D_T_QLFC.js → memory-pressure-patrol-BWlWywmA.js} +2 -2
  25. package/dist/dashboard/{memory-pressure-patrol-D_T_QLFC.js.map → memory-pressure-patrol-BWlWywmA.js.map} +1 -1
  26. package/dist/dashboard/{merge-agent-B8YsWRDu.js → merge-agent-BRSz26Oh.js} +1 -1
  27. package/dist/dashboard/{merge-agent-DxecsTre.js → merge-agent-GWhmnxFk.js} +2 -2
  28. package/dist/dashboard/{merge-agent-DxecsTre.js.map → merge-agent-GWhmnxFk.js.map} +1 -1
  29. package/dist/dashboard/merge-ops-DtHx17Vd.js +2 -0
  30. package/dist/dashboard/{post-merge-lifecycle-worker-DC-i1kqz.js → post-merge-lifecycle-worker-KK1RTKRE.js} +2 -2
  31. package/dist/dashboard/{post-merge-lifecycle-worker-DC-i1kqz.js.map → post-merge-lifecycle-worker-KK1RTKRE.js.map} +1 -1
  32. package/dist/dashboard/{resolver-BdHzKhNL.js → resolver-C8rooxoz.js} +2 -2
  33. package/dist/dashboard/{resolver-BdHzKhNL.js.map → resolver-C8rooxoz.js.map} +1 -1
  34. package/dist/dashboard/server.js +28 -28
  35. package/dist/dashboard/{service-0hbSVeHz.js → service-BLb_CyPL.js} +6 -6
  36. package/dist/dashboard/{service-0hbSVeHz.js.map → service-BLb_CyPL.js.map} +1 -1
  37. package/dist/dashboard/{specialists-C2ZVszIW.js → specialists-DocAK-7A.js} +5 -5
  38. package/dist/dashboard/{specialists-C2ZVszIW.js.map → specialists-DocAK-7A.js.map} +1 -1
  39. package/dist/dashboard/{specialists-DhLEuxVX.js → specialists-xXcJHAyg.js} +1 -1
  40. package/dist/dashboard/{stall-sweeper-o4-q0vqY.js → stall-sweeper-DOyIfeLR.js} +2 -2
  41. package/dist/dashboard/{stall-sweeper-o4-q0vqY.js.map → stall-sweeper-DOyIfeLR.js.map} +1 -1
  42. package/dist/dashboard/{uat-train-fK0FbCx7.js → uat-train-COSy-vEX.js} +1 -1
  43. package/dist/dashboard/{uat-train-CSOval9z.js → uat-train-DVUNW03P.js} +0 -0
  44. package/dist/dashboard/{uat-train-CSOval9z.js.map → uat-train-DVUNW03P.js.map} +1 -1
  45. package/dist/dashboard/{workflows-BnNc1QlT.js → workflows-BYwR2aIN.js} +2 -2
  46. package/dist/dashboard/{workflows-BnNc1QlT.js.map → workflows-BYwR2aIN.js.map} +1 -1
  47. package/dist/dashboard/workflows-Cf4LAnhg.js +2 -0
  48. package/dist/dashboard/{workspaces-CqeaoIK6.js → workspaces-BlpbOPZ7.js} +11 -11
  49. package/dist/dashboard/{workspaces-CqeaoIK6.js.map → workspaces-BlpbOPZ7.js.map} +1 -1
  50. package/dist/{lifecycle-Bhu9mEsV.js → lifecycle-BhAciIXh.js} +1 -1
  51. package/dist/{lifecycle-CMRdm3mR.js → lifecycle-D8m3w850.js} +2 -2
  52. package/dist/{lifecycle-CMRdm3mR.js.map → lifecycle-D8m3w850.js.map} +1 -1
  53. package/dist/{merge-agent-DQ7DOXE2.js → merge-agent-CUnIrr8R.js} +2 -2
  54. package/dist/{merge-agent-DQ7DOXE2.js.map → merge-agent-CUnIrr8R.js.map} +1 -1
  55. package/dist/{merge-agent-D33x_y_T.js → merge-agent-DwfVId_E.js} +1 -1
  56. package/package.json +1 -1
  57. package/dist/build-info-B9bbKbXz.js +0 -2
  58. package/dist/dashboard/build-info-CrBYH-L2.js +0 -2
  59. package/dist/dashboard/merge-ops-C9wpFz1G.js +0 -2
  60. package/dist/dashboard/workflows-C6MkcBR_.js +0 -2
@@ -1,2 +1,2 @@
1
- import { i as validateSpecialistAutoCompleteMetadata, n as _serverManagedMerges, r as firePostMergeLifecycle, t as specialistsRouteLayer } from "./specialists-C2ZVszIW.js";
1
+ import { i as validateSpecialistAutoCompleteMetadata, n as _serverManagedMerges, r as firePostMergeLifecycle, t as specialistsRouteLayer } from "./specialists-DocAK-7A.js";
2
2
  export { _serverManagedMerges, specialistsRouteLayer as default, specialistsRouteLayer, firePostMergeLifecycle, validateSpecialistAutoCompleteMetadata };
@@ -4,7 +4,7 @@ import { S as init_tmux, V as sessionExistsSync } from "./tmux-BqXzRuaH.js";
4
4
  import { h as init_agent_state, m as getAgentStateSync } from "./agent-state-Bb3UUxQm.js";
5
5
  import { c as readMemoizedArtifactVerdict, o as init_synthesis_verdict } from "./synthesis-verdict-N5Z11pg7.js";
6
6
  import { t as getCloisterEventStore } from "./event-store-provider-BKvk2rDj.js";
7
- import { n as resolveParkedPopulation, t as PARKED_ORBIT_SEVERITY } from "./resolver-BdHzKhNL.js";
7
+ import { n as resolveParkedPopulation, t as PARKED_ORBIT_SEVERITY } from "./resolver-C8rooxoz.js";
8
8
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
9
9
  import { join } from "path";
10
10
  //#region ../../lib/cloister/stall-sweeper-state.ts
@@ -302,4 +302,4 @@ function reportRow(row, state, now, reporting, outcome) {
302
302
  //#endregion
303
303
  export { runStallSweeperPatrol };
304
304
 
305
- //# sourceMappingURL=stall-sweeper-o4-q0vqY.js.map
305
+ //# sourceMappingURL=stall-sweeper-DOyIfeLR.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stall-sweeper-o4-q0vqY.js","names":[],"sources":["../../src/lib/cloister/stall-sweeper-state.ts","../../src/lib/cloister/stall-sweeper.ts"],"sourcesContent":["/**\n * Stall-sweeper per-row reporting state (PAN-3485 phase 2).\n *\n * One small JSON file per (issueId, orbit) under ~/.overdeck/stall-sweeper/.\n * Tracks a parked episode's recommendation cooldown, recommendation count, and\n * operator re-surface TTL. Runtime-plane residue — deleting the directory only\n * resets reporting cadence and never loses pipeline state.\n */\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { getOverdeckHome } from '../paths.js';\n\nexport interface StallSweeperRowState {\n /** Total recommendations emitted for the current park episode. */\n recommendationCount: number;\n /** ISO timestamp of the last recommendation (drives cooldowns). */\n lastRecommendedAt?: string;\n /** ISO timestamp when the sweeper first saw this park episode. */\n episodeStartedAt: string;\n /** ISO timestamp of the last operator re-surface (drives the escalation TTL). */\n lastEscalatedAt?: string;\n}\n\nfunction sweeperDir(): string {\n return join(getOverdeckHome(), 'stall-sweeper');\n}\n\nfunction statePath(issueId: string, orbit: string): string {\n return join(sweeperDir(), `${issueId.toUpperCase()}--${orbit}.json`);\n}\n\nexport function readSweeperRowState(issueId: string, orbit: string): StallSweeperRowState | null {\n const filePath = statePath(issueId, orbit);\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8')) as StallSweeperRowState;\n } catch {\n return null;\n }\n}\n\nexport function writeSweeperRowState(issueId: string, orbit: string, state: StallSweeperRowState): void {\n mkdirSync(sweeperDir(), { recursive: true });\n writeFileSync(statePath(issueId, orbit), JSON.stringify(state, null, 2));\n}\n\n/** Episode over (row resolved or orbit changed) — forget so a future park starts fresh. */\nexport function clearSweeperRowState(issueId: string, orbit: string): void {\n rmSync(statePath(issueId, orbit), { force: true });\n}\n\n/** Population-signature persistence for change-only sweep.scan emission. */\nexport function readSweeperSignature(): string | null {\n const filePath = join(sweeperDir(), 'population-signature');\n if (!existsSync(filePath)) return null;\n try { return readFileSync(filePath, 'utf-8'); } catch { return null; }\n}\n\nexport function writeSweeperSignature(signature: string): void {\n mkdirSync(sweeperDir(), { recursive: true });\n writeFileSync(join(sweeperDir(), 'population-signature'), signature);\n}\n","/**\n * The Stall Sweeper (PAN-3485 phase 2) — the pipeline's stall DETECTOR.\n *\n * ─── OBSERVABILITY ONLY — OPERATOR DIRECTIVE (2026-08-05) ───────────────────\n * This module detects parked/stalled work and reports it with a recommended\n * action. It must NEVER act. Do not re-add spawn/stop/kill/message/dispatch/\n * clear/reset capability here — not behind a flag, not as \"just this one safe\n * case\", not as an opt-in. The kill-and-re-drive incarnation killed a\n * completed PAN-3511 review parent on a lost verdict and re-dispatched on\n * phantom stuck flags (2026-08-05): every failure was the sweeper ACTING on\n * state that had drifted. Detection is trustworthy because it reads; action\n * was not, because it wrote. The operator (or a deliberately invoked door)\n * executes recommendations.\n * ───────────────────────────────────────────────────────────────────────────\n *\n * Every failure path in the pipeline parks the issue somewhere autonomous\n * motion stops (the orbits in src/lib/parked/resolver.ts). This patrol walks\n * the parked population every deacon cycle and emits, per row: an\n * activity-feed sentence and a sweep.recommendation domain event naming the\n * evidence and the recommended remedy. Operator-set gates are never touched;\n * gated and truly exhausted rows are re-surfaced to the operator on a TTL\n * instead of going silent. Every recommendation and escalation emits a\n * sweep.* domain event and an activity-feed sentence, so a sweep is always\n * visible (PAN-3489 wires those events into the God View).\n *\n * Guardrails:\n * - one recommendation per row per cooldown window; SWEEP_MAX_RECOMMENDATIONS_PER_ROW\n * per park episode, then escalate-only;\n * - a global recommendation budget per scan so a graveyard census can't\n * flood the feed at once;\n * - this module holds no door to any mutation — there is nothing to force.\n */\nimport { emitActivityEntrySync, type ActivityLevel } from '../activity-logger.js';\nimport { getAgentStateSync } from '../agents/agent-state.js';\nimport {\n PARKED_ORBIT_SEVERITY,\n resolveParkedPopulation,\n type ParkedOrbit,\n type ParkedRow,\n} from '../parked/resolver.js';\nimport { sessionExistsSync } from '../tmux.js';\nimport { getCloisterEventStore } from './event-store-provider.js';\nimport { readMemoizedArtifactVerdict, type SynthesisArtifactVerdict } from './synthesis-verdict.js';\nimport {\n clearSweeperRowState,\n readSweeperRowState,\n readSweeperSignature,\n writeSweeperRowState,\n writeSweeperSignature,\n type StallSweeperRowState,\n} from './stall-sweeper-state.js';\n\n// ─── Policy constants ─────────────────────────────────────────────────────────\n\n/** Max recommendations per park episode; beyond this the row is escalate-only. */\nexport const SWEEP_MAX_RECOMMENDATIONS_PER_ROW = 8;\n/** Max recommendations per patrol scan — a full graveyard surfaces over cycles, never in one burst. */\nexport const SWEEP_MAX_RECOMMENDATIONS_PER_SCAN = 4;\n/** Operator-gated / exhausted rows re-surface to the operator this often (and stay hands-off otherwise). */\nexport const SWEEP_RESURFACE_TTL_MS = 24 * 60 * 60_000;\n\nconst ORBIT_COOLDOWN_MS: Record<string, number> = {\n 'zombie-session': 15 * 60_000,\n 'merge-failed': 2 * 60 * 60_000,\n 'uat-failed': 2 * 60 * 60_000,\n conflicts: 2 * 60 * 60_000,\n 'stuck-flag': 2 * 60 * 60_000,\n 'idle-running': 30 * 60_000,\n};\n/** An idle-running recommendation repeats at most this often while nothing moves. */\nconst IDLE_RECOMMEND_GRACE_MS = 90 * 60_000;\n\n/** Every feed entry carries this so a recommendation can never be mistaken for an action. */\nconst NO_ACTION_TRAILER = 'Observability-only: no action taken.';\n\n// ─── Deps (injectable for tests) ──────────────────────────────────────────────\n\nexport interface StallSweeperDeps {\n now?: number;\n resolveRows?: () => Promise<ParkedRow[]>;\n readArtifact?: (issueId: string) => SynthesisArtifactVerdict | null;\n isAgentLive?: (agentId: string) => boolean;\n emitActivity?: (entry: { level: ActivityLevel; issueId?: string; message: string }) => void;\n emitEvent?: (type: string, payload: Record<string, unknown>) => void;\n}\n\ninterface ScanOutcome {\n recommendations: string[];\n escalations: string[];\n}\n\n// ─── Event + activity emission ────────────────────────────────────────────────\n\nfunction defaultEmitEvent(type: string, payload: Record<string, unknown>): void {\n try {\n getCloisterEventStore()?.append({\n type,\n timestamp: new Date().toISOString(),\n payload,\n } as Parameters<NonNullable<ReturnType<typeof getCloisterEventStore>>['append']>[0]);\n } catch (error) {\n console.warn(`[sweeper] failed to append ${type}:`, error instanceof Error ? error.message : String(error));\n }\n}\n\nfunction defaultEmitActivity(entry: { level: ActivityLevel; issueId?: string; message: string }): void {\n // Source is cloister — the sweeper is cloister machinery; the 🧹 message\n // prefix carries the sweeper identity in the feed.\n emitActivityEntrySync({\n source: 'cloister',\n level: entry.level,\n ...(entry.issueId ? { issueId: entry.issueId } : {}),\n message: entry.message,\n });\n}\n\n// ─── Per-row helpers ──────────────────────────────────────────────────────────\n\nfunction coolingDown(state: StallSweeperRowState | null, orbit: ParkedOrbit, now: number): boolean {\n if (!state?.lastRecommendedAt) return false;\n const cooldown = ORBIT_COOLDOWN_MS[orbit] ?? 60 * 60_000;\n return now - Date.parse(state.lastRecommendedAt) < cooldown;\n}\n\nfunction dueForResurface(state: StallSweeperRowState | null, now: number): boolean {\n if (!state?.lastEscalatedAt) return true;\n return now - Date.parse(state.lastEscalatedAt) >= SWEEP_RESURFACE_TTL_MS;\n}\n\nfunction recordRecommendation(issueId: string, orbit: ParkedOrbit, state: StallSweeperRowState | null, now: number): void {\n writeSweeperRowState(issueId, orbit, {\n recommendationCount: (state?.recommendationCount ?? 0) + 1,\n lastRecommendedAt: new Date(now).toISOString(),\n episodeStartedAt: state?.episodeStartedAt ?? new Date(now).toISOString(),\n ...(state?.lastEscalatedAt ? { lastEscalatedAt: state.lastEscalatedAt } : {}),\n });\n}\n\nfunction recordEscalation(issueId: string, orbit: ParkedOrbit, state: StallSweeperRowState | null, now: number): void {\n writeSweeperRowState(issueId, orbit, {\n recommendationCount: state?.recommendationCount ?? 0,\n ...(state?.lastRecommendedAt ? { lastRecommendedAt: state.lastRecommendedAt } : {}),\n episodeStartedAt: state?.episodeStartedAt ?? new Date(now).toISOString(),\n lastEscalatedAt: new Date(now).toISOString(),\n });\n}\n\n// ─── The patrol ───────────────────────────────────────────────────────────────\n\nexport async function runStallSweeperPatrol(deps: StallSweeperDeps = {}): Promise<string[]> {\n const now = deps.now ?? Date.now();\n const resolveRows = deps.resolveRows ?? resolveParkedPopulation;\n const readArtifact = deps.readArtifact ?? ((issueId: string) => {\n const review = getAgentStateSync(`agent-${issueId.toLowerCase()}-review`);\n return readMemoizedArtifactVerdict(issueId, {\n runId: review?.reviewRunId,\n workspacePath: review?.workspace,\n });\n });\n const isAgentLive = deps.isAgentLive ?? sessionExistsSync;\n const emitActivity = deps.emitActivity ?? defaultEmitActivity;\n const emitEvent = deps.emitEvent ?? defaultEmitEvent;\n\n const rows = await resolveRows();\n const outcome: ScanOutcome = { recommendations: [], escalations: [] };\n\n // Population signature → sweep.scan fires only on CHANGE (a scan that finds\n // the same population is not news; a scan that finds a different one is).\n const signature = rows.map((row) => `${row.issueId}:${row.orbit}`).sort().join('|');\n if (signature !== readSweeperSignature()) {\n emitEvent('sweep.scan', {\n issueCount: new Set(rows.map((row) => row.issueId)).size,\n rowCount: rows.length,\n rows: rows.map((row) => ({ issueId: row.issueId, orbit: row.orbit, parkedAt: row.parkedAt })),\n });\n writeSweeperSignature(signature);\n }\n\n // Resolved rows get their episode state forgotten so a future park starts fresh.\n // (Rows absent from this scan are resolved by definition of the resolver.)\n\n const severity = (row: ParkedRow) => PARKED_ORBIT_SEVERITY.indexOf(row.orbit);\n const work = [...rows].sort((a, b) => severity(a) - severity(b) || a.parkedAt.localeCompare(b.parkedAt));\n let recommendationBudget = SWEEP_MAX_RECOMMENDATIONS_PER_SCAN;\n\n for (const row of work) {\n const { issueId, orbit } = row;\n const state = readSweeperRowState(issueId, orbit);\n\n // Operator-owned rows: never act, re-surface on TTL.\n if (orbit === 'operator-gate' || orbit === 'deacon-ignored' || orbit === 'needs-you' || orbit === 'circuit-breaker') {\n if (dueForResurface(state, now)) {\n recordEscalation(issueId, orbit, state, now);\n emitEvent('sweep.escalated', { issueId, orbit, reason: row.parkReason });\n emitActivity({ level: 'warn', issueId, message: `🧹 sweeper re-surface: ${issueId} is still parked (${orbit}) — ${row.parkReason}. Release: ${row.unparkCondition}` });\n outcome.escalations.push(`${issueId} (${orbit}) re-surfaced to operator`);\n }\n continue;\n }\n\n if (coolingDown(state, orbit, now)) continue;\n if ((state?.recommendationCount ?? 0) >= SWEEP_MAX_RECOMMENDATIONS_PER_ROW) {\n if (dueForResurface(state, now)) {\n recordEscalation(issueId, orbit, state, now);\n emitEvent('sweep.escalated', { issueId, orbit, reason: `exhausted ${SWEEP_MAX_RECOMMENDATIONS_PER_ROW} sweep recommendations` });\n emitActivity({ level: 'warn', issueId, message: `🧹 sweeper: ${issueId} (${orbit}) exhausted ${SWEEP_MAX_RECOMMENDATIONS_PER_ROW} recommendations — needs a human. ${row.parkReason}` });\n outcome.escalations.push(`${issueId} (${orbit}) exhausted → operator`);\n }\n continue;\n }\n if (recommendationBudget <= 0) continue;\n\n const reported = reportRow(row, state, now, { readArtifact, isAgentLive, emitActivity, emitEvent }, outcome);\n if (reported) {\n recordRecommendation(issueId, orbit, state, now);\n recommendationBudget--;\n }\n }\n\n return [...outcome.recommendations, ...outcome.escalations];\n}\n\n// ─── Per-orbit recommendations ────────────────────────────────────────────────\n\ninterface ReportDeps {\n readArtifact: (issueId: string) => SynthesisArtifactVerdict | null;\n isAgentLive: (agentId: string) => boolean;\n emitActivity: (entry: { level: ActivityLevel; issueId?: string; message: string }) => void;\n emitEvent: (type: string, payload: Record<string, unknown>) => void;\n}\n\n/**\n * Build the per-orbit recommendation. This is the ONLY thing the sweeper does\n * with a row: describe the evidence, name the remedy, emit both. There is no\n * action door — see the file-header law.\n *\n * Recommendations always name the CANONICAL existing door (the same machinery\n * the deacon/operator uses — pan resume/start/tell/unstick/review restart/\n * sync-main/done/close), never a sweeper-invented path. A stall that keeps\n * recurring across an episode is a substrate bug by definition: the\n * recommendation says so, so the flywheel's substrate intake files why it\n * keeps parking instead of the symptom being swept forever.\n */\nfunction reportRow(\n row: ParkedRow,\n state: StallSweeperRowState | null,\n now: number,\n reporting: ReportDeps,\n outcome: ScanOutcome,\n): boolean {\n const { issueId, orbit } = row;\n const recurrence = state?.recommendationCount ?? 0;\n const substrateNote = recurrence >= 1\n ? ` This stall has recurred (${recurrence + 1} sweeps this episode) — that is a substrate bug: file why ${issueId} keeps parking here (flywheel substrate intake), don't just remedy the symptom.`\n : '';\n const recommend = (recommendation: string, evidence: Record<string, unknown> = {}) => {\n reporting.emitEvent('sweep.recommendation', { issueId, orbit, recommendation, recurring: recurrence >= 1, ...evidence });\n reporting.emitActivity({ level: 'warn', issueId, message: `🧹 sweeper recommends: ${recommendation} — ${row.parkReason}.${substrateNote} ${NO_ACTION_TRAILER}` });\n outcome.recommendations.push(`${issueId} (${orbit}) recommended: ${recommendation}`);\n };\n\n switch (orbit) {\n case 'zombie-session': {\n const agentId = String(row.details?.agentId ?? `agent-${issueId.toLowerCase()}`);\n const live = reporting.isAgentLive(agentId);\n recommend(`reap zombie session ${agentId} via the existing door (pan close ${issueId} owns merged/closed teardown; the reaper is the backstop)`, { agentId, sessionCurrentlyLive: live });\n return true;\n }\n\n case 'merge-failed': {\n recommend(`reset ${issueId}'s merge for re-evaluation via pan review resync ${issueId}`);\n return true;\n }\n\n case 'uat-failed': {\n // Reaching this orbit means the relay's feedback-target resurrection ladder failed.\n const notes = typeof row.details?.uatNotes === 'string' ? row.details.uatNotes : 'UAT failed — see the UAT panel for details';\n recommend(`start a work agent for ${issueId} via pan start ${issueId} — the UAT-failure relay found no live target for its feedback`, { uatNotes: notes.slice(0, 400) });\n return true;\n }\n\n case 'stuck-flag': {\n const reason = typeof row.details?.stuckReason === 'string' ? row.details.stuckReason : '';\n\n // PAN-3511: evidence from the active review run prevents a recommendation\n // from re-driving work over a review that has already finished. The\n // sweeper remains observability-only and cannot promote that evidence into\n // a terminal review status.\n const artifact = reporting.readArtifact(issueId);\n if (artifact?.verdict === 'passed') {\n recommend(\n `preserve ${issueId}'s passed review evidence from run ${artifact.runId} and await pan admin specialists done review; do not re-dispatch or resume rework`,\n { artifactVerdict: artifact.verdict, artifactRunId: artifact.runId, artifactHead: artifact.headSha },\n );\n return true;\n }\n if (reason === 'review_infrastructure_failure') {\n recommend(`clear ${issueId}'s infra-failure stuck flag and re-dispatch the review via pan unstick ${issueId} && pan review restart ${issueId}`);\n return true;\n }\n if (reason === 'feedback_delivery_needs_you' || reason === 'verification_stuck') {\n recommend(\n artifact?.notes\n ? `resume ${issueId} rework via pan resume agent-${issueId.toLowerCase()} using the blocker from review run ${artifact.runId}`\n : `resume ${issueId} rework from the pending feedback via pan resume agent-${issueId.toLowerCase()} (feedback is in .pan/feedback)`,\n artifact?.notes ? { artifactVerdict: artifact.verdict, artifactRunId: artifact.runId, reviewNotes: artifact.notes.slice(0, 400) } : {},\n );\n return true;\n }\n // Unknown / dead-end stuck flavors are operator-owned — re-surface on TTL.\n if (dueForResurface(state, now)) {\n recordEscalation(issueId, orbit, state, now);\n reporting.emitEvent('sweep.escalated', { issueId, orbit, reason: row.parkReason });\n reporting.emitActivity({ level: 'warn', issueId, message: `🧹 sweeper re-surface: ${issueId} remains stuck (${reason || 'unknown'}) — ${row.parkReason}` });\n outcome.escalations.push(`${issueId} (stuck:${reason || 'unknown'}) re-surfaced`);\n }\n return false;\n }\n\n case 'idle-running': {\n const agentId = String(row.details?.agentId ?? `agent-${issueId.toLowerCase()}`);\n const lastActivity = typeof row.details?.idleMinutes === 'number' ? row.details.idleMinutes : 0;\n if (state?.lastRecommendedAt && now - Date.parse(state.lastRecommendedAt) < IDLE_RECOMMEND_GRACE_MS) return false;\n const previouslyRecommended = !!state?.lastRecommendedAt;\n recommend(\n previouslyRecommended\n ? `stop or resume ${agentId} via pan kill ${agentId} / pan resume ${agentId} — still idle ${Math.round(lastActivity / 60)}h after a prior recommendation`\n : `nudge ${agentId} via pan tell ${agentId} — idle ${Math.round(lastActivity / 60)}h with no pipeline stage owning its next move`,\n { agentId, idleMinutes: lastActivity, live: reporting.isAgentLive(agentId) },\n );\n return true;\n }\n\n default:\n return false;\n }\n}\n\n/** Forget episode state for rows that left the population (called by tests + future reconcilers). */\nexport function forgetResolvedSweeperRows(currentRows: readonly ParkedRow[]): void {\n const live = new Set(currentRows.map((row) => `${row.issueId}:${row.orbit}`));\n for (const row of currentRows) {\n if (!live.has(`${row.issueId}:${row.orbit}`)) clearSweeperRowState(row.issueId, row.orbit);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stall-sweeper-DOyIfeLR.js","names":[],"sources":["../../src/lib/cloister/stall-sweeper-state.ts","../../src/lib/cloister/stall-sweeper.ts"],"sourcesContent":["/**\n * Stall-sweeper per-row reporting state (PAN-3485 phase 2).\n *\n * One small JSON file per (issueId, orbit) under ~/.overdeck/stall-sweeper/.\n * Tracks a parked episode's recommendation cooldown, recommendation count, and\n * operator re-surface TTL. Runtime-plane residue — deleting the directory only\n * resets reporting cadence and never loses pipeline state.\n */\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { getOverdeckHome } from '../paths.js';\n\nexport interface StallSweeperRowState {\n /** Total recommendations emitted for the current park episode. */\n recommendationCount: number;\n /** ISO timestamp of the last recommendation (drives cooldowns). */\n lastRecommendedAt?: string;\n /** ISO timestamp when the sweeper first saw this park episode. */\n episodeStartedAt: string;\n /** ISO timestamp of the last operator re-surface (drives the escalation TTL). */\n lastEscalatedAt?: string;\n}\n\nfunction sweeperDir(): string {\n return join(getOverdeckHome(), 'stall-sweeper');\n}\n\nfunction statePath(issueId: string, orbit: string): string {\n return join(sweeperDir(), `${issueId.toUpperCase()}--${orbit}.json`);\n}\n\nexport function readSweeperRowState(issueId: string, orbit: string): StallSweeperRowState | null {\n const filePath = statePath(issueId, orbit);\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, 'utf-8')) as StallSweeperRowState;\n } catch {\n return null;\n }\n}\n\nexport function writeSweeperRowState(issueId: string, orbit: string, state: StallSweeperRowState): void {\n mkdirSync(sweeperDir(), { recursive: true });\n writeFileSync(statePath(issueId, orbit), JSON.stringify(state, null, 2));\n}\n\n/** Episode over (row resolved or orbit changed) — forget so a future park starts fresh. */\nexport function clearSweeperRowState(issueId: string, orbit: string): void {\n rmSync(statePath(issueId, orbit), { force: true });\n}\n\n/** Population-signature persistence for change-only sweep.scan emission. */\nexport function readSweeperSignature(): string | null {\n const filePath = join(sweeperDir(), 'population-signature');\n if (!existsSync(filePath)) return null;\n try { return readFileSync(filePath, 'utf-8'); } catch { return null; }\n}\n\nexport function writeSweeperSignature(signature: string): void {\n mkdirSync(sweeperDir(), { recursive: true });\n writeFileSync(join(sweeperDir(), 'population-signature'), signature);\n}\n","/**\n * The Stall Sweeper (PAN-3485 phase 2) — the pipeline's stall DETECTOR.\n *\n * ─── OBSERVABILITY ONLY — OPERATOR DIRECTIVE (2026-08-05) ───────────────────\n * This module detects parked/stalled work and reports it with a recommended\n * action. It must NEVER act. Do not re-add spawn/stop/kill/message/dispatch/\n * clear/reset capability here — not behind a flag, not as \"just this one safe\n * case\", not as an opt-in. The kill-and-re-drive incarnation killed a\n * completed PAN-3511 review parent on a lost verdict and re-dispatched on\n * phantom stuck flags (2026-08-05): every failure was the sweeper ACTING on\n * state that had drifted. Detection is trustworthy because it reads; action\n * was not, because it wrote. The operator (or a deliberately invoked door)\n * executes recommendations.\n * ───────────────────────────────────────────────────────────────────────────\n *\n * Every failure path in the pipeline parks the issue somewhere autonomous\n * motion stops (the orbits in src/lib/parked/resolver.ts). This patrol walks\n * the parked population every deacon cycle and emits, per row: an\n * activity-feed sentence and a sweep.recommendation domain event naming the\n * evidence and the recommended remedy. Operator-set gates are never touched;\n * gated and truly exhausted rows are re-surfaced to the operator on a TTL\n * instead of going silent. Every recommendation and escalation emits a\n * sweep.* domain event and an activity-feed sentence, so a sweep is always\n * visible (PAN-3489 wires those events into the God View).\n *\n * Guardrails:\n * - one recommendation per row per cooldown window; SWEEP_MAX_RECOMMENDATIONS_PER_ROW\n * per park episode, then escalate-only;\n * - a global recommendation budget per scan so a graveyard census can't\n * flood the feed at once;\n * - this module holds no door to any mutation — there is nothing to force.\n */\nimport { emitActivityEntrySync, type ActivityLevel } from '../activity-logger.js';\nimport { getAgentStateSync } from '../agents/agent-state.js';\nimport {\n PARKED_ORBIT_SEVERITY,\n resolveParkedPopulation,\n type ParkedOrbit,\n type ParkedRow,\n} from '../parked/resolver.js';\nimport { sessionExistsSync } from '../tmux.js';\nimport { getCloisterEventStore } from './event-store-provider.js';\nimport { readMemoizedArtifactVerdict, type SynthesisArtifactVerdict } from './synthesis-verdict.js';\nimport {\n clearSweeperRowState,\n readSweeperRowState,\n readSweeperSignature,\n writeSweeperRowState,\n writeSweeperSignature,\n type StallSweeperRowState,\n} from './stall-sweeper-state.js';\n\n// ─── Policy constants ─────────────────────────────────────────────────────────\n\n/** Max recommendations per park episode; beyond this the row is escalate-only. */\nexport const SWEEP_MAX_RECOMMENDATIONS_PER_ROW = 8;\n/** Max recommendations per patrol scan — a full graveyard surfaces over cycles, never in one burst. */\nexport const SWEEP_MAX_RECOMMENDATIONS_PER_SCAN = 4;\n/** Operator-gated / exhausted rows re-surface to the operator this often (and stay hands-off otherwise). */\nexport const SWEEP_RESURFACE_TTL_MS = 24 * 60 * 60_000;\n\nconst ORBIT_COOLDOWN_MS: Record<string, number> = {\n 'zombie-session': 15 * 60_000,\n 'merge-failed': 2 * 60 * 60_000,\n 'uat-failed': 2 * 60 * 60_000,\n conflicts: 2 * 60 * 60_000,\n 'stuck-flag': 2 * 60 * 60_000,\n 'idle-running': 30 * 60_000,\n};\n/** An idle-running recommendation repeats at most this often while nothing moves. */\nconst IDLE_RECOMMEND_GRACE_MS = 90 * 60_000;\n\n/** Every feed entry carries this so a recommendation can never be mistaken for an action. */\nconst NO_ACTION_TRAILER = 'Observability-only: no action taken.';\n\n// ─── Deps (injectable for tests) ──────────────────────────────────────────────\n\nexport interface StallSweeperDeps {\n now?: number;\n resolveRows?: () => Promise<ParkedRow[]>;\n readArtifact?: (issueId: string) => SynthesisArtifactVerdict | null;\n isAgentLive?: (agentId: string) => boolean;\n emitActivity?: (entry: { level: ActivityLevel; issueId?: string; message: string }) => void;\n emitEvent?: (type: string, payload: Record<string, unknown>) => void;\n}\n\ninterface ScanOutcome {\n recommendations: string[];\n escalations: string[];\n}\n\n// ─── Event + activity emission ────────────────────────────────────────────────\n\nfunction defaultEmitEvent(type: string, payload: Record<string, unknown>): void {\n try {\n getCloisterEventStore()?.append({\n type,\n timestamp: new Date().toISOString(),\n payload,\n } as Parameters<NonNullable<ReturnType<typeof getCloisterEventStore>>['append']>[0]);\n } catch (error) {\n console.warn(`[sweeper] failed to append ${type}:`, error instanceof Error ? error.message : String(error));\n }\n}\n\nfunction defaultEmitActivity(entry: { level: ActivityLevel; issueId?: string; message: string }): void {\n // Source is cloister — the sweeper is cloister machinery; the 🧹 message\n // prefix carries the sweeper identity in the feed.\n emitActivityEntrySync({\n source: 'cloister',\n level: entry.level,\n ...(entry.issueId ? { issueId: entry.issueId } : {}),\n message: entry.message,\n });\n}\n\n// ─── Per-row helpers ──────────────────────────────────────────────────────────\n\nfunction coolingDown(state: StallSweeperRowState | null, orbit: ParkedOrbit, now: number): boolean {\n if (!state?.lastRecommendedAt) return false;\n const cooldown = ORBIT_COOLDOWN_MS[orbit] ?? 60 * 60_000;\n return now - Date.parse(state.lastRecommendedAt) < cooldown;\n}\n\nfunction dueForResurface(state: StallSweeperRowState | null, now: number): boolean {\n if (!state?.lastEscalatedAt) return true;\n return now - Date.parse(state.lastEscalatedAt) >= SWEEP_RESURFACE_TTL_MS;\n}\n\nfunction recordRecommendation(issueId: string, orbit: ParkedOrbit, state: StallSweeperRowState | null, now: number): void {\n writeSweeperRowState(issueId, orbit, {\n recommendationCount: (state?.recommendationCount ?? 0) + 1,\n lastRecommendedAt: new Date(now).toISOString(),\n episodeStartedAt: state?.episodeStartedAt ?? new Date(now).toISOString(),\n ...(state?.lastEscalatedAt ? { lastEscalatedAt: state.lastEscalatedAt } : {}),\n });\n}\n\nfunction recordEscalation(issueId: string, orbit: ParkedOrbit, state: StallSweeperRowState | null, now: number): void {\n writeSweeperRowState(issueId, orbit, {\n recommendationCount: state?.recommendationCount ?? 0,\n ...(state?.lastRecommendedAt ? { lastRecommendedAt: state.lastRecommendedAt } : {}),\n episodeStartedAt: state?.episodeStartedAt ?? new Date(now).toISOString(),\n lastEscalatedAt: new Date(now).toISOString(),\n });\n}\n\n// ─── The patrol ───────────────────────────────────────────────────────────────\n\nexport async function runStallSweeperPatrol(deps: StallSweeperDeps = {}): Promise<string[]> {\n const now = deps.now ?? Date.now();\n const resolveRows = deps.resolveRows ?? resolveParkedPopulation;\n const readArtifact = deps.readArtifact ?? ((issueId: string) => {\n const review = getAgentStateSync(`agent-${issueId.toLowerCase()}-review`);\n return readMemoizedArtifactVerdict(issueId, {\n runId: review?.reviewRunId,\n workspacePath: review?.workspace,\n });\n });\n const isAgentLive = deps.isAgentLive ?? sessionExistsSync;\n const emitActivity = deps.emitActivity ?? defaultEmitActivity;\n const emitEvent = deps.emitEvent ?? defaultEmitEvent;\n\n const rows = await resolveRows();\n const outcome: ScanOutcome = { recommendations: [], escalations: [] };\n\n // Population signature → sweep.scan fires only on CHANGE (a scan that finds\n // the same population is not news; a scan that finds a different one is).\n const signature = rows.map((row) => `${row.issueId}:${row.orbit}`).sort().join('|');\n if (signature !== readSweeperSignature()) {\n emitEvent('sweep.scan', {\n issueCount: new Set(rows.map((row) => row.issueId)).size,\n rowCount: rows.length,\n rows: rows.map((row) => ({ issueId: row.issueId, orbit: row.orbit, parkedAt: row.parkedAt })),\n });\n writeSweeperSignature(signature);\n }\n\n // Resolved rows get their episode state forgotten so a future park starts fresh.\n // (Rows absent from this scan are resolved by definition of the resolver.)\n\n const severity = (row: ParkedRow) => PARKED_ORBIT_SEVERITY.indexOf(row.orbit);\n const work = [...rows].sort((a, b) => severity(a) - severity(b) || a.parkedAt.localeCompare(b.parkedAt));\n let recommendationBudget = SWEEP_MAX_RECOMMENDATIONS_PER_SCAN;\n\n for (const row of work) {\n const { issueId, orbit } = row;\n const state = readSweeperRowState(issueId, orbit);\n\n // Operator-owned rows: never act, re-surface on TTL.\n if (orbit === 'operator-gate' || orbit === 'deacon-ignored' || orbit === 'needs-you' || orbit === 'circuit-breaker') {\n if (dueForResurface(state, now)) {\n recordEscalation(issueId, orbit, state, now);\n emitEvent('sweep.escalated', { issueId, orbit, reason: row.parkReason });\n emitActivity({ level: 'warn', issueId, message: `🧹 sweeper re-surface: ${issueId} is still parked (${orbit}) — ${row.parkReason}. Release: ${row.unparkCondition}` });\n outcome.escalations.push(`${issueId} (${orbit}) re-surfaced to operator`);\n }\n continue;\n }\n\n if (coolingDown(state, orbit, now)) continue;\n if ((state?.recommendationCount ?? 0) >= SWEEP_MAX_RECOMMENDATIONS_PER_ROW) {\n if (dueForResurface(state, now)) {\n recordEscalation(issueId, orbit, state, now);\n emitEvent('sweep.escalated', { issueId, orbit, reason: `exhausted ${SWEEP_MAX_RECOMMENDATIONS_PER_ROW} sweep recommendations` });\n emitActivity({ level: 'warn', issueId, message: `🧹 sweeper: ${issueId} (${orbit}) exhausted ${SWEEP_MAX_RECOMMENDATIONS_PER_ROW} recommendations — needs a human. ${row.parkReason}` });\n outcome.escalations.push(`${issueId} (${orbit}) exhausted → operator`);\n }\n continue;\n }\n if (recommendationBudget <= 0) continue;\n\n const reported = reportRow(row, state, now, { readArtifact, isAgentLive, emitActivity, emitEvent }, outcome);\n if (reported) {\n recordRecommendation(issueId, orbit, state, now);\n recommendationBudget--;\n }\n }\n\n return [...outcome.recommendations, ...outcome.escalations];\n}\n\n// ─── Per-orbit recommendations ────────────────────────────────────────────────\n\ninterface ReportDeps {\n readArtifact: (issueId: string) => SynthesisArtifactVerdict | null;\n isAgentLive: (agentId: string) => boolean;\n emitActivity: (entry: { level: ActivityLevel; issueId?: string; message: string }) => void;\n emitEvent: (type: string, payload: Record<string, unknown>) => void;\n}\n\n/**\n * Build the per-orbit recommendation. This is the ONLY thing the sweeper does\n * with a row: describe the evidence, name the remedy, emit both. There is no\n * action door — see the file-header law.\n *\n * Recommendations always name the CANONICAL existing door (the same machinery\n * the deacon/operator uses — pan resume/start/tell/unstick/review restart/\n * sync-main/done/close), never a sweeper-invented path. A stall that keeps\n * recurring across an episode is a substrate bug by definition: the\n * recommendation says so, so the flywheel's substrate intake files why it\n * keeps parking instead of the symptom being swept forever.\n */\nfunction reportRow(\n row: ParkedRow,\n state: StallSweeperRowState | null,\n now: number,\n reporting: ReportDeps,\n outcome: ScanOutcome,\n): boolean {\n const { issueId, orbit } = row;\n const recurrence = state?.recommendationCount ?? 0;\n const substrateNote = recurrence >= 1\n ? ` This stall has recurred (${recurrence + 1} sweeps this episode) — that is a substrate bug: file why ${issueId} keeps parking here (flywheel substrate intake), don't just remedy the symptom.`\n : '';\n const recommend = (recommendation: string, evidence: Record<string, unknown> = {}) => {\n reporting.emitEvent('sweep.recommendation', { issueId, orbit, recommendation, recurring: recurrence >= 1, ...evidence });\n reporting.emitActivity({ level: 'warn', issueId, message: `🧹 sweeper recommends: ${recommendation} — ${row.parkReason}.${substrateNote} ${NO_ACTION_TRAILER}` });\n outcome.recommendations.push(`${issueId} (${orbit}) recommended: ${recommendation}`);\n };\n\n switch (orbit) {\n case 'zombie-session': {\n const agentId = String(row.details?.agentId ?? `agent-${issueId.toLowerCase()}`);\n const live = reporting.isAgentLive(agentId);\n recommend(`reap zombie session ${agentId} via the existing door (pan close ${issueId} owns merged/closed teardown; the reaper is the backstop)`, { agentId, sessionCurrentlyLive: live });\n return true;\n }\n\n case 'merge-failed': {\n recommend(`reset ${issueId}'s merge for re-evaluation via pan review resync ${issueId}`);\n return true;\n }\n\n case 'uat-failed': {\n // Reaching this orbit means the relay's feedback-target resurrection ladder failed.\n const notes = typeof row.details?.uatNotes === 'string' ? row.details.uatNotes : 'UAT failed — see the UAT panel for details';\n recommend(`start a work agent for ${issueId} via pan start ${issueId} — the UAT-failure relay found no live target for its feedback`, { uatNotes: notes.slice(0, 400) });\n return true;\n }\n\n case 'stuck-flag': {\n const reason = typeof row.details?.stuckReason === 'string' ? row.details.stuckReason : '';\n\n // PAN-3511: evidence from the active review run prevents a recommendation\n // from re-driving work over a review that has already finished. The\n // sweeper remains observability-only and cannot promote that evidence into\n // a terminal review status.\n const artifact = reporting.readArtifact(issueId);\n if (artifact?.verdict === 'passed') {\n recommend(\n `preserve ${issueId}'s passed review evidence from run ${artifact.runId} and await pan admin specialists done review; do not re-dispatch or resume rework`,\n { artifactVerdict: artifact.verdict, artifactRunId: artifact.runId, artifactHead: artifact.headSha },\n );\n return true;\n }\n if (reason === 'review_infrastructure_failure') {\n recommend(`clear ${issueId}'s infra-failure stuck flag and re-dispatch the review via pan unstick ${issueId} && pan review restart ${issueId}`);\n return true;\n }\n if (reason === 'feedback_delivery_needs_you' || reason === 'verification_stuck') {\n recommend(\n artifact?.notes\n ? `resume ${issueId} rework via pan resume agent-${issueId.toLowerCase()} using the blocker from review run ${artifact.runId}`\n : `resume ${issueId} rework from the pending feedback via pan resume agent-${issueId.toLowerCase()} (feedback is in .pan/feedback)`,\n artifact?.notes ? { artifactVerdict: artifact.verdict, artifactRunId: artifact.runId, reviewNotes: artifact.notes.slice(0, 400) } : {},\n );\n return true;\n }\n // Unknown / dead-end stuck flavors are operator-owned — re-surface on TTL.\n if (dueForResurface(state, now)) {\n recordEscalation(issueId, orbit, state, now);\n reporting.emitEvent('sweep.escalated', { issueId, orbit, reason: row.parkReason });\n reporting.emitActivity({ level: 'warn', issueId, message: `🧹 sweeper re-surface: ${issueId} remains stuck (${reason || 'unknown'}) — ${row.parkReason}` });\n outcome.escalations.push(`${issueId} (stuck:${reason || 'unknown'}) re-surfaced`);\n }\n return false;\n }\n\n case 'idle-running': {\n const agentId = String(row.details?.agentId ?? `agent-${issueId.toLowerCase()}`);\n const lastActivity = typeof row.details?.idleMinutes === 'number' ? row.details.idleMinutes : 0;\n if (state?.lastRecommendedAt && now - Date.parse(state.lastRecommendedAt) < IDLE_RECOMMEND_GRACE_MS) return false;\n const previouslyRecommended = !!state?.lastRecommendedAt;\n recommend(\n previouslyRecommended\n ? `stop or resume ${agentId} via pan kill ${agentId} / pan resume ${agentId} — still idle ${Math.round(lastActivity / 60)}h after a prior recommendation`\n : `nudge ${agentId} via pan tell ${agentId} — idle ${Math.round(lastActivity / 60)}h with no pipeline stage owning its next move`,\n { agentId, idleMinutes: lastActivity, live: reporting.isAgentLive(agentId) },\n );\n return true;\n }\n\n default:\n return false;\n }\n}\n\n/** Forget episode state for rows that left the population (called by tests + future reconcilers). */\nexport function forgetResolvedSweeperRows(currentRows: readonly ParkedRow[]): void {\n const live = new Set(currentRows.map((row) => `${row.issueId}:${row.orbit}`));\n for (const row of currentRows) {\n if (!live.has(`${row.issueId}:${row.orbit}`)) clearSweeperRowState(row.issueId, row.orbit);\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { a as postUatGenerationStackPayload, c as runUatTrainReconcileAllProjects, i as postUatGenerationPromotePayload, l as startUatTrainReconciler, n as getUatCandidatePayload, o as resolveUatProjectRoot, r as getUatGenerationsPayload, s as runUatTrainReconcile, t as canStartUatTrainReconciler, u as stopUatTrainReconciler } from "./uat-train-CSOval9z.js";
1
+ import { a as postUatGenerationStackPayload, c as runUatTrainReconcileAllProjects, i as postUatGenerationPromotePayload, l as startUatTrainReconciler, n as getUatCandidatePayload, o as resolveUatProjectRoot, r as getUatGenerationsPayload, s as runUatTrainReconcile, t as canStartUatTrainReconciler, u as stopUatTrainReconciler } from "./uat-train-DVUNW03P.js";
2
2
  export { canStartUatTrainReconciler, getUatCandidatePayload, getUatGenerationsPayload, postUatGenerationPromotePayload, postUatGenerationStackPayload, resolveUatProjectRoot, runUatTrainReconcile, runUatTrainReconcileAllProjects, startUatTrainReconciler, stopUatTrainReconciler };