instar 1.3.180 → 1.3.182

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 (32) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +18 -22
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/SessionManager.d.ts +63 -3
  5. package/dist/core/SessionManager.d.ts.map +1 -1
  6. package/dist/core/SessionManager.js +90 -6
  7. package/dist/core/SessionManager.js.map +1 -1
  8. package/dist/core/StuckInputSentinel.d.ts.map +1 -1
  9. package/dist/core/StuckInputSentinel.js +35 -6
  10. package/dist/core/StuckInputSentinel.js.map +1 -1
  11. package/dist/core/TelegramRelay.d.ts +52 -0
  12. package/dist/core/TelegramRelay.d.ts.map +1 -0
  13. package/dist/core/TelegramRelay.js +80 -0
  14. package/dist/core/TelegramRelay.js.map +1 -0
  15. package/dist/feedback-factory/dryrun/dryRunCompare.d.ts +1 -0
  16. package/dist/feedback-factory/dryrun/dryRunCompare.d.ts.map +1 -1
  17. package/dist/feedback-factory/dryrun/dryRunCompare.js +1 -0
  18. package/dist/feedback-factory/dryrun/dryRunCompare.js.map +1 -1
  19. package/dist/feedback-factory/processor/parity.d.ts +16 -0
  20. package/dist/feedback-factory/processor/parity.d.ts.map +1 -1
  21. package/dist/feedback-factory/processor/parity.js +6 -0
  22. package/dist/feedback-factory/processor/parity.js.map +1 -1
  23. package/dist/server/routes.d.ts.map +1 -1
  24. package/dist/server/routes.js +7 -2
  25. package/dist/server/routes.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/data/builtin-manifest.json +47 -47
  28. package/upgrades/1.3.180.md +58 -45
  29. package/upgrades/1.3.181.md +45 -0
  30. package/upgrades/1.3.182.md +59 -0
  31. package/upgrades/side-effects/codex-stranded-draft-recovery.md +90 -0
  32. package/upgrades/side-effects/telegram-relay-timeout-observability.md +37 -0
@@ -0,0 +1,90 @@
1
+ # Side-Effects Review — Codex stranded-draft recovery
2
+
3
+ **Version / slug:** `codex-stranded-draft-recovery`
4
+ **Date:** `2026-05-31`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ Make the stuck-input recovery path codex-aware so an inbound message delivered to a
11
+ BUSY codex session is no longer silently stranded as an unsubmitted draft. Three
12
+ pieces: (1) `isMarkerStuckAtPrompt` now recognizes codex's `›` prompt char in
13
+ addition to Claude's `❯`; (2) a new in-memory `strandedDraftMarkers` map on
14
+ `SessionManager` records the injected-message marker for codex injections, with a
15
+ shared static `extractInjectionMarker`; (3) `StuckInputSentinel` gains a codex pass
16
+ that uses MARKER-based detection (immune to codex's dim empty-prompt placeholder) and
17
+ fires the existing escalating Enter recovery once codex goes idle. Claude paths are
18
+ untouched.
19
+
20
+ ## Decision-point inventory
21
+
22
+ - **`StuckInputSentinel.evaluateSession` — codex vs Claude detection branch.** Both
23
+ sides covered by tests: codex-with-marker → marker-based; everything else →
24
+ existing `extractPromptText`.
25
+ - **`isMarkerStuckAtPrompt` — prompt-char match (`❯` OR `›`).** Both chars tested,
26
+ plus the negative (marker absent) and the placeholder-immunity case.
27
+ - **`rawInject` — record marker only when `framework === 'codex-cli'`.** The
28
+ non-codex branch records nothing (Claude behavior byte-identical).
29
+
30
+ ## 1. Over-block
31
+
32
+ **What legitimate inputs does this change reject?** None. The change adds no gate and
33
+ rejects no input. It only *adds* a recovery action (an Enter keypress) for codex
34
+ sessions that were previously never recovered. The recovery is bounded (≤4 attempts)
35
+ and only fires when the pane is idle (no active-work footer) and the injected marker
36
+ is still visibly stuck at the `›` prompt.
37
+
38
+ ## 2. Under-block
39
+
40
+ **What does this still miss?** The marker map is in-memory, so a codex message
41
+ injected and stranded immediately before a server restart (with no subsequent
42
+ message) loses its marker and is not recovered — a strictly rarer compound case than
43
+ the observed bug (no restart occurred). Documented in the spec as a follow-up
44
+ (durable marker store). Also unchanged: the verifyInjection in-process fast path is
45
+ still bounded to 6.5 s; codex busy-long recovery deliberately relies on the
46
+ persistent sentinel, not verifyInjection.
47
+
48
+ ## 3. Level-of-abstraction fit
49
+
50
+ **Right layer?** Yes. Prompt-char knowledge lives in `isMarkerStuckAtPrompt` (the one
51
+ shared marker matcher already used by both verifyInjection and the sentinel). The
52
+ marker map lives on `SessionManager` next to `rawInject`/`verifyInjection` (the single
53
+ injection chokepoint). The codex recovery decision lives in `StuckInputSentinel`,
54
+ which already owns persistent stuck-prompt recovery. No new module, no new process.
55
+
56
+ ## 4. Signal vs authority compliance
57
+
58
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
59
+
60
+ No blocking authority added. The sentinel is a recovery *signal* with the smallest
61
+ possible action surface — a single bounded Enter keypress, exactly as for Claude. It
62
+ gates nothing, blocks no message, and a false-positive Enter against an empty prompt
63
+ is a harmless no-op (the pre-existing design invariant). The marker recording in
64
+ `rawInject` is best-effort and never throws (no-ops on a too-short marker).
65
+
66
+ ## 5. Interactions
67
+
68
+ - **`pendingInjections` (response-verification map):** deliberately NOT reused. That
69
+ map clears on first session output, which for a busy codex session happens while
70
+ the draft is still stranded. The new `strandedDraftMarkers` map clears only when the
71
+ marker leaves the prompt, so the two lifecycles stay independent and correct.
72
+ - **`verifyInjection`:** now also clears the stranded-draft marker on confirmed
73
+ submit, and benefits from the `›`-aware matcher for the idle-fast codex case.
74
+ - **`isPaneActivelyWorking` / `CLAUDE_WORKING_INDICATORS`:** reused unchanged — codex
75
+ shares the `esc to interrupt` footer hint, so the working-skip is correct for codex.
76
+ - **GC:** the sentinel clears markers for sessions no longer running and on
77
+ `tmuxSessionExists` false; a newer injection supersedes an older marker.
78
+ - No interaction with the SessionReaper, CompactionSentinel, RateLimitSentinel, or any
79
+ gate. Idempotent across ticks.
80
+
81
+ ## 6. External surfaces
82
+
83
+ No new HTTP routes, no config keys, no Telegram, no new on-disk files. The only
84
+ observable external surface is one additional row in the existing
85
+ `stuck-input-events.jsonl` audit log when a codex draft is recovered (same format and
86
+ log as the Claude path already uses). No migration required — the change is pure
87
+ in-process recovery logic that ships with the server binary and is live on restart;
88
+ no agent-installed file (`.claude/settings.json`, `.instar/config.json`, CLAUDE.md
89
+ template, hook script, skill) is touched, so the Migration Parity Standard does not
90
+ apply.
@@ -0,0 +1,37 @@
1
+ # Side effects — tokenless-standby relay timeout + observability
2
+
3
+ ## What changes at runtime
4
+
5
+ The tokenless-standby outbound Telegram relay (`outboundRelay`, used only when a
6
+ pool standby serves a moved session) now (a) aborts after a bounded timeout
7
+ instead of hanging, and (b) logs one explanatory line on every failure path.
8
+ Logic extracted into `src/core/TelegramRelay.ts`; success behavior unchanged.
9
+
10
+ ## Who is affected
11
+
12
+ - **Single-machine agents:** zero behavior change. `outboundRelay` is only wired
13
+ in the multi-machine session-pool branch and is only invoked by `sendToTopic`
14
+ when the adapter has no usable bot token (a standby). A single-machine agent
15
+ never relays.
16
+ - **Multi-machine standbys (a moved session replying):** a relay to an
17
+ unreachable/slow holder now fails after `relayTimeoutMs` (default 15s) instead
18
+ of hanging indefinitely, and the failure is logged with its cause.
19
+
20
+ ## Blast radius
21
+
22
+ - New file `src/core/TelegramRelay.ts` + a wiring change in `src/commands/server.ts`
23
+ (the `outboundRelay` assignment) + one import. No route, schema, config-key, or
24
+ migration change. New optional config `multiMachine.relayTimeoutMs` (absent →
25
+ 15s default).
26
+ - Compiled source only — no agent-installed file/hook/skill, so no
27
+ PostUpdateMigrator change; agents get it on the normal server update.
28
+
29
+ ## Failure modes considered
30
+
31
+ - **Timeout too aggressive:** default 15s is generous for a tunnel round-trip;
32
+ tunable up via config if a deployment needs it. On timeout the reply fails
33
+ (logged) rather than hangs — strictly better than the prior unbounded hang.
34
+ - **Log noise:** one line per failed relay only (success is silent), so a
35
+ healthy multi-machine setup adds no log volume.
36
+ - **Behavior parity:** the success path (POST holder, return messageId, pass
37
+ `silent` through) is byte-equivalent to the original; covered by a 2xx test.