instar 1.3.409 → 1.3.411

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 (33) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +13 -3
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/lifeline/MessageQueue.d.ts +22 -2
  5. package/dist/lifeline/MessageQueue.d.ts.map +1 -1
  6. package/dist/lifeline/MessageQueue.js +41 -1
  7. package/dist/lifeline/MessageQueue.js.map +1 -1
  8. package/dist/lifeline/TelegramLifeline.js +2 -2
  9. package/dist/lifeline/TelegramLifeline.js.map +1 -1
  10. package/dist/messaging/MessageProcessingLedger.d.ts +22 -0
  11. package/dist/messaging/MessageProcessingLedger.d.ts.map +1 -1
  12. package/dist/messaging/MessageProcessingLedger.js +58 -6
  13. package/dist/messaging/MessageProcessingLedger.js.map +1 -1
  14. package/dist/messaging/ingressDedup.d.ts +3 -1
  15. package/dist/messaging/ingressDedup.d.ts.map +1 -1
  16. package/dist/messaging/ingressDedup.js +1 -1
  17. package/dist/messaging/ingressDedup.js.map +1 -1
  18. package/dist/messaging/stuckMessageRecovery.d.ts +13 -2
  19. package/dist/messaging/stuckMessageRecovery.d.ts.map +1 -1
  20. package/dist/messaging/stuckMessageRecovery.js +20 -4
  21. package/dist/messaging/stuckMessageRecovery.js.map +1 -1
  22. package/dist/monitoring/SessionWatchdog.d.ts +1 -1
  23. package/dist/monitoring/SessionWatchdog.d.ts.map +1 -1
  24. package/dist/monitoring/SessionWatchdog.js +55 -25
  25. package/dist/monitoring/SessionWatchdog.js.map +1 -1
  26. package/dist/server/routes.d.ts.map +1 -1
  27. package/dist/server/routes.js +5 -0
  28. package/dist/server/routes.js.map +1 -1
  29. package/package.json +1 -1
  30. package/src/data/builtin-manifest.json +47 -47
  31. package/upgrades/1.3.411.md +93 -0
  32. package/upgrades/side-effects/stuck-recovery-replay-dedupe.md +88 -0
  33. package/upgrades/side-effects/watchdog-nonblocking-scans.md +81 -0
@@ -0,0 +1,81 @@
1
+ # Side-Effects Review — SessionWatchdog non-blocking process scans
2
+
3
+ **Version / slug:** `watchdog-nonblocking-scans`
4
+ **Date:** `2026-06-07`
5
+ **Author:** `Echo`
6
+ **Tier:** 1 (internal monitor refactor; no API/route/config/migration surface)
7
+ **Second-pass reviewer:** `Echo (self) — Tier-1; the behavior-equivalence + ordering analysis below is load-bearing`
8
+
9
+ ## Summary of the change
10
+
11
+ `SessionWatchdog` polled every 30s over EVERY running session, running several
12
+ `ps`/`pgrep` probes per session via **synchronous** `spawnSync` (5s timeout each).
13
+ Each probe blocked the single Node event loop for its full duration; under load
14
+ (dozens of sessions, a busy box) the cumulative stall made the server miss its own
15
+ `/health` window → false "server temporarily down" + restart loop (2026-06-07 topic
16
+ 21816 incident). This converts the watchdog's process scans to async (`execFile`) and
17
+ makes the poll yield the loop between sessions. File: `src/monitoring/SessionWatchdog.ts`.
18
+
19
+ - `shellExec` (spawnSync) → `shellExecAsync` (`promisify(execFile)`); returns captured
20
+ stdout or '' on non-zero exit/timeout — identical to the prior `.stdout ?? ''`.
21
+ - `getFrameworkPid`, `getClaudePid`, `getChildProcesses`, `hasActivePipelineSibling`,
22
+ `checkCompactionIdle` are now `async`; all internal callers (`checkSession`,
23
+ `checkCompactionIdle`) `await` them.
24
+ - `poll()` `await new Promise(setImmediate)` between sessions so a scan over many
25
+ sessions can never monopolize the loop.
26
+
27
+ ## Decision-point inventory
28
+
29
+ - The watchdog's escalation/kill decisions are UNCHANGED — only the I/O mechanism of
30
+ the read-only process probes changed (sync → async). Same commands, same parsing,
31
+ same thresholds, same LLM gate.
32
+ - No message block/allow surface. No new route/config/migration.
33
+
34
+ ## 1. Over-block (escalating a session that shouldn't be)
35
+
36
+ Behavior is preserved: the probe commands, output parsing, stuck-thresholds, pipeline
37
+ guard, and LLM gate are byte-for-byte the same. `execFile`'s non-zero-exit throw is
38
+ caught and mapped to the captured stdout (or '') — matching `spawnSync(...).stdout ??
39
+ ''`, which never threw. So a pgrep/egrep no-match still reads as "no PID / no children",
40
+ exactly as before. No new false escalation path.
41
+
42
+ ## 2. Under-block (missing a genuinely stuck session)
43
+
44
+ The scans now interleave with other event-loop work, but each poll still visits every
45
+ session and runs the same probes; nothing is skipped. The 5s per-probe timeout is
46
+ preserved (passed to execFile). A probe that times out returns '' (treated as
47
+ "unknown / no match") exactly as the sync version did. The `running` re-entrancy guard
48
+ still prevents overlapping polls.
49
+
50
+ ## 3. Level-of-abstraction fit
51
+
52
+ Correct layer. This is the same OS-process read, moved off the synchronous path so it
53
+ shares the loop cooperatively. No LLM involved in the scan itself.
54
+
55
+ ## 4. Ordering / concurrency
56
+
57
+ The methods became async, so within a single `checkSession` the probes now `await`
58
+ (yield) between steps. A session could be killed between two awaited probes — but the
59
+ existing code already tolerates "process gone" (empty output → null/empty list), so a
60
+ mid-scan disappearance degrades to the same no-op as a dead pid. The per-session
61
+ `await` + the inter-session `setImmediate` only ADD yield points; they do not reorder
62
+ the decisions within a session.
63
+
64
+ ## 5. Blast radius
65
+
66
+ Single file. The watchdog is opt-in (`monitoring.watchdog.enabled`). The async
67
+ conversion does not change what the watchdog DOES, only that it stops starving the
68
+ event loop while doing it. Tests for compaction/pipeline/mcp-exclusion/rate-limit all
69
+ pass unchanged (their sync `mockReturnValue` stubs work under `await`).
70
+
71
+ ## 6. Rollback
72
+
73
+ Pure code revert. No state/format/config change.
74
+
75
+ ## 7. Tests
76
+
77
+ `tests/unit/SessionWatchdog-nonblocking.test.ts` (new): the scanning helpers return
78
+ Promises (async), a 0ms timer fires during an in-flight probe (loop stays live), and
79
+ source guards assert no `spawnSync(` call, `execFileAsync` present, the three helpers
80
+ are async, and `poll()` yields via `setImmediate`. Existing watchdog suites updated to
81
+ `await` the now-async methods. 72 watchdog unit tests green; `tsc --noEmit` clean.