instar 1.3.207 → 1.3.209

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 (54) hide show
  1. package/dist/commands/init.js +4 -0
  2. package/dist/commands/init.js.map +1 -1
  3. package/dist/commands/server.d.ts.map +1 -1
  4. package/dist/commands/server.js +48 -0
  5. package/dist/commands/server.js.map +1 -1
  6. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  7. package/dist/config/ConfigDefaults.js +13 -0
  8. package/dist/config/ConfigDefaults.js.map +1 -1
  9. package/dist/core/PostUpdateMigrator.d.ts +23 -1
  10. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  11. package/dist/core/PostUpdateMigrator.js +138 -0
  12. package/dist/core/PostUpdateMigrator.js.map +1 -1
  13. package/dist/core/SessionManager.d.ts.map +1 -1
  14. package/dist/core/SessionManager.js +7 -3
  15. package/dist/core/SessionManager.js.map +1 -1
  16. package/dist/core/frameworkSessionLaunch.d.ts.map +1 -1
  17. package/dist/core/frameworkSessionLaunch.js +15 -0
  18. package/dist/core/frameworkSessionLaunch.js.map +1 -1
  19. package/dist/core/types.d.ts +10 -0
  20. package/dist/core/types.d.ts.map +1 -1
  21. package/dist/core/types.js.map +1 -1
  22. package/dist/monitoring/sentinelWiring.d.ts +13 -0
  23. package/dist/monitoring/sentinelWiring.d.ts.map +1 -1
  24. package/dist/monitoring/sentinelWiring.js +44 -1
  25. package/dist/monitoring/sentinelWiring.js.map +1 -1
  26. package/dist/scaffold/templates.d.ts.map +1 -1
  27. package/dist/scaffold/templates.js +6 -0
  28. package/dist/scaffold/templates.js.map +1 -1
  29. package/dist/server/routes.d.ts.map +1 -1
  30. package/dist/server/routes.js +76 -0
  31. package/dist/server/routes.js.map +1 -1
  32. package/dist/threadline/A2ACheckInPolicy.d.ts +50 -0
  33. package/dist/threadline/A2ACheckInPolicy.d.ts.map +1 -0
  34. package/dist/threadline/A2ACheckInPolicy.js +51 -0
  35. package/dist/threadline/A2ACheckInPolicy.js.map +1 -0
  36. package/dist/threadline/A2ACheckInProxy.d.ts +56 -0
  37. package/dist/threadline/A2ACheckInProxy.d.ts.map +1 -0
  38. package/dist/threadline/A2ACheckInProxy.js +53 -0
  39. package/dist/threadline/A2ACheckInProxy.js.map +1 -0
  40. package/dist/threadline/A2ACheckInScheduler.d.ts +77 -0
  41. package/dist/threadline/A2ACheckInScheduler.d.ts.map +1 -0
  42. package/dist/threadline/A2ACheckInScheduler.js +90 -0
  43. package/dist/threadline/A2ACheckInScheduler.js.map +1 -0
  44. package/dist/threadline/A2ACheckInSummarizer.d.ts +48 -0
  45. package/dist/threadline/A2ACheckInSummarizer.d.ts.map +1 -0
  46. package/dist/threadline/A2ACheckInSummarizer.js +64 -0
  47. package/dist/threadline/A2ACheckInSummarizer.js.map +1 -0
  48. package/package.json +1 -1
  49. package/src/data/builtin-manifest.json +64 -64
  50. package/src/scaffold/templates.ts +6 -0
  51. package/upgrades/1.3.208.md +54 -0
  52. package/upgrades/1.3.209.md +66 -0
  53. package/upgrades/side-effects/iris-audit-session-lifecycle.md +146 -0
  54. package/upgrades/side-effects/spinner-immune-liveness.md +122 -0
@@ -0,0 +1,66 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Three connected session-lifecycle fixes, all surfaced by a token-efficiency audit
9
+ on a deployed agent:
10
+
11
+ 1. **The Claude session builder now honors the configured default model.**
12
+ `claudeCodeBuilder` resolved `frameworkDefaultModels['claude-code']` but never
13
+ passed `--model` to the `claude` CLI — unlike the Codex and Gemini builders,
14
+ which both do. So a configured default model was silently dropped for every
15
+ interactive Claude session; they always ran the CLI's account default. The
16
+ builder now pins `--model <resolved>` when a default is set (tier aliases
17
+ `fast|balanced|capable` → `haiku|sonnet|opus`; raw model ids pass through), and
18
+ pushes nothing when unset so the account default is preserved. This matches the
19
+ documented contract on `InteractiveLaunchOptions.defaultModel`.
20
+
21
+ 2. **`GET /sessions` now reports the real launched model for interactive sessions.**
22
+ The session record stores the model the session was *actually* launched with
23
+ (post Codex rate-limit swap), so after a config change you can confirm which
24
+ model a running session picked up.
25
+
26
+ 3. **New `POST /sessions/restart-all` bulk-restart endpoint.** A running session
27
+ keeps the config it was spawned with — and Claude Code loads hooks/settings only
28
+ at session start, so a newly-added hook never engages on a live session. There
29
+ was no way to push every session onto new config short of waiting for the reaper
30
+ or refreshing each by hand. `POST /sessions/restart-all` refreshes every running,
31
+ Telegram-bound session through the existing `SessionRefresh` path (kill +
32
+ `claude --resume`, each conversation preserved), staggered to avoid a respawn
33
+ storm. Pass `{"excludeSession":"<tmux-name>"}` to keep the caller alive;
34
+ non-Telegram-bound sessions are skipped and reported in `skipped`.
35
+
36
+ ## What to Tell Your User
37
+
38
+ - **Your configured default model now actually applies to Claude sessions.** "If
39
+ you set a default model, my Claude sessions will launch with it now — previously
40
+ that setting was quietly ignored for Claude and only worked for Codex/Gemini."
41
+ - **One command to apply a config or hook change to everything running.** "After
42
+ you change my default model, disable a feature, or add a hook, I don't pick it up
43
+ on a session that's already running — Claude only loads settings when a session
44
+ starts. I can now restart all my live sessions in one go (each conversation is
45
+ preserved) so the new config takes effect, then confirm what each one is running."
46
+
47
+ ## Summary of New Capabilities
48
+
49
+ | Capability | How to Use |
50
+ |-----------|-----------|
51
+ | Configured default model applies to Claude sessions | Automatic (set `frameworkDefaultModels['claude-code']`) |
52
+ | Per-session launched model in `GET /sessions` | `GET /sessions` → each session's `model` field |
53
+ | Bulk restart all running sessions onto new config | `POST /sessions/restart-all` (one session: `POST /sessions/refresh`) |
54
+
55
+ ## Evidence
56
+
57
+ - **Root cause (model):** `src/core/frameworkSessionLaunch.ts` `claudeCodeBuilder`
58
+ built `[binary, --dangerously-skip-permissions, (--resume id)]` with no `--model`,
59
+ while `codexCliBuilder`/`geminiBuilder` both push `--model`. Unit-proven in
60
+ `tests/unit/frameworkSessionLaunch.test.ts` (now asserts `--model` present when a
61
+ default is set, absent when unset, tier→model and raw-id pass-through).
62
+ - **`restart-all`:** `tests/unit/sessions-restart-all-route.test.ts` drives the real
63
+ Express route — validation, 202 ack with honest `scheduled`/`skipped`, exclusion,
64
+ and that each target is refreshed through `SessionRefresh` after the stagger.
65
+ - **Migration parity:** `tests/unit/PostUpdateMigrator-applyConfigToRunningSessions.test.ts`
66
+ proves existing agents get the awareness section on update (idempotent).
@@ -0,0 +1,146 @@
1
+ # Side-Effects Review — Iris-audit session lifecycle (PR A: items 2/3/4)
2
+
3
+ **Version / slug:** `iris-audit-session-lifecycle`
4
+ **Date:** `2026-06-02`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `3 independent spec reviewers (convergence round) — concur`
7
+
8
+ ## Summary of the change
9
+
10
+ PR A of the Iris-audit spec (`docs/specs/iris-audit-session-observability.md`),
11
+ covering items 2/3/4. Three changes: (a) `claudeCodeBuilder` now pushes `--model
12
+ <resolved>` when `frameworkDefaultModels['claude-code']` is set (it was silently
13
+ dropped before — only Codex/Gemini builders passed it), and the interactive `Session`
14
+ record stores the model actually launched with; (b) a new `POST /sessions/restart-all`
15
+ route that bulk-refreshes every running Telegram-bound session through the existing
16
+ `SessionRefresh` path (staggered, conversation-preserving); (c) a CLAUDE.md template
17
+ section + idempotent `migrateClaudeMd` backfill teaching that hooks/config load at
18
+ session start so applying a change requires a restart. Files: `src/core/
19
+ frameworkSessionLaunch.ts`, `src/core/SessionManager.ts`, `src/server/routes.ts`,
20
+ `src/scaffold/templates.ts`, `src/core/PostUpdateMigrator.ts`, plus tests and an
21
+ upgrade fragment. Decision points touched: the interactive launch-arg builder
22
+ (launch-shape, no block surface), the new restart-all action endpoint (real blast
23
+ radius — reuses the existing rate-guarded `SessionRefresh` authority), and an
24
+ additive idempotent doc migration.
25
+
26
+ ## Decision-point inventory
27
+
28
+ - `claudeCodeBuilder` argv (frameworkSessionLaunch.ts) — **modify** — adds `--model`
29
+ when a default is set; pass-through otherwise. No block/allow surface.
30
+ - `POST /sessions/restart-all` (routes.ts) — **add** — new action endpoint; delegates
31
+ to the existing `SessionRefresh` (does not add a new blocking authority).
32
+ - interactive `Session.model` recording (SessionManager.ts) — **modify** — stores the
33
+ effective launched model; observational, no decision logic.
34
+ - `migrateClaudeMd` awareness section (PostUpdateMigrator.ts) — **add** — additive,
35
+ idempotent, content-sniffed text backfill; no decision logic.
36
+
37
+ ## 1. Over-block
38
+
39
+ No block/allow surface — over-block not applicable. The only gating is the existing
40
+ `SessionRefresh` rate-guard (5/10min per session), reused unchanged; restart-all does
41
+ not add or alter any allow/deny logic. The Telegram-bound filter is an inclusion
42
+ filter (which sessions are eligible), not a rejection of legitimate input.
43
+
44
+ ## 2. Under-block
45
+
46
+ No block/allow surface — under-block not applicable. restart-all intentionally skips
47
+ non-Telegram-bound sessions (Slack/iMessage/headless) — reported transparently in the
48
+ `skipped` count, not silently dropped.
49
+
50
+ ## 3. Level-of-abstraction fit
51
+
52
+ restart-all sits at the right layer: it is a thin HTTP route that orchestrates the
53
+ existing, fully-tested `SessionRefresh` orchestrator (which owns kill+respawn,
54
+ rate-guarding, in-flight protection, and topic resolution). It does NOT re-implement
55
+ any of that — it loops the existing primitive with a stagger. The model-launch change
56
+ is at the builder layer where every other framework already applies `--model`. The
57
+ awareness change is documentation, delivered via the established `migrateClaudeMd`
58
+ mechanism. Nothing is at the wrong layer; no parallel re-implementation of an existing
59
+ primitive.
60
+
61
+ ## 4. Signal vs authority compliance
62
+
63
+ **Required reference:** docs/signal-vs-authority.md
64
+
65
+ - [x] No — this change has no block/allow surface (restart-all reuses the existing
66
+ `SessionRefresh` authority; the model record and the awareness section are signals/
67
+ documentation).
68
+
69
+ The model field on `GET /sessions` is a pure signal (observability). restart-all
70
+ carries the authority to kill+respawn, but that authority already exists in
71
+ `SessionRefresh` (used by `/sessions/refresh`); this change does not create a new
72
+ brittle authority — it reuses the smart, rate-guarded one. No brittle detector owns
73
+ blocking authority here.
74
+
75
+ ## 5. Interactions
76
+
77
+ - **Shadowing:** restart-all runs N independent single-refreshes; it neither shadows
78
+ nor is shadowed by other `/sessions/*` routes (it only reads the session list and
79
+ calls `SessionRefresh`).
80
+ - **Double-fire:** the in-flight guard inside `SessionRefresh` prevents a second
81
+ refresh of the same session firing before the first completes, so restart-all can't
82
+ double-restart a session even if called twice.
83
+ - **Races:** the target set is snapshot-time; a session spawned after the snapshot is
84
+ untouched (documented). The reaper interaction is NOT new — restart-all reuses the
85
+ exact shipped `/sessions/refresh` path; a freshly respawned session has current
86
+ activity (not idle-reapable) and the old session is marked `killed`.
87
+ - **Feedback loops:** none. restart-all is a one-shot operation; it does not feed a
88
+ system that re-triggers it.
89
+
90
+ ## 6. External surfaces
91
+
92
+ - **Other agents on the machine:** none — restart-all only acts on THIS agent's own
93
+ sessions (its own `state`/`SessionRefresh`).
94
+ - **Install base:** items 2 and 4 reach the fleet via update. Item 2 makes a
95
+ previously-inert config (`frameworkDefaultModels['claude-code']`) active — effect
96
+ appears only on a fresh session, only when the field is set, and is auditable via
97
+ `GET /sessions` (documented "activation safety"). Item 4 appends an idempotent
98
+ CLAUDE.md section.
99
+ - **External systems:** Telegram only insofar as restarted sessions resume their
100
+ Telegram-bound conversations via `claude --resume` — same as the existing single
101
+ refresh.
102
+ - **Persistent state:** the `Session` record now carries `model` for interactive
103
+ sessions (additive field); no schema migration needed (optional field already on the
104
+ `Session` type). The CLAUDE.md migration appends text idempotently.
105
+ - **Timing:** the restart-all stagger (500 + i·750 ms) spreads respawns; no fleet-wide
106
+ concurrency ceiling in v1 (per-session rate-guard is the aggregate backstop; named
107
+ as a known bound in the spec).
108
+
109
+ ## 7. Rollback cost
110
+
111
+ - **Hot-fix release:** pure code revert shipped as the next patch.
112
+ - **Data migration:** none — `Session.model` is an optional field already in the type;
113
+ reverting just stops populating it for interactive sessions.
114
+ - **Agent state repair:** none. The CLAUDE.md migration is idempotent and additive;
115
+ reverting the migrator leaves already-patched CLAUDE.md files harmlessly carrying the
116
+ section (no removal needed).
117
+ - **User visibility:** no user-visible regression during the rollback window. Item 2's
118
+ effect only manifests on a fresh session; reverting simply returns Claude sessions to
119
+ the CLI account default.
120
+
121
+ ## Conclusion
122
+
123
+ The review produced no design changes to PR A's code — the changes are additive and
124
+ reuse existing authorities. The convergence round refined the SPEC's documentation
125
+ (snapshot semantics, fleet bound, reaper-reuse, activation safety, idempotency
126
+ pattern). Clear to ship. Item 1 (token accounting) ships as the sibling PR B against
127
+ the same spec.
128
+
129
+ ## Second-pass review (if required)
130
+
131
+ **Reviewer:** 3 independent spec reviewers (design-correctness, safety/blast-radius,
132
+ completeness/standards-fit)
133
+ **Independent read of the artifact: concur**
134
+
135
+ All three reviewers' material findings were resolved in-spec; the two "item 1 not
136
+ implemented" criticals were a misunderstanding of the intended PR A / PR B phasing
137
+ (item 1 is PR B, tracked via `deferrals-tracked`). No structural redesign. See
138
+ `docs/specs/reports/iris-audit-session-observability-convergence.md`.
139
+
140
+ ## Evidence pointers
141
+
142
+ - `tests/unit/frameworkSessionLaunch.test.ts` — `--model` set/unset/tier/raw/with-resume.
143
+ - `tests/unit/sessions-restart-all-route.test.ts` — real Express route behavior.
144
+ - `tests/unit/PostUpdateMigrator-applyConfigToRunningSessions.test.ts` — migration idempotency.
145
+ - `tests/unit/feature-delivery-completeness.test.ts` — template↔migrator parity (green).
146
+ - `tsc --noEmit` clean; `pnpm build` clean.
@@ -0,0 +1,122 @@
1
+ # Side-Effects Review — spinner-immune liveness signal
2
+
3
+ **Version / slug:** `spinner-immune-liveness`
4
+ **Date:** `2026-06-02`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `instar-codey (codex) — cross-model review completed; verdict incorporated`
7
+
8
+ ## Summary of the change
9
+
10
+ `src/monitoring/sentinelWiring.ts`: `OutputActivityTracker.snapshot()` now hashes
11
+ `stripVolatileStatus(output, framework)` instead of the raw pane. `stripVolatileStatus`
12
+ strips the host's animated working-status region (Braille spinner glyphs, the
13
+ `Nm Ns` / `(Ns` elapsed timers, token/context counters, and the `esc to interrupt`
14
+ footer line) so only real scrollback changes refresh `lastChangeAt`. Fixes the
15
+ silence sentinel being permanently blinded by the spinner's ticking clock.
16
+
17
+ ## Decision-point inventory
18
+
19
+ - `OutputActivityTracker: did this frame change?` (sentinelWiring.ts:~215) — **modify**
20
+ — the hashed input is now spinner-normalized. The downstream "observed-change
21
+ requirement" + `looksActivelyWorking` + silence-threshold logic are unchanged.
22
+
23
+ ---
24
+
25
+ ## 1. Over-block
26
+
27
+ **No block/allow surface — over-block not applicable.** The change cannot reject or
28
+ block anything. The only effect is that the silence sentinel correctly recognizes a
29
+ stalled-but-spinning turn as idle (rather than perpetually "active") and may issue
30
+ its existing non-destructive `Enter` nudge.
31
+
32
+ ---
33
+
34
+ ## 2. Under-block
35
+
36
+ **What does it still miss?** It strips a conservative, anchored set of volatile
37
+ tokens; an exotic future spinner format could still leak a changing token into the
38
+ hash (degrading gracefully back to the old "always active" behavior for that host —
39
+ no worse than today). It does not change the silence THRESHOLD; a true stall is
40
+ detected at the existing ~16-min mark.
41
+
42
+ ---
43
+
44
+ ## 3. Level-of-abstraction fit
45
+
46
+ Correct layer — a normalization at the change-detector's input boundary, reusing the
47
+ existing per-framework `getActivitySignal` patterns rather than inventing new ones.
48
+ It feeds the existing smart silence sentinel; it does not add a parallel detector or
49
+ hold any authority.
50
+
51
+ ---
52
+
53
+ ## 4. Signal vs authority compliance
54
+
55
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
56
+
57
+ - [x] No — this change produces a signal (a fresher/stale activity timestamp)
58
+ consumed by the existing `ActiveWorkSilenceSentinel`, which owns the (non-destructive)
59
+ recovery decision.
60
+
61
+ The cross-model review (Codey) specifically affirmed the signal-vs-authority shape:
62
+ absence-of-activity must NOT authorize destructive recovery; here it only authorizes a
63
+ non-destructive `Enter` nudge, and the destructive Ctrl-C path (SocketDisconnectSentinel)
64
+ remains gated on a POSITIVE error-string marker. No change weakens that.
65
+
66
+ ---
67
+
68
+ ## 5. Interactions
69
+
70
+ - **Shadowing:** none — same single hash site; downstream logic unchanged.
71
+ - **Double-fire:** none — `SocketDisconnectSentinel` (error-string → Ctrl-C) and
72
+ `ActiveWorkSilenceSentinel` (silence → Enter) remain independent; this only un-blinds
73
+ the latter.
74
+ - **Races:** none — pure synchronous string transform inside the existing snapshot tick.
75
+ - **Feedback loops:** the Enter nudge could, on a genuinely-long generation, submit a
76
+ stray blank line; the pane is mid-turn (spinner present) so it is queued/ignored, not
77
+ destructive. Verified the nudge is `sendKey(session, 'Enter')` (sentinelWiring.ts:255),
78
+ not Ctrl-C.
79
+
80
+ ---
81
+
82
+ ## 6. External surfaces
83
+
84
+ - Persistent state: none.
85
+ - External systems: none.
86
+ - Behavior visible to operators: a stalled-but-spinning session now appears in
87
+ `logs/sentinel-events.jsonl` as detected/nudged where before it was invisible. The
88
+ Telegram escalation default (off) is unchanged.
89
+ - Runtime: one extra string transform per session per silence tick — negligible.
90
+
91
+ ---
92
+
93
+ ## 7. Rollback cost
94
+
95
+ Pure code change — revert `stripVolatileStatus` + restore `cheapHash(output)`, ship a
96
+ patch. No persistent state, no migration, no user-visible regression (it would simply
97
+ return to the prior "spinner fools the detector" behavior).
98
+
99
+ ---
100
+
101
+ ## Conclusion
102
+
103
+ The cross-model review materially improved this change: it began as a multi-state
104
+ process-activity gate to protect long generations from a *destructive* Ctrl-C, but the
105
+ reviewer's grounded catch — the silence nudge is `Enter`-only, not Ctrl-C — collapsed it
106
+ to a single safe normalization, with the destructive path already correctly gated on a
107
+ positive error marker elsewhere. Clear to ship as a Tier-1 monitoring reliability fix.
108
+
109
+ ## Second-pass review (if required)
110
+
111
+ **Reviewer:** instar-codey (codex)
112
+ **Independent read: concur (after the implementation correction).** The reviewer's
113
+ verdict drove the final design: do not let absence-of-activity authorize destructive
114
+ recovery (already satisfied — the silence path is non-destructive `Enter`; Ctrl-C stays
115
+ behind the SocketDisconnectSentinel error marker). No residual concern on the shipped
116
+ shape.
117
+
118
+ ## Evidence pointers
119
+
120
+ - `tests/unit/spinner-immune-liveness.test.ts` — 7 tests (normalizer + tracker behavior).
121
+ - `src/monitoring/sentinelWiring.ts:255` — nudge is `sendKey(session, 'Enter')`.
122
+ - Origin incident: `logs/server.log` + `logs/sentinel-events.jsonl`, 2026-06-02 26-min stall.