instar 1.3.642 → 1.3.643

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 (52) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +160 -6
  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 +29 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/InFlightSyncOpMarker.d.ts +29 -0
  8. package/dist/core/InFlightSyncOpMarker.d.ts.map +1 -0
  9. package/dist/core/InFlightSyncOpMarker.js +149 -0
  10. package/dist/core/InFlightSyncOpMarker.js.map +1 -0
  11. package/dist/core/PostUpdateMigrator.d.ts +16 -0
  12. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  13. package/dist/core/PostUpdateMigrator.js +56 -0
  14. package/dist/core/PostUpdateMigrator.js.map +1 -1
  15. package/dist/core/SessionManager.d.ts +146 -1
  16. package/dist/core/SessionManager.d.ts.map +1 -1
  17. package/dist/core/SessionManager.js +498 -144
  18. package/dist/core/SessionManager.js.map +1 -1
  19. package/dist/core/SleepWakeDetector.d.ts +33 -0
  20. package/dist/core/SleepWakeDetector.d.ts.map +1 -1
  21. package/dist/core/SleepWakeDetector.js +53 -0
  22. package/dist/core/SleepWakeDetector.js.map +1 -1
  23. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  24. package/dist/core/devGatedFeatures.js +23 -0
  25. package/dist/core/devGatedFeatures.js.map +1 -1
  26. package/dist/core/types.d.ts +52 -0
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/core/types.js.map +1 -1
  29. package/dist/lifeline/ServerSupervisor.d.ts +42 -0
  30. package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
  31. package/dist/lifeline/ServerSupervisor.js +79 -4
  32. package/dist/lifeline/ServerSupervisor.js.map +1 -1
  33. package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
  34. package/dist/lifeline/TelegramLifeline.js +8 -0
  35. package/dist/lifeline/TelegramLifeline.js.map +1 -1
  36. package/dist/monitoring/DegradedTmuxGuard.d.ts +161 -0
  37. package/dist/monitoring/DegradedTmuxGuard.d.ts.map +1 -0
  38. package/dist/monitoring/DegradedTmuxGuard.js +277 -0
  39. package/dist/monitoring/DegradedTmuxGuard.js.map +1 -0
  40. package/dist/monitoring/guardManifest.d.ts.map +1 -1
  41. package/dist/monitoring/guardManifest.js +18 -0
  42. package/dist/monitoring/guardManifest.js.map +1 -1
  43. package/dist/server/routes.d.ts.map +1 -1
  44. package/dist/server/routes.js +13 -5
  45. package/dist/server/routes.js.map +1 -1
  46. package/package.json +2 -2
  47. package/scripts/lint-no-direct-destructive.js +14 -0
  48. package/scripts/lint-sync-subprocess-chokepoint.js +208 -0
  49. package/scripts/sync-subprocess-chokepoint-baseline.json +148 -0
  50. package/src/data/builtin-manifest.json +65 -65
  51. package/upgrades/1.3.643.md +66 -0
  52. package/upgrades/side-effects/tmux-event-loop-resilience.md +86 -0
@@ -0,0 +1,86 @@
1
+ # Side-Effects Review — tmux Event-Loop Resilience (Increment 1)
2
+
3
+ **Slug:** `tmux-event-loop-resilience` · **Tier:** 2 (converged + approved spec
4
+ `docs/specs/tmux-event-loop-resilience.md`). Touches `PostUpdateMigrator` (a
5
+ config-strip migration), so the tier signal flags `belowFloor` — accepted: the
6
+ PostUpdateMigrator touch is a dev-gate cleanup strip (removes a stale persisted
7
+ `enabled:false` so the dev-gate resolves live-on-dev), fully reversible, no
8
+ external surface.
9
+
10
+ ## Summary of the change
11
+
12
+ The server's frequent synchronous `tmux` calls blocked the single event loop; a
13
+ slow shared tmux server froze the loop ~15s, dropping the dashboard websocket and
14
+ getting misread as host sleep. Increment 1: (A) an async, timeout-bounded tmux
15
+ hot path with cache-served dashboard/session reads; (B) an in-flight-sync-op
16
+ marker as the block-vs-sleep discriminator (in-process for SleepWakeDetector,
17
+ cross-process via a mirror file for ServerSupervisor); (C) a signal-only
18
+ `DegradedTmuxGuard` that surfaces a persistently slow tmux without ever killing
19
+ it. All three are dev-gated: LIVE on a development agent, DARK on the fleet.
20
+
21
+ ## 1. Over-block / false signal
22
+
23
+ `DegradedTmuxGuard` is signal-only — it raises ONE deduped attention item and
24
+ never kills, restarts, or reaps anything, so a false degradation signal costs at
25
+ most one surfaced notice. It is load-gated (suppressed when per-core load is high
26
+ — that is expected slowness, not a tmux fault) and requires N-cycle corroboration
27
+ (a single hiccup never raises an episode), with episode dedup + age-escalation.
28
+ The in-flight marker can only SUPPRESS a wake / DEFER a restart when affirmatively
29
+ present, in-flight, and non-stale — a false positive there fails toward the SAFE
30
+ direction (keep the session alive / let a genuinely-dead server restart).
31
+
32
+ ## 2. Under-block / missed signal
33
+
34
+ A real freeze the marker doesn't cover is still caught: SleepWakeDetector's
35
+ existing cpuBlockBusyRatio path (CPU-spin blocks) is unchanged, and the marker
36
+ adds the ~0-CPU I/O-wait case #1240 couldn't see. The marker self-heals via a
37
+ 2×timeout TTL so a leaked depth can never permanently blind sleep detection. The
38
+ supervisor defer is hard-capped (`starvationRestartThreshold`) so a stuck
39
+ in-flight marker can never wedge the restart path forever — it gives up loudly.
40
+
41
+ ## 3. Blast radius / fail-open
42
+
43
+ Every failure path fails toward SAFE and is non-silent (no-silent-fallbacks
44
+ ratchet enforced): a tmux call that times out maps to INDETERMINATE, never to
45
+ "absent" — `isSessionAliveAsync` returns `'indeterminate'` (never `false`) on a
46
+ timeout, so a slow tmux can NEVER cause a live session to be reaped (the
47
+ line-2352 regression the tri-state guards). The cross-process marker reader is
48
+ fail-OPEN: an absent/unparseable mirror ⇒ null ⇒ the supervisor proceeds to
49
+ restart a genuinely dead server. The mirror writer is best-effort: an unwritable
50
+ mirror never breaks a tmux call. `DegradedTmuxGuard` uses a fixed-capacity
51
+ modulo-write ring (Bounded Accumulation — 10,000-sample burst-invariant test
52
+ proves the ring length never exceeds windowSize), so it cannot grow memory under
53
+ a flood.
54
+
55
+ ## 4. Signal vs authority
56
+
57
+ The only blocking authority introduced is the supervisor restart-DEFER, and it is
58
+ bounded (hard cap + TTL + fail-open) and additive to the existing
59
+ `deferRestartForCpuStarvation` (the `||` keeps the CPU side-effect — verified by
60
+ test). The wake-handler amplifier guard short-circuits a marker-covered wake and
61
+ bounds the cascade's tmux re-validation (async 9000+SIGKILL); it never silences a
62
+ genuine recovery. `DegradedTmuxGuard` holds zero authority — it observes and
63
+ surfaces only.
64
+
65
+ ## 5. Interactions
66
+
67
+ Reuses the existing `'event-loop-block'` WakeSuppressionReason + StallEvent (no
68
+ new telemetry shape). The async hot-path twins coexist with the legacy sync
69
+ methods behind `tmuxAsyncEnabled` (off ⇒ byte-identical legacy behavior — the e2e
70
+ observable-equivalence test). `getCachedRunningSessions()` is the cache the
71
+ request routes (GET /status et al.) now read; the non-request consumers
72
+ (JobScheduler, WebSocketManager, AutoUpdater) intentionally keep the live read
73
+ (documented residual, Increment 2 territory). Per-agent socket isolation is
74
+ explicitly OUT of Increment 1 (Increment 2).
75
+
76
+ ## 6. Rollback
77
+
78
+ Each of the three flags is independently disable-able in `.instar/config.json`
79
+ (`monitoring.tmuxResilience.asyncHotPath.enabled`,
80
+ `monitoring.tmuxResilience.inFlightMarker.enabled`,
81
+ `monitoring.degradedTmuxGuard.enabled`) — set to `false` to revert that layer to
82
+ the pre-change behavior. The async hot path falls back to the sync path; the
83
+ marker branch goes inert; the guard stops observing. The migration strips only a
84
+ default-shaped persisted `false`, never an explicit operator `true`/`false`.
85
+ Config defaults OMIT `enabled` so the dev-gate (resolveDevAgentGate) governs:
86
+ fleet = dark, dev = live.