instar 1.3.62 → 1.3.63

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 (57) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +132 -8
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +20 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  8. package/dist/core/PostUpdateMigrator.js +22 -0
  9. package/dist/core/PostUpdateMigrator.js.map +1 -1
  10. package/dist/core/ReapGuard.d.ts +79 -0
  11. package/dist/core/ReapGuard.d.ts.map +1 -0
  12. package/dist/core/ReapGuard.js +114 -0
  13. package/dist/core/ReapGuard.js.map +1 -0
  14. package/dist/core/SessionLivenessOracle.d.ts +104 -0
  15. package/dist/core/SessionLivenessOracle.d.ts.map +1 -0
  16. package/dist/core/SessionLivenessOracle.js +201 -0
  17. package/dist/core/SessionLivenessOracle.js.map +1 -0
  18. package/dist/core/SessionManager.d.ts +90 -10
  19. package/dist/core/SessionManager.d.ts.map +1 -1
  20. package/dist/core/SessionManager.js +200 -40
  21. package/dist/core/SessionManager.js.map +1 -1
  22. package/dist/core/types.d.ts +30 -0
  23. package/dist/core/types.d.ts.map +1 -1
  24. package/dist/core/types.js.map +1 -1
  25. package/dist/monitoring/ReapLog.d.ts +51 -0
  26. package/dist/monitoring/ReapLog.d.ts.map +1 -0
  27. package/dist/monitoring/ReapLog.js +82 -0
  28. package/dist/monitoring/ReapLog.js.map +1 -0
  29. package/dist/monitoring/ReapNotifier.d.ts +66 -0
  30. package/dist/monitoring/ReapNotifier.d.ts.map +1 -0
  31. package/dist/monitoring/ReapNotifier.js +112 -0
  32. package/dist/monitoring/ReapNotifier.js.map +1 -0
  33. package/dist/monitoring/SessionReaper.d.ts +4 -0
  34. package/dist/monitoring/SessionReaper.d.ts.map +1 -1
  35. package/dist/monitoring/SessionReaper.js +19 -42
  36. package/dist/monitoring/SessionReaper.js.map +1 -1
  37. package/dist/monitoring/StaleSessionBackstop.d.ts +89 -0
  38. package/dist/monitoring/StaleSessionBackstop.d.ts.map +1 -0
  39. package/dist/monitoring/StaleSessionBackstop.js +176 -0
  40. package/dist/monitoring/StaleSessionBackstop.js.map +1 -0
  41. package/dist/scaffold/templates.d.ts.map +1 -1
  42. package/dist/scaffold/templates.js +5 -0
  43. package/dist/scaffold/templates.js.map +1 -1
  44. package/dist/server/AgentServer.d.ts +3 -0
  45. package/dist/server/AgentServer.d.ts.map +1 -1
  46. package/dist/server/AgentServer.js +1 -0
  47. package/dist/server/AgentServer.js.map +1 -1
  48. package/dist/server/routes.d.ts +1 -0
  49. package/dist/server/routes.d.ts.map +1 -1
  50. package/dist/server/routes.js +33 -11
  51. package/dist/server/routes.js.map +1 -1
  52. package/package.json +1 -1
  53. package/src/data/builtin-manifest.json +64 -64
  54. package/src/scaffold/templates.ts +5 -0
  55. package/upgrades/1.3.62.md +43 -45
  56. package/upgrades/1.3.63.md +87 -0
  57. package/upgrades/side-effects/unified-session-lifecycle-robustness.md +241 -0
@@ -6,6 +6,8 @@
6
6
  * and can be monitored/reaped by the server.
7
7
  */
8
8
  import { EventEmitter } from 'node:events';
9
+ import { SessionLivenessOracle } from './SessionLivenessOracle.js';
10
+ import type { ReapGuard } from './ReapGuard.js';
9
11
  /** Diagnostics for a single running session */
10
12
  export interface SessionDiagnostic {
11
13
  name: string;
@@ -59,6 +61,13 @@ export declare class SessionManager extends EventEmitter {
59
61
  private subagentChecker?;
60
62
  /** Optional callback: is this session currently in active compaction recovery? If so, skip zombie kill. */
61
63
  private activeRecoveryChecker?;
64
+ /** Shared stateless KEEP-guard consulted by terminateSession (§P2). */
65
+ private reapGuard?;
66
+ /** Sessions the §P5 backstop has flagged long-`indeterminate` — excluded from
67
+ * the ABSOLUTE spawn cap so unverifiable panes can't lock out spawning. */
68
+ private longIndeterminateSessions;
69
+ /** Multi-machine lease/awake predicate gating autonomous reaps (§Multi-machine). */
70
+ private isAwakeMachine?;
62
71
  /** Optional callback: is this tmux session currently bound to a live messaging topic
63
72
  * (Telegram/Slack/iMessage)? Returns a stable identifier (e.g. topic ID or channel ID)
64
73
  * when bound, null otherwise. When bound, the zombie-kill threshold is extended via
@@ -100,6 +109,15 @@ export declare class SessionManager extends EventEmitter {
100
109
  /** Per-session shim directory root (one subdir per session). Used for K9 mandatory shim. */
101
110
  private shimRoot;
102
111
  constructor(config: SessionManagerConfig, state: StateManager);
112
+ /** Lazily-constructed tri-state liveness oracle (UNIFIED-SESSION-LIFECYCLE §P1).
113
+ * Backs the boot purge and isSessionAliveAsync so a slow/unreachable tmux is
114
+ * treated as `indeterminate`, never `dead`. */
115
+ private _livenessOracle;
116
+ private get livenessOracle();
117
+ /** Test/DI seam: inject a liveness oracle (e.g. one with a scripted exec).
118
+ * Production builds the oracle lazily from config; this lets unit tests drive
119
+ * the alive/dead/indeterminate verdicts deterministically. */
120
+ setLivenessOracle(oracle: SessionLivenessOracle): void;
103
121
  /** Effective idle-at-prompt kill threshold (config override or hardcoded default) */
104
122
  private get effectiveIdleKillMinutes();
105
123
  /** Effective idle-at-prompt kill threshold for sessions bound to a live messaging topic.
@@ -157,6 +175,41 @@ export declare class SessionManager extends EventEmitter {
157
175
  * window. Wired by CompactionSentinel at server startup.
158
176
  */
159
177
  setActiveRecoveryChecker(checker: (session: Session) => boolean): void;
178
+ /**
179
+ * Register the shared ReapGuard (UNIFIED-SESSION-LIFECYCLE §P2). Once set,
180
+ * every AUTONOMOUS terminate consults it: a non-null KEEP reason makes the
181
+ * terminate a no-op `{ terminated:false, skipped:<reason> }`. Wired in server.ts
182
+ * with the same signal closures that back SessionReaper, so a killer can only
183
+ * *request* a kill — the authority refuses to end a guarded session. Operator
184
+ * kills bypass the guard. Unset (tests/standalone) → no guard consult.
185
+ */
186
+ setReapGuard(guard: ReapGuard): void;
187
+ /**
188
+ * Flag/unflag a session as long-`indeterminate` (UNIFIED-SESSION-LIFECYCLE §P5).
189
+ * Driven by the StaleSessionBackstop. A flagged session still counts toward the
190
+ * soft scheduler cap, but is excluded from the ABSOLUTE `maxSessions × 3` cap so
191
+ * a fleet of unverifiable panes can never lock a human out of spawning.
192
+ */
193
+ markLongIndeterminate(sessionId: string, isLong: boolean): void;
194
+ /**
195
+ * Resolve tri-state liveness for many sessions from ONE tmux snapshot via the
196
+ * P1 oracle (UNIFIED-SESSION-LIFECYCLE §P5 backstop). `reachable` is false when
197
+ * the snapshot was non-authoritative (control plane unreachable) — in which
198
+ * case every session resolves `indeterminate`. Shares the oracle's short-TTL
199
+ * cache, so the backstop and boot-purge never double-probe within a tick.
200
+ */
201
+ probeLivenessBatch(tmuxSessions: string[]): Promise<{
202
+ reachable: boolean;
203
+ liveness: Map<string, 'alive' | 'dead' | 'indeterminate'>;
204
+ }>;
205
+ /**
206
+ * Register the multi-machine lease/awake predicate. When set and it returns
207
+ * false, an AUTONOMOUS terminate is a no-op `skipped:'not-lease-holder'` — only
208
+ * the awake/lease-holding machine may autonomously reap; a standby may detect
209
+ * and signal but never kill another machine's sessions. Operator kills bypass.
210
+ * Unset → treated as awake (single-machine default).
211
+ */
212
+ setAwakeChecker(fn: () => boolean): void;
160
213
  /**
161
214
  * Set the Prompt Gate InputDetector for prompt monitoring.
162
215
  * When set, monitorTick() will capture output and feed it to the detector.
@@ -190,20 +243,40 @@ export declare class SessionManager extends EventEmitter {
190
243
  /** True if a reap is in flight for this session. */
191
244
  isReaping(sessionId: string): boolean;
192
245
  /**
193
- * Single-writer session termination (SESSION-REAPER-SPEC §3.6). Both the
194
- * idle-kill path and the SessionReaper funnel through this so a session is
195
- * killed at most once with exactly-once `beforeSessionKill`/`sessionComplete`
246
+ * Single-writer session termination — the sole ReapAuthority
247
+ * (UNIFIED-SESSION-LIFECYCLE §P0, building on SESSION-REAPER-SPEC §3.6). EVERY
248
+ * autonomous killer funnels through this so a session is killed at most once,
249
+ * with exactly-once `beforeSessionKill`/`sessionComplete`/`sessionReaped`
196
250
  * emission and a correct `endedReason`.
197
251
  *
198
- * Compare-and-set semantics: a session that is not in a live state
199
- * ('starting'/'running'), or whose termination is already in flight, is a
200
- * no-op — this is what prevents the idle-kill ↔ reaper double-kill race.
252
+ * The authority holds the safety checks so a killer can only *request* a kill:
253
+ * - CAS on live status + an in-flight guard (prevents the double-kill race).
254
+ * - `protectedSessions` (never kill).
255
+ * - Lease-holder gate: an AUTONOMOUS reap on a standby machine is a no-op
256
+ * `skipped:'not-lease-holder'` — only the awake machine reaps.
257
+ * - ReapGuard (§P2): an AUTONOMOUS reap of a session the guard says to KEEP is
258
+ * a no-op `skipped:<keep-reason>` — even a buggy killer cannot end a guarded
259
+ * session.
260
+ * `origin:'operator'` bypasses the lease-gate and the guard (an explicit human
261
+ * kill must always happen). Default `origin` is `'autonomous'` so an in-process
262
+ * caller can never accidentally mint operator privilege.
263
+ *
264
+ * Re-entrancy: the guard is consulted BEFORE this call acquires its own
265
+ * in-flight lock, so the authority's lock for the kill it is performing is
266
+ * never misread by the guard.
267
+ *
268
+ * `disposition:'recovery-bounce'` marks a kill-to-respawn (SessionRecovery,
269
+ * version-skew, context-exhaustion) so the §P3 notifier stays silent — that is
270
+ * a bounce, not a disappearance. Default `'terminal'`.
201
271
  *
202
272
  * @returns `{ terminated: true }` on a kill performed by THIS call, or
203
273
  * `{ terminated: false, skipped }` describing why it was a no-op.
204
274
  */
205
275
  terminateSession(sessionId: string, reason: string, opts?: {
206
276
  finalStatus?: 'completed' | 'killed';
277
+ disposition?: 'terminal' | 'recovery-bounce';
278
+ origin?: 'operator' | 'autonomous';
279
+ knownDead?: boolean;
207
280
  }): Promise<{
208
281
  terminated: boolean;
209
282
  skipped?: string;
@@ -355,10 +428,17 @@ export declare class SessionManager extends EventEmitter {
355
428
  sessions: Session[];
356
429
  };
357
430
  /**
358
- * Fast startup purge — immediately remove session records for dead tmux sessions.
359
- * Called once at server boot BEFORE monitoring starts, to prevent the death spiral
360
- * where stale sessions overwhelm startup and block health checks.
361
- * Uses a short timeout (1s) per session to fail fast.
431
+ * Fast startup purge — remove session records for sessions that are *definitively*
432
+ * dead. Called once at server boot BEFORE monitoring starts, to prevent the death
433
+ * spiral where stale records overwhelm startup and block health checks.
434
+ *
435
+ * UNIFIED-SESSION-LIFECYCLE §P1 (the 2026-05-27 fix): liveness is resolved from a
436
+ * single `tmux list-sessions` via the tri-state oracle, NOT a per-session
437
+ * `has-session` with a 1s timeout. The old code treated a timeout (tmux busy at
438
+ * boot) identically to "session gone" and mass-purged live sessions — "9 of 9".
439
+ * Now ONLY a `dead` verdict (server reachable + exact id absent) purges; `alive`
440
+ * and `indeterminate` are kept. An indeterminate session lingers one extra tick
441
+ * (cheap, caught by monitoring) rather than being falsely reaped (expensive).
362
442
  */
363
443
  purgeDeadSessions(): Promise<number>;
364
444
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"SessionManager.d.ts","sourceRoot":"","sources":["../../src/core/SessionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionManager.d.ts","sourceRoot":"","sources":["../../src/core/SessionManager.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,7 @@ import fs from 'node:fs';
13
13
  import os from 'node:os';
14
14
  import path from 'node:path';
15
15
  import { fileURLToPath } from 'node:url';
16
+ import { SessionLivenessOracle } from './SessionLivenessOracle.js';
16
17
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
18
  import { DegradationReporter } from '../monitoring/DegradationReporter.js';
18
19
  import { detectRateLimited } from '../monitoring/rateLimitDetection.js';
@@ -94,6 +95,13 @@ export class SessionManager extends EventEmitter {
94
95
  subagentChecker;
95
96
  /** Optional callback: is this session currently in active compaction recovery? If so, skip zombie kill. */
96
97
  activeRecoveryChecker;
98
+ /** Shared stateless KEEP-guard consulted by terminateSession (§P2). */
99
+ reapGuard;
100
+ /** Sessions the §P5 backstop has flagged long-`indeterminate` — excluded from
101
+ * the ABSOLUTE spawn cap so unverifiable panes can't lock out spawning. */
102
+ longIndeterminateSessions = new Set();
103
+ /** Multi-machine lease/awake predicate gating autonomous reaps (§Multi-machine). */
104
+ isAwakeMachine;
97
105
  /** Optional callback: is this tmux session currently bound to a live messaging topic
98
106
  * (Telegram/Slack/iMessage)? Returns a stable identifier (e.g. topic ID or channel ID)
99
107
  * when bound, null otherwise. When bound, the zombie-kill threshold is extended via
@@ -139,6 +147,22 @@ export class SessionManager extends EventEmitter {
139
147
  this.config = config;
140
148
  this.state = state;
141
149
  }
150
+ /** Lazily-constructed tri-state liveness oracle (UNIFIED-SESSION-LIFECYCLE §P1).
151
+ * Backs the boot purge and isSessionAliveAsync so a slow/unreachable tmux is
152
+ * treated as `indeterminate`, never `dead`. */
153
+ _livenessOracle = null;
154
+ get livenessOracle() {
155
+ if (!this._livenessOracle) {
156
+ this._livenessOracle = new SessionLivenessOracle({ tmuxPath: this.config.tmuxPath, exec: execFileAsync }, this.config.liveness);
157
+ }
158
+ return this._livenessOracle;
159
+ }
160
+ /** Test/DI seam: inject a liveness oracle (e.g. one with a scripted exec).
161
+ * Production builds the oracle lazily from config; this lets unit tests drive
162
+ * the alive/dead/indeterminate verdicts deterministically. */
163
+ setLivenessOracle(oracle) {
164
+ this._livenessOracle = oracle;
165
+ }
142
166
  /** Effective idle-at-prompt kill threshold (config override or hardcoded default) */
143
167
  get effectiveIdleKillMinutes() {
144
168
  return this.config.idlePromptKillMinutes ?? FALLBACK_IDLE_PROMPT_KILL_MINUTES;
@@ -250,6 +274,57 @@ rm() { "${shimRunner}" rm "$@"; }
250
274
  setActiveRecoveryChecker(checker) {
251
275
  this.activeRecoveryChecker = checker;
252
276
  }
277
+ /**
278
+ * Register the shared ReapGuard (UNIFIED-SESSION-LIFECYCLE §P2). Once set,
279
+ * every AUTONOMOUS terminate consults it: a non-null KEEP reason makes the
280
+ * terminate a no-op `{ terminated:false, skipped:<reason> }`. Wired in server.ts
281
+ * with the same signal closures that back SessionReaper, so a killer can only
282
+ * *request* a kill — the authority refuses to end a guarded session. Operator
283
+ * kills bypass the guard. Unset (tests/standalone) → no guard consult.
284
+ */
285
+ setReapGuard(guard) {
286
+ this.reapGuard = guard;
287
+ }
288
+ /**
289
+ * Flag/unflag a session as long-`indeterminate` (UNIFIED-SESSION-LIFECYCLE §P5).
290
+ * Driven by the StaleSessionBackstop. A flagged session still counts toward the
291
+ * soft scheduler cap, but is excluded from the ABSOLUTE `maxSessions × 3` cap so
292
+ * a fleet of unverifiable panes can never lock a human out of spawning.
293
+ */
294
+ markLongIndeterminate(sessionId, isLong) {
295
+ if (isLong)
296
+ this.longIndeterminateSessions.add(sessionId);
297
+ else
298
+ this.longIndeterminateSessions.delete(sessionId);
299
+ }
300
+ /**
301
+ * Resolve tri-state liveness for many sessions from ONE tmux snapshot via the
302
+ * P1 oracle (UNIFIED-SESSION-LIFECYCLE §P5 backstop). `reachable` is false when
303
+ * the snapshot was non-authoritative (control plane unreachable) — in which
304
+ * case every session resolves `indeterminate`. Shares the oracle's short-TTL
305
+ * cache, so the backstop and boot-purge never double-probe within a tick.
306
+ */
307
+ async probeLivenessBatch(tmuxSessions) {
308
+ const results = await this.livenessOracle.probeAll(tmuxSessions);
309
+ const liveness = new Map();
310
+ for (const [name, r] of results)
311
+ liveness.set(name, r.liveness);
312
+ // With a single authoritative snapshot, a session is only `indeterminate`
313
+ // when the whole snapshot was non-authoritative — i.e. the server is
314
+ // unreachable. So "reachable" ⟺ at least one definitive (alive/dead) verdict.
315
+ const reachable = tmuxSessions.length === 0 || [...liveness.values()].some((l) => l !== 'indeterminate');
316
+ return { reachable, liveness };
317
+ }
318
+ /**
319
+ * Register the multi-machine lease/awake predicate. When set and it returns
320
+ * false, an AUTONOMOUS terminate is a no-op `skipped:'not-lease-holder'` — only
321
+ * the awake/lease-holding machine may autonomously reap; a standby may detect
322
+ * and signal but never kill another machine's sessions. Operator kills bypass.
323
+ * Unset → treated as awake (single-machine default).
324
+ */
325
+ setAwakeChecker(fn) {
326
+ this.isAwakeMachine = fn;
327
+ }
253
328
  /**
254
329
  * Set the Prompt Gate InputDetector for prompt monitoring.
255
330
  * When set, monitorTick() will capture output and feed it to the detector.
@@ -307,14 +382,31 @@ rm() { "${shimRunner}" rm "$@"; }
307
382
  return this.reapingSessions.has(sessionId);
308
383
  }
309
384
  /**
310
- * Single-writer session termination (SESSION-REAPER-SPEC §3.6). Both the
311
- * idle-kill path and the SessionReaper funnel through this so a session is
312
- * killed at most once with exactly-once `beforeSessionKill`/`sessionComplete`
385
+ * Single-writer session termination — the sole ReapAuthority
386
+ * (UNIFIED-SESSION-LIFECYCLE §P0, building on SESSION-REAPER-SPEC §3.6). EVERY
387
+ * autonomous killer funnels through this so a session is killed at most once,
388
+ * with exactly-once `beforeSessionKill`/`sessionComplete`/`sessionReaped`
313
389
  * emission and a correct `endedReason`.
314
390
  *
315
- * Compare-and-set semantics: a session that is not in a live state
316
- * ('starting'/'running'), or whose termination is already in flight, is a
317
- * no-op — this is what prevents the idle-kill ↔ reaper double-kill race.
391
+ * The authority holds the safety checks so a killer can only *request* a kill:
392
+ * - CAS on live status + an in-flight guard (prevents the double-kill race).
393
+ * - `protectedSessions` (never kill).
394
+ * - Lease-holder gate: an AUTONOMOUS reap on a standby machine is a no-op
395
+ * `skipped:'not-lease-holder'` — only the awake machine reaps.
396
+ * - ReapGuard (§P2): an AUTONOMOUS reap of a session the guard says to KEEP is
397
+ * a no-op `skipped:<keep-reason>` — even a buggy killer cannot end a guarded
398
+ * session.
399
+ * `origin:'operator'` bypasses the lease-gate and the guard (an explicit human
400
+ * kill must always happen). Default `origin` is `'autonomous'` so an in-process
401
+ * caller can never accidentally mint operator privilege.
402
+ *
403
+ * Re-entrancy: the guard is consulted BEFORE this call acquires its own
404
+ * in-flight lock, so the authority's lock for the kill it is performing is
405
+ * never misread by the guard.
406
+ *
407
+ * `disposition:'recovery-bounce'` marks a kill-to-respawn (SessionRecovery,
408
+ * version-skew, context-exhaustion) so the §P3 notifier stays silent — that is
409
+ * a bounce, not a disappearance. Default `'terminal'`.
318
410
  *
319
411
  * @returns `{ terminated: true }` on a kill performed by THIS call, or
320
412
  * `{ terminated: false, skipped }` describing why it was a no-op.
@@ -327,8 +419,42 @@ rm() { "${shimRunner}" rm "$@"; }
327
419
  if (session.status !== 'running' && session.status !== 'starting') {
328
420
  return { terminated: false, skipped: `already-${session.status}` };
329
421
  }
330
- if (this.config.protectedSessions.includes(session.tmuxSession)) {
331
- return { terminated: false, skipped: 'protected' };
422
+ const origin = opts?.origin ?? 'autonomous';
423
+ const disposition = opts?.disposition ?? 'terminal';
424
+ // ── Authority gates (autonomous only; operator bypasses) ──
425
+ // An `origin:'operator'` kill — stamped ONLY by the Bearer-authed HTTP route
426
+ // layer — must always happen: the user clicked "kill". It bypasses protected,
427
+ // the lease gate, and the KEEP-guard. Autonomous killers (the default) can
428
+ // only *request*; the authority holds the safety checks.
429
+ if (origin === 'autonomous') {
430
+ // Protected set — never autonomously reap a protected session.
431
+ if (this.config.protectedSessions.includes(session.tmuxSession)) {
432
+ this.emit('reapBlocked', { session, reason, skipped: 'protected', origin });
433
+ return { terminated: false, skipped: 'protected' };
434
+ }
435
+ // Lease-holder gate: a standby machine never reaps another machine's sessions.
436
+ if (this.isAwakeMachine && !this.isAwakeMachine()) {
437
+ this.emit('reapBlocked', { session, reason, skipped: 'not-lease-holder', origin });
438
+ return { terminated: false, skipped: 'not-lease-holder' };
439
+ }
440
+ // ReapGuard: refuse to end a session the guard says to KEEP. Consulted
441
+ // before the in-flight lock is acquired (re-entrancy ordering).
442
+ //
443
+ // `knownDead` bypass (boot-purge, #1): the caller has already proven the
444
+ // session is `dead` via the P1 oracle (tmux server reachable + exact id
445
+ // absent). The guard exists to protect a LIVE-but-busy session from being
446
+ // mistaken for dead — its topic-state KEEP reasons (recent-user-message,
447
+ // open-commitment) are liveness-blind, so consulting it on a proven-dead
448
+ // session would pin a tombstone in the running list and re-create the boot
449
+ // death-spiral the purge guards against. A proven-dead session has no
450
+ // liveness to protect, so skip the guard. Lease + protected + CAS still apply.
451
+ if (!opts?.knownDead) {
452
+ const blocked = this.reapGuard?.blockedReason(session);
453
+ if (blocked) {
454
+ this.emit('reapBlocked', { session, reason, skipped: blocked.reason, origin });
455
+ return { terminated: false, skipped: blocked.reason };
456
+ }
457
+ }
332
458
  }
333
459
  // In-flight guard: a concurrent terminate already owns this session.
334
460
  if (this.terminating.has(sessionId)) {
@@ -348,6 +474,9 @@ rm() { "${shimRunner}" rm "$@"; }
348
474
  session.endedReason = reason;
349
475
  this.state.saveSession(session);
350
476
  this.emit('sessionComplete', session);
477
+ // The single reap-notification signal (§P3): terminal reaps may reach the
478
+ // user; recovery-bounce reaps are silent. One emission, at the one chokepoint.
479
+ this.emit('sessionReaped', { session, reason, disposition, origin });
351
480
  this.idlePromptSince.delete(session.id);
352
481
  this.reapingSessions.delete(session.id);
353
482
  return { terminated: true };
@@ -527,20 +656,17 @@ rm() { "${shimRunner}" rm "$@"; }
527
656
  injectedAt: pendingInjection.injectedAt,
528
657
  });
529
658
  }
530
- console.warn(`[SessionManager] Session "${session.name}" exceeded timeout (${Math.round(elapsed)}m > ${maxMinutes}m) and is idle. Killing.`);
531
- // Emit beforeSessionKill BEFORE destroying the tmux session so
532
- // listeners (e.g. TopicResumeMap) can discover the Claude UUID.
533
- this.emit('beforeSessionKill', session);
534
- try {
535
- await execFileAsync(this.config.tmuxPath, ['kill-session', '-t', `=${session.tmuxSession}`]);
536
- }
537
- catch {
538
- // @silent-fallback-ok — tmux kill, session may be dead
539
- }
540
- session.status = 'killed';
541
- session.endedAt = new Date().toISOString();
542
- this.state.saveSession(session);
543
- this.emit('sessionComplete', session);
659
+ console.warn(`[SessionManager] Session "${session.name}" exceeded timeout (${Math.round(elapsed)}m > ${maxMinutes}m) and is idle. Requesting kill via ReapAuthority.`);
660
+ // Route through the single ReapAuthority (§P0) instead of an inline
661
+ // kill: this restores the beforeSessionKill/sessionComplete emission,
662
+ // adds the sessionReaped signal + reap-log entry, applies the lease
663
+ // gate, and — critically — gains the P2 KEEP-guard's topic-bound
664
+ // grace, so a session that just received a user message is not
665
+ // age-killed out from under the user.
666
+ await this.terminateSession(session.id, 'age-limit', {
667
+ finalStatus: 'killed',
668
+ disposition: 'terminal',
669
+ });
544
670
  continue;
545
671
  }
546
672
  }
@@ -646,8 +772,11 @@ rm() { "${shimRunner}" rm "$@"; }
646
772
  const bindingNote = binding != null ? ` (topic-bound, threshold ${killThresholdMinutes}m)` : ` (threshold ${killThresholdMinutes}m)`;
647
773
  console.warn(`[SessionManager] Session "${session.name}" idle at prompt for ${Math.round(idleMs / 60_000)}m with no active processes${bindingNote}. Killing zombie.`);
648
774
  // Funnel through the single-writer path so the reaper and this
649
- // idle-kill can never double-kill or double-emit (§3.6).
650
- await this.terminateSession(session.id, 'idle-zombie');
775
+ // idle-kill can never double-kill or double-emit (§3.6). Explicit
776
+ // terminal disposition → the §P3 notifier surfaces it to the user.
777
+ await this.terminateSession(session.id, 'idle-zombie', {
778
+ disposition: 'terminal',
779
+ });
651
780
  continue;
652
781
  }
653
782
  }
@@ -1170,32 +1299,58 @@ rm() { "${shimRunner}" rm "$@"; }
1170
1299
  return { count: this._cachedRunningCount, sessions: this._cachedRunningSessions };
1171
1300
  }
1172
1301
  /**
1173
- * Fast startup purge — immediately remove session records for dead tmux sessions.
1174
- * Called once at server boot BEFORE monitoring starts, to prevent the death spiral
1175
- * where stale sessions overwhelm startup and block health checks.
1176
- * Uses a short timeout (1s) per session to fail fast.
1302
+ * Fast startup purge — remove session records for sessions that are *definitively*
1303
+ * dead. Called once at server boot BEFORE monitoring starts, to prevent the death
1304
+ * spiral where stale records overwhelm startup and block health checks.
1305
+ *
1306
+ * UNIFIED-SESSION-LIFECYCLE §P1 (the 2026-05-27 fix): liveness is resolved from a
1307
+ * single `tmux list-sessions` via the tri-state oracle, NOT a per-session
1308
+ * `has-session` with a 1s timeout. The old code treated a timeout (tmux busy at
1309
+ * boot) identically to "session gone" and mass-purged live sessions — "9 of 9".
1310
+ * Now ONLY a `dead` verdict (server reachable + exact id absent) purges; `alive`
1311
+ * and `indeterminate` are kept. An indeterminate session lingers one extra tick
1312
+ * (cheap, caught by monitoring) rather than being falsely reaped (expensive).
1177
1313
  */
1178
1314
  async purgeDeadSessions() {
1179
1315
  const running = this.state.listSessions({ status: 'running' });
1180
1316
  if (running.length === 0)
1181
1317
  return 0;
1318
+ const verdicts = await this.livenessOracle.probeAll(running.map((s) => s.tmuxSession));
1182
1319
  let purged = 0;
1320
+ let kept = 0;
1321
+ let indeterminate = 0;
1322
+ let skipped = 0;
1183
1323
  for (const session of running) {
1184
- try {
1185
- execFileSync(this.config.tmuxPath, ['has-session', '-t', `=${session.tmuxSession}`], {
1186
- stdio: 'ignore', timeout: 1000,
1324
+ const v = verdicts.get(session.tmuxSession);
1325
+ if (v?.liveness === 'dead') {
1326
+ // Route through the single ReapAuthority (§P0) so the reap is lease-gated,
1327
+ // recorded in the reap-log, and emits the standard lifecycle events. The
1328
+ // KEEP-guard is bypassed via `knownDead` — the oracle has already proven
1329
+ // this session dead, and the guard's liveness-blind topic-state KEEPs would
1330
+ // otherwise pin a tombstone and re-create the death-spiral.
1331
+ const r = await this.terminateSession(session.id, 'boot-purge-dead', {
1332
+ knownDead: true,
1333
+ finalStatus: 'completed',
1187
1334
  });
1335
+ if (r.terminated)
1336
+ purged++;
1337
+ else
1338
+ skipped++; // not-lease-holder / protected — recorded, kept for next awake tick
1188
1339
  }
1189
- catch {
1190
- // tmux session doesn't exist — purge the record
1191
- session.status = 'completed';
1192
- session.endedAt = new Date().toISOString();
1193
- this.state.saveSession(session);
1194
- purged++;
1340
+ else {
1341
+ kept++;
1342
+ if (v?.liveness === 'indeterminate')
1343
+ indeterminate++;
1195
1344
  }
1196
1345
  }
1197
- if (purged > 0) {
1198
- console.log(`[SessionManager] Startup purge: removed ${purged} dead session(s) of ${running.length} tracked`);
1346
+ if (purged > 0 || indeterminate > 0 || skipped > 0) {
1347
+ console.log(`[SessionManager] Startup purge: removed ${purged} dead session(s) of ${running.length} tracked` +
1348
+ (indeterminate > 0
1349
+ ? ` (${indeterminate} indeterminate — KEPT, will re-verify on the next tick rather than risk a false purge)`
1350
+ : '') +
1351
+ (skipped > 0
1352
+ ? ` (${skipped} dead but not reaped here — standby/protected, deferred to the awake machine)`
1353
+ : ''));
1199
1354
  }
1200
1355
  return purged;
1201
1356
  }
@@ -1401,7 +1556,12 @@ rm() { "${shimRunner}" rm "$@"; }
1401
1556
  // Safety valve: still cap at maxSessions * 3 to prevent runaway sessions.
1402
1557
  const runningSessions = this.listRunningSessions();
1403
1558
  const absoluteLimit = this.config.maxSessions * 3;
1404
- if (runningSessions.length >= absoluteLimit) {
1559
+ // §P5: exclude long-`indeterminate` sessions (unverifiable panes flagged by the
1560
+ // StaleSessionBackstop) from the ABSOLUTE cap, so a fleet of them can never lock
1561
+ // a human out of spawning — the death-spiral the boot purge guarded against
1562
+ // cannot relocate here.
1563
+ const countable = runningSessions.filter(s => !this.longIndeterminateSessions.has(s.id));
1564
+ if (countable.length >= absoluteLimit) {
1405
1565
  throw new Error(`Absolute session limit (${absoluteLimit}) reached. ` +
1406
1566
  `Running: ${runningSessions.map(s => s.name).join(', ')}`);
1407
1567
  }