@telora/daemon 0.22.13 → 0.22.52

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 (155) hide show
  1. package/build-info.json +5 -3
  2. package/dist/backends/index.d.ts.map +1 -1
  3. package/dist/backends/index.js +1 -0
  4. package/dist/backends/index.js.map +1 -1
  5. package/dist/ci/ci-status.d.ts.map +1 -1
  6. package/dist/ci/ci-status.js +1 -0
  7. package/dist/ci/ci-status.js.map +1 -1
  8. package/dist/completion/detector.d.ts +9 -0
  9. package/dist/completion/detector.d.ts.map +1 -1
  10. package/dist/completion/detector.js +18 -0
  11. package/dist/completion/detector.js.map +1 -1
  12. package/dist/completion/event-phases.d.ts +20 -0
  13. package/dist/completion/event-phases.d.ts.map +1 -1
  14. package/dist/completion/event-phases.js +46 -13
  15. package/dist/completion/event-phases.js.map +1 -1
  16. package/dist/completion/event.d.ts +69 -9
  17. package/dist/completion/event.d.ts.map +1 -1
  18. package/dist/completion/event.js +109 -22
  19. package/dist/completion/event.js.map +1 -1
  20. package/dist/completion/liveness-firing.d.ts +27 -0
  21. package/dist/completion/liveness-firing.d.ts.map +1 -0
  22. package/dist/completion/liveness-firing.js +79 -0
  23. package/dist/completion/liveness-firing.js.map +1 -0
  24. package/dist/completion/review-exit-phase.js +4 -4
  25. package/dist/completion/review-exit-phase.js.map +1 -1
  26. package/dist/completion/state-cascade.d.ts.map +1 -1
  27. package/dist/completion/state-cascade.js +8 -0
  28. package/dist/completion/state-cascade.js.map +1 -1
  29. package/dist/completion/stdin-turn-tracker.d.ts +19 -0
  30. package/dist/completion/stdin-turn-tracker.d.ts.map +1 -0
  31. package/dist/completion/stdin-turn-tracker.js +57 -0
  32. package/dist/completion/stdin-turn-tracker.js.map +1 -0
  33. package/dist/completion/supervision-firing-record.d.ts +242 -0
  34. package/dist/completion/supervision-firing-record.d.ts.map +1 -0
  35. package/dist/completion/supervision-firing-record.js +292 -0
  36. package/dist/completion/supervision-firing-record.js.map +1 -0
  37. package/dist/completion/team-lifecycle.d.ts.map +1 -1
  38. package/dist/completion/team-lifecycle.js +9 -0
  39. package/dist/completion/team-lifecycle.js.map +1 -1
  40. package/dist/directive/directive-dispatch.d.ts +7 -1
  41. package/dist/directive/directive-dispatch.d.ts.map +1 -1
  42. package/dist/directive/directive-dispatch.js +105 -39
  43. package/dist/directive/directive-dispatch.js.map +1 -1
  44. package/dist/directive/directive-executor.d.ts +1 -10
  45. package/dist/directive/directive-executor.d.ts.map +1 -1
  46. package/dist/directive/directive-executor.js +51 -33
  47. package/dist/directive/directive-executor.js.map +1 -1
  48. package/dist/directive/directive-queue.d.ts +35 -9
  49. package/dist/directive/directive-queue.d.ts.map +1 -1
  50. package/dist/directive/directive-queue.js +15 -8
  51. package/dist/directive/directive-queue.js.map +1 -1
  52. package/dist/directive/directive-verify-hold-gate.d.ts +33 -0
  53. package/dist/directive/directive-verify-hold-gate.d.ts.map +1 -0
  54. package/dist/directive/directive-verify-hold-gate.js +57 -0
  55. package/dist/directive/directive-verify-hold-gate.js.map +1 -0
  56. package/dist/directive/phase-sync.d.ts +11 -0
  57. package/dist/directive/phase-sync.d.ts.map +1 -1
  58. package/dist/directive/phase-sync.js +12 -0
  59. package/dist/directive/phase-sync.js.map +1 -1
  60. package/dist/drift/staleness-sensor.d.ts +62 -67
  61. package/dist/drift/staleness-sensor.d.ts.map +1 -1
  62. package/dist/drift/staleness-sensor.js +233 -68
  63. package/dist/drift/staleness-sensor.js.map +1 -1
  64. package/dist/drift/staleness.d.ts +8 -0
  65. package/dist/drift/staleness.d.ts.map +1 -1
  66. package/dist/drift/staleness.js +7 -1
  67. package/dist/drift/staleness.js.map +1 -1
  68. package/dist/focus/focus-engine.js +1 -1
  69. package/dist/focus/focus-engine.js.map +1 -1
  70. package/dist/focus/focus-team-state.d.ts.map +1 -1
  71. package/dist/focus/focus-team-state.js +2 -0
  72. package/dist/focus/focus-team-state.js.map +1 -1
  73. package/dist/focus/focus-worktree-state.d.ts.map +1 -1
  74. package/dist/focus/focus-worktree-state.js +5 -2
  75. package/dist/focus/focus-worktree-state.js.map +1 -1
  76. package/dist/focus/listener-spawn.d.ts +39 -0
  77. package/dist/focus/listener-spawn.d.ts.map +1 -1
  78. package/dist/focus/listener-spawn.js +140 -24
  79. package/dist/focus/listener-spawn.js.map +1 -1
  80. package/dist/focus/listener.d.ts.map +1 -1
  81. package/dist/focus/listener.js +53 -25
  82. package/dist/focus/listener.js.map +1 -1
  83. package/dist/focus/session-health.d.ts +25 -3
  84. package/dist/focus/session-health.d.ts.map +1 -1
  85. package/dist/focus/session-health.js +32 -1
  86. package/dist/focus/session-health.js.map +1 -1
  87. package/dist/focus/team-actionable-work.d.ts +41 -2
  88. package/dist/focus/team-actionable-work.d.ts.map +1 -1
  89. package/dist/focus/team-actionable-work.js +52 -7
  90. package/dist/focus/team-actionable-work.js.map +1 -1
  91. package/dist/merge/focus-merge.d.ts +12 -1
  92. package/dist/merge/focus-merge.d.ts.map +1 -1
  93. package/dist/merge/focus-merge.js +33 -2
  94. package/dist/merge/focus-merge.js.map +1 -1
  95. package/dist/nexus/return.d.ts +105 -1
  96. package/dist/nexus/return.d.ts.map +1 -1
  97. package/dist/nexus/return.js +237 -47
  98. package/dist/nexus/return.js.map +1 -1
  99. package/dist/queries/schemas.d.ts +12 -0
  100. package/dist/queries/schemas.d.ts.map +1 -1
  101. package/dist/queries/schemas.js +7 -0
  102. package/dist/queries/schemas.js.map +1 -1
  103. package/dist/queries/sessions.d.ts.map +1 -1
  104. package/dist/queries/sessions.js +1 -0
  105. package/dist/queries/sessions.js.map +1 -1
  106. package/dist/shell/heartbeat-metadata.d.ts +102 -0
  107. package/dist/shell/heartbeat-metadata.d.ts.map +1 -0
  108. package/dist/shell/heartbeat-metadata.js +172 -0
  109. package/dist/shell/heartbeat-metadata.js.map +1 -0
  110. package/dist/shell/heartbeat.d.ts +7 -22
  111. package/dist/shell/heartbeat.d.ts.map +1 -1
  112. package/dist/shell/heartbeat.js +120 -89
  113. package/dist/shell/heartbeat.js.map +1 -1
  114. package/dist/shell/unified-shell.d.ts.map +1 -1
  115. package/dist/shell/unified-shell.js +21 -12
  116. package/dist/shell/unified-shell.js.map +1 -1
  117. package/dist/spawn/helpers.d.ts.map +1 -1
  118. package/dist/spawn/helpers.js +7 -1
  119. package/dist/spawn/helpers.js.map +1 -1
  120. package/dist/spawn/process-spawn.d.ts +32 -1
  121. package/dist/spawn/process-spawn.d.ts.map +1 -1
  122. package/dist/spawn/process-spawn.js +43 -5
  123. package/dist/spawn/process-spawn.js.map +1 -1
  124. package/dist/testing/fixtures/index.js +1 -1
  125. package/dist/types/index.js +1 -1
  126. package/dist/types/session.d.ts +11 -0
  127. package/dist/types/session.d.ts.map +1 -1
  128. package/dist/update/auto-update-idle.d.ts +22 -0
  129. package/dist/update/auto-update-idle.d.ts.map +1 -1
  130. package/dist/update/auto-update-idle.js +8 -1
  131. package/dist/update/auto-update-idle.js.map +1 -1
  132. package/dist/update/auto-update.d.ts +0 -6
  133. package/dist/update/auto-update.d.ts.map +1 -1
  134. package/dist/update/auto-update.js +20 -6
  135. package/dist/update/auto-update.js.map +1 -1
  136. package/dist/update/version-check.d.ts +73 -0
  137. package/dist/update/version-check.d.ts.map +1 -1
  138. package/dist/update/version-check.js +107 -11
  139. package/dist/update/version-check.js.map +1 -1
  140. package/dist/verify/stall-detector-config.d.ts +26 -0
  141. package/dist/verify/stall-detector-config.d.ts.map +1 -1
  142. package/dist/verify/stall-detector-config.js +32 -0
  143. package/dist/verify/stall-detector-config.js.map +1 -1
  144. package/dist/verify/stall-detectors.d.ts +40 -0
  145. package/dist/verify/stall-detectors.d.ts.map +1 -1
  146. package/dist/verify/stall-detectors.js +60 -6
  147. package/dist/verify/stall-detectors.js.map +1 -1
  148. package/dist/verify/stalled-team-backstop.d.ts +43 -0
  149. package/dist/verify/stalled-team-backstop.d.ts.map +1 -0
  150. package/dist/verify/stalled-team-backstop.js +131 -0
  151. package/dist/verify/stalled-team-backstop.js.map +1 -0
  152. package/dist/worktree/verify-interlock.d.ts.map +1 -1
  153. package/dist/worktree/verify-interlock.js +3 -1
  154. package/dist/worktree/verify-interlock.js.map +1 -1
  155. package/package.json +3 -3
@@ -0,0 +1,57 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/completion/stdin-turn-tracker.test.ts,
3
+ // packages/daemon/src/spawn/spawn-compact-turn.test.ts
4
+ // PINNED-BY-END
5
+ /**
6
+ * Stdin-turn tracker -- orders team teardown after queued directive delivery.
7
+ *
8
+ * The completion detector fires `complete` when the lead finishes a turn (a
9
+ * `result` event) with no active subagents, and the completion handler tears the
10
+ * team down. But the daemon may have WRITTEN more stdin user messages to the team
11
+ * than the CLI has resulted yet: a coding-stage /compact + content injected ~0.4s
12
+ * after spawn sit queued BEHIND the long kickoff turn, and the kickoff's result
13
+ * triggers teardown before they run (2026-09-06: 5 of 10 /compact sends lost this
14
+ * way).
15
+ *
16
+ * This tracks stdin user messages SENT per focus. The completion detector reads
17
+ * it (pendingStdinTurns) and SUPPRESSES `complete` while more messages have been
18
+ * written than the CLI has resulted (turnCount, one result event per turn -- see
19
+ * CompletionDetector). So a team with queued stdin turns is not classified done
20
+ * until it has processed them.
21
+ *
22
+ * Conservative + bounded by construction: it only DELAYS completion (never kills
23
+ * early), it is INERT for a normal spawn (kickoff alone -> sent === turnCount), and
24
+ * a directive the CLI never results leaves the team to the existing backstops (the
25
+ * process-close path and the stall/liveness detectors), not wedged here.
26
+ *
27
+ * @module completion/stdin-turn-tracker
28
+ */
29
+ /** stdin user messages the daemon has written to each focus's live team. */
30
+ const sentByFocus = new Map();
31
+ /**
32
+ * Record one stdin user message written to a focus's team (the spawn kickoff
33
+ * write, and each executeInjectDirective sendMessage). One write == one CLI turn
34
+ * == one eventual `result` event.
35
+ */
36
+ export function recordStdinMessageSent(focusId) {
37
+ sentByFocus.set(focusId, (sentByFocus.get(focusId) ?? 0) + 1);
38
+ }
39
+ /**
40
+ * Whether the focus has stdin turns queued but not yet resulted: the daemon has
41
+ * written more user messages than the CLI has completed (`turnCount`). The
42
+ * completion detector suppresses `complete` while this is true so a queued
43
+ * directive is delivered before teardown. False when nothing was written (the map
44
+ * has no entry) -- so a team with no injected directive completes normally.
45
+ */
46
+ export function pendingStdinTurns(focusId, turnCount) {
47
+ return (sentByFocus.get(focusId) ?? 0) > turnCount;
48
+ }
49
+ /** Clear a focus's tracking on teardown (a respawn starts a fresh count / detector). */
50
+ export function clearStdinTurnTracking(focusId) {
51
+ sentByFocus.delete(focusId);
52
+ }
53
+ /** Test-only: reset all tracking. */
54
+ export function __resetStdinTurnTrackingForTesting() {
55
+ sentByFocus.clear();
56
+ }
57
+ //# sourceMappingURL=stdin-turn-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin-turn-tracker.js","sourceRoot":"","sources":["../../src/completion/stdin-turn-tracker.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,wEAAwE;AACxE,yDAAyD;AACzD,gBAAgB;AAEhB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,4EAA4E;AAC5E,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,SAAiB;IAClE,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;AACrD,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,kCAAkC;IAChD,WAAW,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Supervision firing records -- the falsifiability instrument.
3
+ *
4
+ * The mechanisms that can END, HOLD, or RESPAWN a team (teardown-at-first-result,
5
+ * the spawn-gate-vs-exit respawn, the liveness badge, stall detectors, the verify
6
+ * interlock) were unfalsifiable: nothing recorded whether a firing was later
7
+ * borne out, so a false positive (the 80-spawn storm, the 5 lost compactions on
8
+ * 2026-09-06) was discoverable only by grepping the log after the cost was paid.
9
+ *
10
+ * This module gives every such mechanism a small firing record with a LATER-
11
+ * classified verdict: a firing predicts an outcome ("this team has no more
12
+ * actionable work"; "this respawn has work to do"; "this team is unresponsive"),
13
+ * and once reality is known the firing is classified true_positive (the
14
+ * prediction was borne out) or false_positive (it was not). The per-mechanism
15
+ * false-positive RATE is then a reading (surfaced in the heartbeat + metrics),
16
+ * and demotion from block to observe becomes a policy driven by that reading
17
+ * rather than a human hand-diagnosing a stuck mode.
18
+ *
19
+ * In-memory + bounded (a per-mechanism ring buffer): this is a live falsifiability
20
+ * signal for the running daemon, not a durable audit log. The ratchet pattern
21
+ * (scripts/ratchet-*.mjs) is the precedent for demote-on-reading; this is its
22
+ * runtime analogue.
23
+ *
24
+ * @module completion/supervision-firing-record
25
+ */
26
+ /** The supervision mechanisms covered first (the three implicated 2026-09-06). */
27
+ export declare const SUPERVISION_MECHANISM: {
28
+ /** The completion handler ends a team at its first `result`. Predicts: the team
29
+ * had no more actionable work / nothing queued still to run. */
30
+ readonly TEARDOWN_AT_FIRST_RESULT: "teardown_at_first_result";
31
+ /** The spawn gate respawns a focus its exit classifier just declared done.
32
+ * Predicts: the respawned focus has team-actionable work. */
33
+ readonly SPAWN_GATE_VS_EXIT_RESPAWN: "spawn_gate_vs_exit_respawn";
34
+ /** The liveness badge marks a team unresponsive. Predicts: the team is wedged
35
+ * (not a legitimate multi-minute park). */
36
+ readonly LIVENESS_BADGE: "liveness_badge";
37
+ /** The poll-loop stalled-team backstop reaps a live `executing` team that has
38
+ * emitted no agent event past the backstop window, WITHOUT waiting for the
39
+ * completion event (which can be suppressed / never fire / be latched -- the
40
+ * 2026-09-07 wedge). Predicts: the idle team is wedged, not mid-long-operation. */
41
+ readonly STALLED_TEAM_REAP: "stalled_team_reap";
42
+ };
43
+ export type SupervisionMechanism = (typeof SUPERVISION_MECHANISM)[keyof typeof SUPERVISION_MECHANISM];
44
+ /** A firing's later-classified verdict. */
45
+ export type FiringVerdict = 'true_positive' | 'false_positive' | 'unclassified';
46
+ /** One recorded firing of a supervision mechanism. */
47
+ export interface SupervisionFiring {
48
+ /** Monotonic id, unique within this daemon run. */
49
+ id: number;
50
+ /** Which mechanism fired (a SUPERVISION_MECHANISM value; a string so a new
51
+ * mechanism can record without a type change). */
52
+ mechanism: string;
53
+ /** The focus the firing acted on. */
54
+ focusId: string;
55
+ /** Epoch ms the mechanism fired. */
56
+ firedAt: number;
57
+ /** The outcome the mechanism PREDICTED when it fired (free text, per mechanism). */
58
+ predicted: string;
59
+ /** Verdict, classified later from the observed outcome. */
60
+ verdict: FiringVerdict;
61
+ /**
62
+ * Whether the mechanism ACTUALLY took its kill/hold/respawn action when it
63
+ * fired. True by default (most firings act). Set false at the suppression sites
64
+ * when the mechanism is demoted to observe-only and records without acting.
65
+ * An UNACTED firing had no action to falsify, so the settle sweep must never
66
+ * true-positive it by silence -- doing so was the self-laundering bug (a
67
+ * demotion lifting itself and erasing the FP history that justified it). An
68
+ * unacted firing is scored ONLY by an active event that observes what the
69
+ * unblocked system actually went on to do; until then it stays unclassified.
70
+ */
71
+ acted: boolean;
72
+ /**
73
+ * How the verdict was reached: 'active' (an observed falsifying/confirming
74
+ * event) vs 'sweep' (the settle window elapsed with no falsifying event).
75
+ * Absent while unclassified. Lets a reading tell a verdict EARNED in action
76
+ * from one inferred from silence.
77
+ */
78
+ classifiedBy?: 'active' | 'sweep';
79
+ /** Epoch ms the verdict was classified (absent while unclassified). */
80
+ classifiedAt?: number;
81
+ /** The outcome actually observed at classification time (absent while unclassified). */
82
+ observed?: string;
83
+ }
84
+ /** Aggregate reading for one mechanism over a window. */
85
+ export interface FiringStats {
86
+ mechanism: string;
87
+ total: number;
88
+ truePositives: number;
89
+ falsePositives: number;
90
+ unclassified: number;
91
+ /** falsePositives / (truePositives + falsePositives); null when none are
92
+ * classified yet (a rate over zero classified firings is undefined, never 0). */
93
+ falsePositiveRate: number | null;
94
+ /** Firings recorded while the mechanism was demoted (acted===false): observe-only
95
+ * counterfactuals, never true-positived by silence. */
96
+ unacted: number;
97
+ /** True positives reached by an OBSERVED event (classifiedBy==='active'). */
98
+ activeTruePositives: number;
99
+ /** True positives inferred from the settle window elapsing (classifiedBy==='sweep').
100
+ * A reading that separates accuracy EARNED in action from the benefit of the
101
+ * doubt silence gives an acted firing. */
102
+ sweptTruePositives: number;
103
+ }
104
+ /** Max firings retained per mechanism (oldest evicted). Bounds memory; the rate
105
+ * is a recency signal, not a full history. */
106
+ export declare const FIRING_BUFFER_CAP = 256;
107
+ /**
108
+ * Settle window: an ACTED prediction that survives this long with no falsifying
109
+ * event is swept to true_positive. It is also the FP horizon by construction -- an
110
+ * active classifier (e.g. a teardown falsified by a re-ready focus) can only fire
111
+ * while the firing is still unclassified, i.e. younger than this. So a teardown a
112
+ * focus contradicts QUICKLY (the storm) is FP; one that stands past the window is
113
+ * TP. One knob. 3 minutes: longer than a spawn cooldown / re-ready cycle, short
114
+ * enough that the rate reflects recent behavior.
115
+ *
116
+ * The sweep applies ONLY to ACTED firings: an unacted firing (recorded while the
117
+ * mechanism was demoted to observe-only) had no action, so silence proves nothing
118
+ * about it. True-positiving unacted firings by silence was the self-laundering bug
119
+ * -- it lifted a demotion within one settle window and erased the FP history that
120
+ * justified it, regardless of the mechanism's real accuracy.
121
+ */
122
+ export declare const FIRING_SETTLE_WINDOW_MS = 180000;
123
+ /**
124
+ * Record a mechanism firing. Returns the firing id so the caller can classify it
125
+ * later once the predicted outcome is known. The buffer is bounded per mechanism.
126
+ */
127
+ export declare function recordFiring(args: {
128
+ mechanism: string;
129
+ focusId: string;
130
+ predicted: string;
131
+ now?: number;
132
+ }): number;
133
+ /**
134
+ * Flip the MOST RECENT firing of `mechanism` for `focusId` to UNACTED -- the
135
+ * mechanism recorded it but, being demoted to observe-only, did NOT take its
136
+ * kill/hold/respawn action. An unacted firing is never true-positived by the
137
+ * settle sweep (silence cannot vindicate an action that never happened); it is
138
+ * scored only by an active event observing what the unblocked system did. Returns
139
+ * true if a firing was found and flipped. Idempotent: re-flipping an already
140
+ * unacted firing is a no-op.
141
+ */
142
+ export declare function markLatestFiringUnacted(mechanism: string, focusId: string): boolean;
143
+ /**
144
+ * Classify a recorded firing from the outcome it predicted: `borneOut` true means
145
+ * the prediction held (true_positive), false means it did not (false_positive).
146
+ * A no-op if the id is unknown (evicted or never recorded) or already classified.
147
+ */
148
+ export declare function classifyFiring(id: number, args: {
149
+ borneOut: boolean;
150
+ observed: string;
151
+ now?: number;
152
+ }): void;
153
+ /**
154
+ * Aggregate the reading for one mechanism over the firings within `windowMs`
155
+ * (default: all retained). The false-positive rate is over CLASSIFIED firings
156
+ * only; null when none are classified yet.
157
+ */
158
+ export declare function firingStats(mechanism: string, opts?: {
159
+ windowMs?: number;
160
+ now?: number;
161
+ }): FiringStats;
162
+ /**
163
+ * Classify the MOST RECENT still-unclassified firing of `mechanism` for `focusId`
164
+ * from the outcome it predicted, and report whether one was found. The active
165
+ * classification path: a caller that observes the falsifying (or confirming)
166
+ * event for a focus -- e.g. the spawn gate respawning a focus a teardown just
167
+ * declared work-free -- classifies that specific prior firing without threading
168
+ * its id through unrelated code. A no-op (returns false) when the focus has no
169
+ * unclassified firing of that mechanism (e.g. a first-ever spawn, no prior
170
+ * teardown).
171
+ */
172
+ export declare function classifyLatestUnclassifiedFiring(mechanism: string, focusId: string, args: {
173
+ borneOut: boolean;
174
+ observed: string;
175
+ now?: number;
176
+ }): boolean;
177
+ /**
178
+ * Settle sweep: classify every still-unclassified ACTED firing older than
179
+ * `olderThanMs` as borne out (true_positive) -- the prediction HELD because no
180
+ * falsifying event arrived within the settle window (FPs are classified actively
181
+ * at their falsifying event, so an aged unclassified ACTED firing is one nothing
182
+ * contradicted). UNACTED firings are skipped: a firing whose mechanism was demoted
183
+ * and took no action has nothing for silence to vindicate, so sweeping it to TP
184
+ * would launder the demotion (lift it and erase the FP record that justified it).
185
+ * An unacted firing is scored only by an active event. Optionally scoped to one
186
+ * `mechanism`. Returns the number classified. Idempotent and cheap; call it from
187
+ * the poll loop.
188
+ */
189
+ export declare function sweepAgedFirings(args: {
190
+ olderThanMs: number;
191
+ now?: number;
192
+ mechanism?: string;
193
+ observed?: string;
194
+ }): number;
195
+ /** Min classified firings before demotion can be recommended -- a single early FP
196
+ * must not disable a mechanism. */
197
+ export declare const DEMOTE_MIN_CLASSIFIED = 8;
198
+ /** Window the demotion policy reads the rate over (1 hour). */
199
+ export declare const DEMOTE_WINDOW_MS = 3600000;
200
+ /**
201
+ * Demotion policy -- the CONDITION a mechanism must meet to be demoted to
202
+ * observe-only. This is the pure predicate; the heartbeat surfaces it as a
203
+ * reading (demotionRecommended) and the action sites ENFORCE it via
204
+ * isMechanismDemoted (below). "Converge first" (the focus statement) was about
205
+ * not DELETING supervision code -- demotion to observe-only is a runtime,
206
+ * reversible, data-driven gate, which the AC requires be enforced, not merely
207
+ * reported (AC/FRT #10: "demoted to observe-only -- it records but no longer
208
+ * kills or holds -- by policy").
209
+ *
210
+ * A mechanism has earned demotion when, over the window, it has at least
211
+ * DEMOTE_MIN_CLASSIFIED classified firings AND ZERO true positives -- it has NEVER
212
+ * been right in a meaningful sample. The min-sample guard keeps a single early FP
213
+ * from disabling a mechanism. The reading is over a window and self-lifting: as a
214
+ * demoted mechanism's firings age (or sweep to TP because, no longer acting, it
215
+ * has nothing left to falsify them), the condition clears and the mechanism
216
+ * re-arms -- a brief circuit-break during a storm, not a permanent disable.
217
+ */
218
+ export declare function isDemotionRecommended(mechanism: string, opts?: {
219
+ windowMs?: number;
220
+ minClassified?: number;
221
+ now?: number;
222
+ }): boolean;
223
+ /**
224
+ * Enforcement gate: whether a mechanism is currently DEMOTED and its caller must
225
+ * therefore skip the kill/hold/respawn (record the firing, take no action). The
226
+ * single seam every action site reads so the block-to-observe policy lives in one
227
+ * place -- and so it can later diverge from the raw reading (e.g. an operator
228
+ * kill-switch, or a per-mechanism min-sample) without touching every call site.
229
+ * Same condition as isDemotionRecommended today; a distinct name so an action
230
+ * site reads as enforcement ("if demoted, do not terminate") rather than as the
231
+ * advisory reading the heartbeat shows.
232
+ */
233
+ export declare function isMechanismDemoted(mechanism: string, opts?: {
234
+ windowMs?: number;
235
+ minClassified?: number;
236
+ now?: number;
237
+ }): boolean;
238
+ /** The mechanisms that currently have at least one recorded firing. */
239
+ export declare function firingMechanisms(): string[];
240
+ /** Test-only: clear all recorded firings and reset the id counter. */
241
+ export declare function __resetFiringRecordsForTesting(): void;
242
+ //# sourceMappingURL=supervision-firing-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervision-firing-record.d.ts","sourceRoot":"","sources":["../../src/completion/supervision-firing-record.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,kFAAkF;AAClF,eAAO,MAAM,qBAAqB;IAChC;qEACiE;;IAEjE;kEAC8D;;IAE9D;gDAC4C;;IAE5C;;;wFAGoF;;CAE5E,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAC9B,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,OAAO,qBAAqB,CAAC,CAAC;AAErE,2CAA2C;AAC3C,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAEhF,sDAAsD;AACtD,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX;uDACmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,OAAO,EAAE,aAAa,CAAC;IACvB;;;;;;;;;OASG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,YAAY,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAClC,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,yDAAyD;AACzD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB;sFACkF;IAClF,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;4DACwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;+CAE2C;IAC3C,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;+CAC+C;AAC/C,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB,SAAU,CAAC;AAK/C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GAAG,MAAM,CAmBT;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAWnF;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,IAAI,CAWN;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7C,WAAW,CA+Bb;AAED;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAC9C,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D,OAAO,CAcT;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAqBT;AAED;oCACoC;AACpC,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,UAAY,CAAC;AAE1C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GACrE,OAAO,CAIT;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GACrE,OAAO,CAET;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED,sEAAsE;AACtE,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD"}
@@ -0,0 +1,292 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/completion/liveness-firing.test.ts,
3
+ // packages/daemon/src/completion/supervision-firing-record.test.ts,
4
+ // packages/daemon/src/completion/teardown-demotion-gate.test.ts,
5
+ // packages/daemon/src/focus/respawn-demotion-gate.test.ts,
6
+ // packages/daemon/src/focus/supervision-firing-correlation.test.ts,
7
+ // packages/daemon/src/shell/supervision-firing-rates.test.ts,
8
+ // packages/daemon/src/verify/stalled-team-backstop-detector.test.ts
9
+ // PINNED-BY-END
10
+ /**
11
+ * Supervision firing records -- the falsifiability instrument.
12
+ *
13
+ * The mechanisms that can END, HOLD, or RESPAWN a team (teardown-at-first-result,
14
+ * the spawn-gate-vs-exit respawn, the liveness badge, stall detectors, the verify
15
+ * interlock) were unfalsifiable: nothing recorded whether a firing was later
16
+ * borne out, so a false positive (the 80-spawn storm, the 5 lost compactions on
17
+ * 2026-09-06) was discoverable only by grepping the log after the cost was paid.
18
+ *
19
+ * This module gives every such mechanism a small firing record with a LATER-
20
+ * classified verdict: a firing predicts an outcome ("this team has no more
21
+ * actionable work"; "this respawn has work to do"; "this team is unresponsive"),
22
+ * and once reality is known the firing is classified true_positive (the
23
+ * prediction was borne out) or false_positive (it was not). The per-mechanism
24
+ * false-positive RATE is then a reading (surfaced in the heartbeat + metrics),
25
+ * and demotion from block to observe becomes a policy driven by that reading
26
+ * rather than a human hand-diagnosing a stuck mode.
27
+ *
28
+ * In-memory + bounded (a per-mechanism ring buffer): this is a live falsifiability
29
+ * signal for the running daemon, not a durable audit log. The ratchet pattern
30
+ * (scripts/ratchet-*.mjs) is the precedent for demote-on-reading; this is its
31
+ * runtime analogue.
32
+ *
33
+ * @module completion/supervision-firing-record
34
+ */
35
+ /** The supervision mechanisms covered first (the three implicated 2026-09-06). */
36
+ export const SUPERVISION_MECHANISM = {
37
+ /** The completion handler ends a team at its first `result`. Predicts: the team
38
+ * had no more actionable work / nothing queued still to run. */
39
+ TEARDOWN_AT_FIRST_RESULT: 'teardown_at_first_result',
40
+ /** The spawn gate respawns a focus its exit classifier just declared done.
41
+ * Predicts: the respawned focus has team-actionable work. */
42
+ SPAWN_GATE_VS_EXIT_RESPAWN: 'spawn_gate_vs_exit_respawn',
43
+ /** The liveness badge marks a team unresponsive. Predicts: the team is wedged
44
+ * (not a legitimate multi-minute park). */
45
+ LIVENESS_BADGE: 'liveness_badge',
46
+ /** The poll-loop stalled-team backstop reaps a live `executing` team that has
47
+ * emitted no agent event past the backstop window, WITHOUT waiting for the
48
+ * completion event (which can be suppressed / never fire / be latched -- the
49
+ * 2026-09-07 wedge). Predicts: the idle team is wedged, not mid-long-operation. */
50
+ STALLED_TEAM_REAP: 'stalled_team_reap',
51
+ };
52
+ /** Max firings retained per mechanism (oldest evicted). Bounds memory; the rate
53
+ * is a recency signal, not a full history. */
54
+ export const FIRING_BUFFER_CAP = 256;
55
+ /**
56
+ * Settle window: an ACTED prediction that survives this long with no falsifying
57
+ * event is swept to true_positive. It is also the FP horizon by construction -- an
58
+ * active classifier (e.g. a teardown falsified by a re-ready focus) can only fire
59
+ * while the firing is still unclassified, i.e. younger than this. So a teardown a
60
+ * focus contradicts QUICKLY (the storm) is FP; one that stands past the window is
61
+ * TP. One knob. 3 minutes: longer than a spawn cooldown / re-ready cycle, short
62
+ * enough that the rate reflects recent behavior.
63
+ *
64
+ * The sweep applies ONLY to ACTED firings: an unacted firing (recorded while the
65
+ * mechanism was demoted to observe-only) had no action, so silence proves nothing
66
+ * about it. True-positiving unacted firings by silence was the self-laundering bug
67
+ * -- it lifted a demotion within one settle window and erased the FP history that
68
+ * justified it, regardless of the mechanism's real accuracy.
69
+ */
70
+ export const FIRING_SETTLE_WINDOW_MS = 180_000;
71
+ const firings = new Map();
72
+ let nextId = 1;
73
+ /**
74
+ * Record a mechanism firing. Returns the firing id so the caller can classify it
75
+ * later once the predicted outcome is known. The buffer is bounded per mechanism.
76
+ */
77
+ export function recordFiring(args) {
78
+ const id = nextId++;
79
+ const firing = {
80
+ id,
81
+ mechanism: args.mechanism,
82
+ focusId: args.focusId,
83
+ firedAt: args.now ?? Date.now(),
84
+ predicted: args.predicted,
85
+ verdict: 'unclassified',
86
+ // Recorded as ACTED by default: most firings come from a mechanism that took
87
+ // its action. A suppression site that records-without-acting (demoted to
88
+ // observe-only) calls markLatestFiringUnacted right after to flip this.
89
+ acted: true,
90
+ };
91
+ const buf = firings.get(args.mechanism) ?? [];
92
+ buf.push(firing);
93
+ if (buf.length > FIRING_BUFFER_CAP)
94
+ buf.shift();
95
+ firings.set(args.mechanism, buf);
96
+ return id;
97
+ }
98
+ /**
99
+ * Flip the MOST RECENT firing of `mechanism` for `focusId` to UNACTED -- the
100
+ * mechanism recorded it but, being demoted to observe-only, did NOT take its
101
+ * kill/hold/respawn action. An unacted firing is never true-positived by the
102
+ * settle sweep (silence cannot vindicate an action that never happened); it is
103
+ * scored only by an active event observing what the unblocked system did. Returns
104
+ * true if a firing was found and flipped. Idempotent: re-flipping an already
105
+ * unacted firing is a no-op.
106
+ */
107
+ export function markLatestFiringUnacted(mechanism, focusId) {
108
+ const buf = firings.get(mechanism);
109
+ if (!buf)
110
+ return false;
111
+ for (let i = buf.length - 1; i >= 0; i--) {
112
+ const f = buf[i];
113
+ if (f && f.focusId === focusId) {
114
+ f.acted = false;
115
+ return true;
116
+ }
117
+ }
118
+ return false;
119
+ }
120
+ /**
121
+ * Classify a recorded firing from the outcome it predicted: `borneOut` true means
122
+ * the prediction held (true_positive), false means it did not (false_positive).
123
+ * A no-op if the id is unknown (evicted or never recorded) or already classified.
124
+ */
125
+ export function classifyFiring(id, args) {
126
+ for (const buf of firings.values()) {
127
+ const firing = buf.find((f) => f.id === id);
128
+ if (!firing)
129
+ continue;
130
+ if (firing.verdict !== 'unclassified')
131
+ return;
132
+ firing.verdict = args.borneOut ? 'true_positive' : 'false_positive';
133
+ firing.classifiedBy = 'active';
134
+ firing.classifiedAt = args.now ?? Date.now();
135
+ firing.observed = args.observed;
136
+ return;
137
+ }
138
+ }
139
+ /**
140
+ * Aggregate the reading for one mechanism over the firings within `windowMs`
141
+ * (default: all retained). The false-positive rate is over CLASSIFIED firings
142
+ * only; null when none are classified yet.
143
+ */
144
+ export function firingStats(mechanism, opts = {}) {
145
+ const now = opts.now ?? Date.now();
146
+ const cutoff = opts.windowMs === undefined ? -Infinity : now - opts.windowMs;
147
+ const buf = (firings.get(mechanism) ?? []).filter((f) => f.firedAt >= cutoff);
148
+ let truePositives = 0;
149
+ let falsePositives = 0;
150
+ let unclassified = 0;
151
+ let unacted = 0;
152
+ let activeTruePositives = 0;
153
+ let sweptTruePositives = 0;
154
+ for (const f of buf) {
155
+ if (!f.acted)
156
+ unacted++;
157
+ if (f.verdict === 'true_positive') {
158
+ truePositives++;
159
+ if (f.classifiedBy === 'sweep')
160
+ sweptTruePositives++;
161
+ else
162
+ activeTruePositives++;
163
+ }
164
+ else if (f.verdict === 'false_positive')
165
+ falsePositives++;
166
+ else
167
+ unclassified++;
168
+ }
169
+ const classified = truePositives + falsePositives;
170
+ return {
171
+ mechanism,
172
+ total: buf.length,
173
+ truePositives,
174
+ falsePositives,
175
+ unclassified,
176
+ falsePositiveRate: classified === 0 ? null : falsePositives / classified,
177
+ unacted,
178
+ activeTruePositives,
179
+ sweptTruePositives,
180
+ };
181
+ }
182
+ /**
183
+ * Classify the MOST RECENT still-unclassified firing of `mechanism` for `focusId`
184
+ * from the outcome it predicted, and report whether one was found. The active
185
+ * classification path: a caller that observes the falsifying (or confirming)
186
+ * event for a focus -- e.g. the spawn gate respawning a focus a teardown just
187
+ * declared work-free -- classifies that specific prior firing without threading
188
+ * its id through unrelated code. A no-op (returns false) when the focus has no
189
+ * unclassified firing of that mechanism (e.g. a first-ever spawn, no prior
190
+ * teardown).
191
+ */
192
+ export function classifyLatestUnclassifiedFiring(mechanism, focusId, args) {
193
+ const buf = firings.get(mechanism);
194
+ if (!buf)
195
+ return false;
196
+ for (let i = buf.length - 1; i >= 0; i--) {
197
+ const f = buf[i];
198
+ if (f && f.focusId === focusId && f.verdict === 'unclassified') {
199
+ f.verdict = args.borneOut ? 'true_positive' : 'false_positive';
200
+ f.classifiedBy = 'active';
201
+ f.classifiedAt = args.now ?? Date.now();
202
+ f.observed = args.observed;
203
+ return true;
204
+ }
205
+ }
206
+ return false;
207
+ }
208
+ /**
209
+ * Settle sweep: classify every still-unclassified ACTED firing older than
210
+ * `olderThanMs` as borne out (true_positive) -- the prediction HELD because no
211
+ * falsifying event arrived within the settle window (FPs are classified actively
212
+ * at their falsifying event, so an aged unclassified ACTED firing is one nothing
213
+ * contradicted). UNACTED firings are skipped: a firing whose mechanism was demoted
214
+ * and took no action has nothing for silence to vindicate, so sweeping it to TP
215
+ * would launder the demotion (lift it and erase the FP record that justified it).
216
+ * An unacted firing is scored only by an active event. Optionally scoped to one
217
+ * `mechanism`. Returns the number classified. Idempotent and cheap; call it from
218
+ * the poll loop.
219
+ */
220
+ export function sweepAgedFirings(args) {
221
+ const now = args.now ?? Date.now();
222
+ const cutoff = now - args.olderThanMs;
223
+ const bufs = args.mechanism
224
+ ? [firings.get(args.mechanism)].filter((b) => b !== undefined)
225
+ : [...firings.values()];
226
+ let swept = 0;
227
+ for (const buf of bufs) {
228
+ for (const f of buf) {
229
+ // Skip UNACTED firings: no action happened, so the settle window elapsing
230
+ // proves nothing -- true-positiving it by silence is the self-laundering bug.
231
+ if (f.verdict === 'unclassified' && f.acted && f.firedAt < cutoff) {
232
+ f.verdict = 'true_positive';
233
+ f.classifiedBy = 'sweep';
234
+ f.classifiedAt = now;
235
+ f.observed = args.observed ?? 'settle window elapsed with no falsifying event';
236
+ swept++;
237
+ }
238
+ }
239
+ }
240
+ return swept;
241
+ }
242
+ /** Min classified firings before demotion can be recommended -- a single early FP
243
+ * must not disable a mechanism. */
244
+ export const DEMOTE_MIN_CLASSIFIED = 8;
245
+ /** Window the demotion policy reads the rate over (1 hour). */
246
+ export const DEMOTE_WINDOW_MS = 3_600_000;
247
+ /**
248
+ * Demotion policy -- the CONDITION a mechanism must meet to be demoted to
249
+ * observe-only. This is the pure predicate; the heartbeat surfaces it as a
250
+ * reading (demotionRecommended) and the action sites ENFORCE it via
251
+ * isMechanismDemoted (below). "Converge first" (the focus statement) was about
252
+ * not DELETING supervision code -- demotion to observe-only is a runtime,
253
+ * reversible, data-driven gate, which the AC requires be enforced, not merely
254
+ * reported (AC/FRT #10: "demoted to observe-only -- it records but no longer
255
+ * kills or holds -- by policy").
256
+ *
257
+ * A mechanism has earned demotion when, over the window, it has at least
258
+ * DEMOTE_MIN_CLASSIFIED classified firings AND ZERO true positives -- it has NEVER
259
+ * been right in a meaningful sample. The min-sample guard keeps a single early FP
260
+ * from disabling a mechanism. The reading is over a window and self-lifting: as a
261
+ * demoted mechanism's firings age (or sweep to TP because, no longer acting, it
262
+ * has nothing left to falsify them), the condition clears and the mechanism
263
+ * re-arms -- a brief circuit-break during a storm, not a permanent disable.
264
+ */
265
+ export function isDemotionRecommended(mechanism, opts = {}) {
266
+ const s = firingStats(mechanism, { windowMs: opts.windowMs ?? DEMOTE_WINDOW_MS, now: opts.now });
267
+ const classified = s.truePositives + s.falsePositives;
268
+ return classified >= (opts.minClassified ?? DEMOTE_MIN_CLASSIFIED) && s.truePositives === 0;
269
+ }
270
+ /**
271
+ * Enforcement gate: whether a mechanism is currently DEMOTED and its caller must
272
+ * therefore skip the kill/hold/respawn (record the firing, take no action). The
273
+ * single seam every action site reads so the block-to-observe policy lives in one
274
+ * place -- and so it can later diverge from the raw reading (e.g. an operator
275
+ * kill-switch, or a per-mechanism min-sample) without touching every call site.
276
+ * Same condition as isDemotionRecommended today; a distinct name so an action
277
+ * site reads as enforcement ("if demoted, do not terminate") rather than as the
278
+ * advisory reading the heartbeat shows.
279
+ */
280
+ export function isMechanismDemoted(mechanism, opts = {}) {
281
+ return isDemotionRecommended(mechanism, opts);
282
+ }
283
+ /** The mechanisms that currently have at least one recorded firing. */
284
+ export function firingMechanisms() {
285
+ return [...firings.keys()];
286
+ }
287
+ /** Test-only: clear all recorded firings and reset the id counter. */
288
+ export function __resetFiringRecordsForTesting() {
289
+ firings.clear();
290
+ nextId = 1;
291
+ }
292
+ //# sourceMappingURL=supervision-firing-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervision-firing-record.js","sourceRoot":"","sources":["../../src/completion/supervision-firing-record.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"team-lifecycle.d.ts","sourceRoot":"","sources":["../../src/completion/team-lifecycle.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA8B5D;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,cAAc,CAAC,gBAAgB,CAAC,GAChD,OAAO,CAsET;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAsB1F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAKxC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,mFAAmF;IACnF,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC;CACtD;AAcD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,qBAAqB,GAC1B,uBAAuB,CAgDzB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,mFAAmF;IACnF,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC;CACtD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,mBAAmB,GACxB,uBAAuB,CAuDzB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAyBf;AAuCD;;;;;;;;;;;;GAYG;AACH,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAwIf"}
1
+ {"version":3,"file":"team-lifecycle.d.ts","sourceRoot":"","sources":["../../src/completion/team-lifecycle.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA+B5D;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,cAAc,CAAC,gBAAgB,CAAC,GAChD,OAAO,CA4ET;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAsB1F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAKxC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,mFAAmF;IACnF,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC;CACtD;AAcD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,qBAAqB,GAC1B,uBAAuB,CAiDzB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,mFAAmF;IACnF,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC;CACtD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,mBAAmB,GACxB,uBAAuB,CAwDzB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAyBf;AAuCD;;;;;;;;;;;;GAYG;AACH,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAwIf"}