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.
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +18 -22
- package/dist/commands/server.js.map +1 -1
- package/dist/core/SessionManager.d.ts +63 -3
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +90 -6
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/StuckInputSentinel.d.ts.map +1 -1
- package/dist/core/StuckInputSentinel.js +35 -6
- package/dist/core/StuckInputSentinel.js.map +1 -1
- package/dist/core/TelegramRelay.d.ts +52 -0
- package/dist/core/TelegramRelay.d.ts.map +1 -0
- package/dist/core/TelegramRelay.js +80 -0
- package/dist/core/TelegramRelay.js.map +1 -0
- package/dist/feedback-factory/dryrun/dryRunCompare.d.ts +1 -0
- package/dist/feedback-factory/dryrun/dryRunCompare.d.ts.map +1 -1
- package/dist/feedback-factory/dryrun/dryRunCompare.js +1 -0
- package/dist/feedback-factory/dryrun/dryRunCompare.js.map +1 -1
- package/dist/feedback-factory/processor/parity.d.ts +16 -0
- package/dist/feedback-factory/processor/parity.d.ts.map +1 -1
- package/dist/feedback-factory/processor/parity.js +6 -0
- package/dist/feedback-factory/processor/parity.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +7 -2
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.180.md +58 -45
- package/upgrades/1.3.181.md +45 -0
- package/upgrades/1.3.182.md +59 -0
- package/upgrades/side-effects/codex-stranded-draft-recovery.md +90 -0
- 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.
|