instar 1.3.375 → 1.3.377

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.
@@ -0,0 +1,58 @@
1
+ # Side-Effects Review — SessionMonitor ctx-notified ledger persistence
2
+
3
+ **Version / slug:** `sessionmonitor-ctx-ledger-persistence`
4
+ **Date:** `2026-06-06`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (SMALL, single-component, both-sides tested)`
7
+
8
+ ## Summary of the change
9
+
10
+ The once-per-death-episode dedup map in SessionMonitor (`ctxNotifiedSessions`,
11
+ added by #914) was in-memory only — every server restart re-announced already-
12
+ announced dead sessions, once per boot (2026-06-06 residual, topics 16566 +
13
+ 19437; operator pick 1Y approved persisting it). The map is now persisted to
14
+ `state/session-monitor-ctx-notified.json` (atomic tmp+rename), loaded at
15
+ construction with a 7-day prune, and updated on both mutation sites (notify →
16
+ set, successful recovery → delete).
17
+
18
+ ## Decision-point inventory
19
+
20
+ - Load: missing file → empty; corrupt file → warn + empty (never throws);
21
+ entry older than 7 days or malformed → dropped. All arms tested.
22
+ - Persist: write failure → one-time warn, monitoring continues (degrades to
23
+ pre-persistence behavior). statePath absent → feature inert (tested).
24
+
25
+ ## 1. Over-block
26
+
27
+ A persisted episode could suppress a notice the user wanted if the SAME
28
+ topic+sessionName genuinely dies twice without an intervening recovery or
29
+ respawn — but the same was already true in-memory within one server lifetime;
30
+ persistence only extends the existing semantics across boots. The 7-day prune
31
+ bounds the suppression horizon.
32
+
33
+ ## 2. Under-block / residual risk
34
+
35
+ - A respawn that reuses the SAME tmux session name after a fresh death still
36
+ notifies (sessionName equality is the episode key — unchanged semantics).
37
+ - Multi-machine: the ledger is machine-local (registered as such); a topic
38
+ transferred to another machine starts a fresh episode there. Acceptable —
39
+ the post-transfer closeout kills the old session anyway.
40
+
41
+ ## 3. Level-of-abstraction fit
42
+
43
+ Persistence lives inside SessionMonitor next to the map it persists; the path
44
+ is injected via deps (testable, inert when absent); wiring at the single
45
+ construction site in server.ts; the new state file is declared in
46
+ `src/data/state-coherence-registry.json` (machine-local / single-writer / none)
47
+ so the state-registry lint passes at birth.
48
+
49
+ ## Rollback
50
+
51
+ Revert the PR; the orphaned state file is inert (nothing reads it) and ≤ a few
52
+ hundred bytes.
53
+
54
+ ## Blast radius
55
+
56
+ Server-side only; no agent-installed files, no hooks, no config defaults, no
57
+ template changes → no Migration Parity obligations. New state file is created
58
+ lazily on first notify.