instar 1.3.124 → 1.3.126
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/providers/adapters/openai-codex/observability/sessionPaths.d.ts +26 -18
- package/dist/providers/adapters/openai-codex/observability/sessionPaths.d.ts.map +1 -1
- package/dist/providers/adapters/openai-codex/observability/sessionPaths.js +53 -32
- package/dist/providers/adapters/openai-codex/observability/sessionPaths.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +26 -21
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +46 -46
- package/upgrades/1.3.125.md +53 -0
- package/upgrades/1.3.126.md +53 -0
- package/upgrades/side-effects/codex-rollout-scan-perf-v2.md +55 -0
- package/upgrades/side-effects/relay-agent-accept-boundary.md +128 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Side-Effects Review — relay-agent accept-boundary (duplicate-reply root)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `relay-agent-accept-boundary`
|
|
4
|
+
**Date:** 2026-05-30
|
|
5
|
+
**Author:** Echo (instar-dev agent)
|
|
6
|
+
**Second-pass reviewer:** REQUIRED (inbound agent-to-agent messaging path) — verdict appended below
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
`POST /messages/relay-agent` (`src/server/routes.ts`) now responds at the accept
|
|
11
|
+
boundary — `{ ok:true, accepted:true, threadline:{accepted:true, async:true} }`
|
|
12
|
+
— instead of awaiting `handleInboundMessage` (a 9-30 s session spawn) before
|
|
13
|
+
responding. The spawn runs in the background (`void` + logged `.then`/`.catch`).
|
|
14
|
+
This removes the duplicate-reply ROOT: the co-located sender
|
|
15
|
+
(`MessageRouter.relay`) uses `AbortSignal.timeout(5000)` and reads only
|
|
16
|
+
`response.ok`, so awaiting the spawn past 5 s made it retry with a fresh id →
|
|
17
|
+
duplicate spawn. Scoped to the co-located path only; the relay-funnel path is
|
|
18
|
+
tracked separately.
|
|
19
|
+
|
|
20
|
+
## Decision-point inventory
|
|
21
|
+
|
|
22
|
+
- No decision is added or changed. The accept decision (`relay`) and the
|
|
23
|
+
warrants-reply gate already ran upstream and are unchanged. This only moves
|
|
24
|
+
WHEN the HTTP response is sent relative to the background spawn —
|
|
25
|
+
modify (pass-through of the decision, not a new decision).
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. Over-block
|
|
30
|
+
No block/allow surface added. The change responds *sooner*; it rejects nothing
|
|
31
|
+
it didn't reject before (auth, envelope-validation, dedup, and the
|
|
32
|
+
warrants-reply suppress path are all unchanged and still run before the
|
|
33
|
+
response).
|
|
34
|
+
|
|
35
|
+
## 2. Under-block
|
|
36
|
+
The warrants-reply gate's suppress→short-circuit is preserved and still runs
|
|
37
|
+
synchronously before the spawn, so a no-reply verdict still prevents the spawn.
|
|
38
|
+
The only thing no longer surfaced synchronously is the spawn OUTCOME
|
|
39
|
+
(spawned/handled/error) — which no caller reads (see §5/§6); it is logged.
|
|
40
|
+
|
|
41
|
+
## 3. Level-of-abstraction fit
|
|
42
|
+
Correct layer — the fix is at the HTTP handler that owns the request/response
|
|
43
|
+
lifecycle for this path. The decision of WHAT to do (accept, gate, spawn) is
|
|
44
|
+
unchanged; only the response timing within the handler moves.
|
|
45
|
+
|
|
46
|
+
## 4. Signal vs authority compliance
|
|
47
|
+
Compliant. No authority added. The handler already held the accept + gate
|
|
48
|
+
authority upstream; the change carries no new gate and fails safe (a background
|
|
49
|
+
error is logged, never surfaced as a 500 on an already-sent response).
|
|
50
|
+
|
|
51
|
+
## 5. Interactions
|
|
52
|
+
- **Sender (`MessageRouter.relay`, src/messaging/MessageRouter.ts:494-505):**
|
|
53
|
+
reads ONLY `response.ok` within a 5 s `AbortSignal.timeout` — verified. The
|
|
54
|
+
accept-boundary gives it a fast `ok` and never the spawn fields it never
|
|
55
|
+
read.
|
|
56
|
+
- **Reply-waiter mechanism:** resolved synchronously BEFORE the response
|
|
57
|
+
(unchanged) — the actual reply path is decoupled from this response. Tests
|
|
58
|
+
for waiter-by-threadId stay green.
|
|
59
|
+
- **Content-hash dedup (#573):** runs before the response, unchanged; remains
|
|
60
|
+
the backstop for any retry that still slips through.
|
|
61
|
+
- **Keystone gate-before-spawn:** the warrants-reply gate still runs before the
|
|
62
|
+
(now async) spawn; the wiring test asserting that ordering stays green (made
|
|
63
|
+
formatting-robust).
|
|
64
|
+
- **No double-fire:** the spawn runs exactly once per accepted message, just
|
|
65
|
+
asynchronously.
|
|
66
|
+
|
|
67
|
+
## 6. External surfaces
|
|
68
|
+
- The `/messages/relay-agent` response body changes from `{ok, threadline:
|
|
69
|
+
<spawnResult>}` to `{ok, accepted, threadline:{accepted, async}}`. Audited
|
|
70
|
+
consumers:
|
|
71
|
+
- `MessageRouter.relayToAgent` (`src/messaging/MessageRouter.ts:486-510`) —
|
|
72
|
+
reads ONLY `response.ok` within `AbortSignal.timeout(5000)`. Fully satisfied
|
|
73
|
+
by the fast `ok`; never read the spawn fields. No behavior change.
|
|
74
|
+
- **`/threadline/relay-send` local fast-path** (`src/server/routes.ts:13824-
|
|
75
|
+
13835`) — the SENDER side of this same co-located hop reads
|
|
76
|
+
`threadline.{injected,spawned,resumed,gateDecision,error,handled}` to build
|
|
77
|
+
an informational `deliveryOutcome` string (logged + returned to the calling
|
|
78
|
+
agent's `threadline_send` MCP result via `mcp-http-client` →
|
|
79
|
+
`ThreadlineMCPServer:575`). With the accept-boundary those fields are
|
|
80
|
+
`undefined`, so `outcome` falls through to the existing default `'accepted'`
|
|
81
|
+
(previously e.g. `'spawned new session'`/`'resumed existing thread'`). This
|
|
82
|
+
is a **cosmetic/observability degradation only**: `delivered` is computed as
|
|
83
|
+
`!outcome.startsWith('error')`, and `'accepted'` is not an error, so
|
|
84
|
+
`delivered` stays `true` exactly as before; `outcome` gates no retry, no
|
|
85
|
+
delivery, no reply-wait. `'accepted'` is also the HONEST value — the local
|
|
86
|
+
send IS accepted and processing async. (Found by the Phase-5 reviewer; the
|
|
87
|
+
original draft of this section wrongly claimed `MessageRouter.relay` was the
|
|
88
|
+
only consumer.)
|
|
89
|
+
- The change is invisible to the sender's actual behavior (fast ack) and to the
|
|
90
|
+
user (the real reply still arrives via the session, just without a 30 s sender
|
|
91
|
+
hang and without the occasional duplicate).
|
|
92
|
+
- No new route, no new message.
|
|
93
|
+
|
|
94
|
+
## 7. Rollback cost
|
|
95
|
+
Trivial — revert the one handler block (re-await + return the result) and the
|
|
96
|
+
test rewrite. No data, no migration. The content-hash dedup stays as the
|
|
97
|
+
symptom backstop regardless.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Phase 5 — Second-pass reviewer verdict
|
|
102
|
+
|
|
103
|
+
An independent reviewer subagent adversarially audited the artifact AND the
|
|
104
|
+
actual handler code (not just the claims), and **raised one concern — now
|
|
105
|
+
addressed**:
|
|
106
|
+
|
|
107
|
+
- **Concern (artifact overstatement, not a code bug):** §6's original draft
|
|
108
|
+
claimed `MessageRouter.relay` + the test suite were the only consumers. The
|
|
109
|
+
reviewer found a SECOND consumer — the `/threadline/relay-send` local
|
|
110
|
+
fast-path (`routes.ts:13824-13835`) reads the spawn-outcome fields to compute
|
|
111
|
+
an informational `deliveryOutcome`. **Resolution:** §6 corrected above to name
|
|
112
|
+
this consumer and document that it degrades gracefully to the existing
|
|
113
|
+
`'accepted'` outcome — `delivered` stays `true` (`'accepted'` is not an
|
|
114
|
+
error), no retry/delivery/correctness impact. The CODE is safe to ship as-is;
|
|
115
|
+
only the artifact's honesty needed the fix.
|
|
116
|
+
|
|
117
|
+
- **What the reviewer verified as correct (the core change is sound):** handler
|
|
118
|
+
ordering preserved — dedup, reply-waiter resolution, and the warrants-reply
|
|
119
|
+
gate's `suppress`→short-circuit all still run synchronously BEFORE the
|
|
120
|
+
response; `handleInboundMessage` is called exactly once (never dropped), its
|
|
121
|
+
rejection caught (can't 500 an already-sent response); the reply-waiter path
|
|
122
|
+
is decoupled and unbroken; the sole co-located sender reads only `response.ok`
|
|
123
|
+
within the 5 s timeout, so the accept-boundary genuinely removes the
|
|
124
|
+
duplicate-reply root; no test breaks; the rewritten test asserts the right
|
|
125
|
+
things (returns before `router-end`, no spawn fields, background completion,
|
|
126
|
+
error → still 200).
|
|
127
|
+
|
|
128
|
+
Verdict after the §6 correction: concern resolved; change is correct and safe.
|