Repository navigation
fix(server): Cue waits up to 1.5 s for a score the moment needs now - #251
Conversation
The serving cut-off is 2 s while Cue is new (user decision 2026-10-13, #248): the hook now allows 2 s, so the user-message and failed-call wait rises from 650 ms to 1.5 s and still leaves the reply inside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
What: PASS at
Read the complete PR diff and body, linked Issue and all prior PR/Issue comments, including inline review comments. No private data or credentials found in the changes. Testing used only my clones/worktrees under |
|
What: FAIL at Blocking: Rocky serving log, read-only, timing columns only, Cue-scored moments since 2026-10-13 16:11Z.
The 140 ms figure is 792 minus the 650 ms cap. In this window the median user-message wait is 414 ms, so the rest is about 240 ms. Failed calls are slower, and they share this constant. A reply after 2 s never reaches the agent: the hook exits 0. That is the cut this change is meant to stop. On these rows a shared wait has to stay under about 1.2 s to clear failed-call p90 (about 790 ms of other work) with nothing to spare. 1.5 s does not. Not the bug, checked at this head:
Proof, temp worktree under
No private data in the diff. I did not restart Chromeria or use its ports. |
The fixed 1.5 s Cue wait plus the moment's own work missed the hook's 2 s cut-off on failed calls (Grok review of #251). A moment now has one budget from its arrival: its work must finish 250 ms before the end or it is cut and logged over_budget, and a Cue wait takes only what the budget leaves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Grok's finding was right: my 140 ms figure for the other work came from user-message medians only. Failed calls take up to about 1 s on their own, and pre_tool and tool_result occasionally take 1.8 to 2.4 s. Fixed in |
|
What: FAIL at Blocking: P1, the arrival-based budget excludes authenticationLocation: The route awaits Reproduction on the exact head, only in my The deadline must start at route entry, before authentication, and its remaining time must carry into serving. A timed-out auth must fail open without serving unauthenticated content. Test both successful delayed authentication and delayed authentication failure. Merely qualifying the 1.2 s claim does not fix the reachable 2 s miss. Verified and limits
Elon record for this review:
Reviewer: independent Sol, medium effort. |
The route authenticated before the moment's clock started, so a slow authentication could still push the reply past the hook's 2 s (Sol review of #251). The moment now starts its clock first and checks the credential inside the same timed work; a cut moment serves nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Sol's round 2 finding is fixed in |
|
What: FAIL at Blocking: the arrival budget does not include authentication
This is not the disclosed synchronous stall inside the moment. The event loop can stay free while authentication waits on the semaphore, and the budget cannot shrink to pay for time it has not started counting. After that wait the handler may still use the whole 1.2 s, so the hook (curl Reproduction, only in a Checked, not blocking
Reviewer: independent Grok, medium effort. |
… parsed A moment cut by its budget was logged with only harness, delivery and timing, so a measurement joining calls to the serving log could not tell a budget cut from a call that never arrived (#252). Its row now carries what it had parsed: kind, session, tool-use id, and the run once joined. Closes #252. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Grok's round 2 blocker is the same one Sol found; it's fixed in |
|
What: FAIL at Blocking: P2, identity is saved only after all selection work finishesLocation: ContextmdServing.ts:482-504, with Select.ts:194-296.
Independent reproduction on the exact production head, in a disposable copy of the route test under {"kind":null,"status":"over_budget","session":null,"tool_use_id":null}The identity assertion fails. Repeated the probe: same failure. This is injected asynchronous store latency, not a claim that production stores currently take 1.3 s. No production implementation was modified for this probe. Retain the parsed identity before those waits, using the same validated/normalized harness interpretation as normal selection; retain nulls when authentication or actual event parsing has not completed. Cleared concerns and proof
All test runs and disposable changes were in Elon record:
Reviewer: independent Sol, medium effort, round 3. |
… any file An over-budget moment cut while selection loaded its config or store still logged no identity, because it was taken only after selection finished (Sol round 3 on #251). Selection's event reading is now `Select.identify`, which serving runs as soon as the body parses, before any file work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Sol's round 3 finding is fixed in |
|
What: PASS at Round 2 blockers, closedAuthentication is inside the timed work. The shared-database lock is inside the same clock. A transaction held on the server Other paths
Proof
No private data in the diff. I did not write Elon record
Reviewer: independent Grok, medium effort, round 3. |
|
What: PASS at Round 3 finding closed
I found no remaining asynchronous cut point after valid identity extraction that loses these fields. The new store-delay route test genuinely reaches Additional disposable real-route probes pass:
These fields satisfy #252 and contextmd#61's identity join. No credential is logged. Earlier fixes and regressionsThe first operation in The 2 s deadline remains qualified by the same disclosed synchronous limitations: shared SQLite can block the event loop with a 5 s busy timeout; synchronous final decision/logging runs after preparation, and the serving-state connection uses a 100 ms busy timeout. The guard cannot enforce an unconditional wall-clock deadline against an event-loop stall. This head neither introduces nor closes that limitation. No production latency or deployment verification is claimed. Proof, only in my
Read the PR body and all prior comments in full, complete Elon record:
Reviewer: independent Sol, medium effort, round 4. |
|
What: PASS at Round 3 finding, closedSol's cut during selection lost parsed ids because
contextmd#61 counts a server cut only when the sole Earlier fixes, still holding
Proof
The same test with GitHub Lint, Typecheck, and Test are green on this SHA. I did not re-run Knip or the contextmd contract suite. This commit does not change the HTTP reply. No private data in the diff. I did not write Elon record
Reviewer: independent Grok, medium effort, round 4. |
…251) * fix(server): Cue waits up to 1.5 s for a score the moment needs now The serving cut-off is 2 s while Cue is new (user decision 2026-10-13, #248): the hook now allows 2 s, so the user-message and failed-call wait rises from 650 ms to 1.5 s and still leaves the reply inside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(server): every ContextMD moment replies within a 1.2 s budget The fixed 1.5 s Cue wait plus the moment's own work missed the hook's 2 s cut-off on failed calls (Grok review of #251). A moment now has one budget from its arrival: its work must finish 250 ms before the end or it is cut and logged over_budget, and a Cue wait takes only what the budget leaves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(server): a moment's budget includes its authentication The route authenticated before the moment's clock started, so a slow authentication could still push the reply past the hook's 2 s (Sol review of #251). The moment now starts its clock first and checks the credential inside the same timed work; a cut moment serves nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(server): an over-budget moment logs the kind, session and call it parsed A moment cut by its budget was logged with only harness, delivery and timing, so a measurement joining calls to the serving log could not tell a budget cut from a call that never arrived (#252). Its row now carries what it had parsed: kind, session, tool-use id, and the run once joined. Closes #252. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(server): a moment knows its kind, session and call before reading any file An over-budget moment cut while selection loaded its config or store still logged no identity, because it was taken only after selection finished (Sol round 3 on #251). Selection's event reading is now `Select.identify`, which serving runs as soon as the body parses, before any file work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…251) * fix(server): Cue waits up to 1.5 s for a score the moment needs now The serving cut-off is 2 s while Cue is new (user decision 2026-10-13, #248): the hook now allows 2 s, so the user-message and failed-call wait rises from 650 ms to 1.5 s and still leaves the reply inside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(server): every ContextMD moment replies within a 1.2 s budget The fixed 1.5 s Cue wait plus the moment's own work missed the hook's 2 s cut-off on failed calls (Grok review of #251). A moment now has one budget from its arrival: its work must finish 250 ms before the end or it is cut and logged over_budget, and a Cue wait takes only what the budget leaves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(server): a moment's budget includes its authentication The route authenticated before the moment's clock started, so a slow authentication could still push the reply past the hook's 2 s (Sol review of #251). The moment now starts its clock first and checks the credential inside the same timed work; a cut moment serves nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(server): an over-budget moment logs the kind, session and call it parsed A moment cut by its budget was logged with only harness, delivery and timing, so a measurement joining calls to the serving log could not tell a budget cut from a call that never arrived (#252). Its row now carries what it had parsed: kind, session, tool-use id, and the run once joined. Closes #252. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(server): a moment knows its kind, session and call before reading any file An over-budget moment cut while selection loaded its config or store still logged no identity, because it was taken only after selection finished (Sol round 3 on #251). Selection's event reading is now `Select.identify`, which serving runs as soon as the body parses, before any file work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
What changed: every ContextMD moment now replies within 1.2 s of reaching the server, authentication included; a Cue wait gets only what that budget leaves.
Why: the first version raised the Cue wait to a fixed 1.5 s, which missed the hook's 2 s cut-off once a failed call's own work (up to about 1 s) was added (Grok review on this PR).
So what: pairs with toolboxmd/contextmd#58 (the hook's 2 s cut-off); the planner runs Sol and Grok on the new head and merges both, then the build is deployed to each machine (rocky's restart through the planner).
Part of #248. Closes #252.
Change
ContextmdServing.ts: one budget per moment,MOMENT_BUDGET_MS= 1,200 ms from its arrival.ContextmdRoute.tspasses the credential check intomoment, which runs it first inside the timed work (Sol, round 2). A moment cut before its credential is known serves nothing (204,over_budget); a refused credential still gets 401 andunauthorized.REPLY_RESERVE_MS). Past it, the moment is cut: 204, logged with the new unserved statusover_budget.COLLECT_MS(300 ms) and is also bounded by the budget.Select.ts: the event reading (harness, kind including a reported or printed failure, session, call id) isSelect.identify, run byselectand by serving right after the body parses, before any config or store file is read (Sol round 3).Cue.ts:WAIT_MSremoved;scoretakes the wait from its caller.ServingState.ts:over_budgetadded to the unserved statuses. Anover_budgetrow carries what the moment had parsed when it was cut: kind, session and tool-use id, recorded as soon as the body parses, plus thread and run once joined; a moment cut before parsing has them null (contextmd serving log: over_budget moments carry no kind, session or tool-call id #252, for contextmd#57's lost-moment count).How the numbers were picked
Outside the server, measured from Grok hook logs (hook elapsed minus server time; includes spawn, connect, queueing, transfer and the settle call), p50/p90/p99 in ms:
The server's own work besides the Cue wait, rocky, last 3 days, p50 / p90 / p99 / max in ms:
Pre_tool and tool_result reach 1.8 to 2.4 s even with no Cue wait, so no fixed wait can fit; only a total budget does.
The budget: 2,000 ms − 591 ms (user-message p99 outside the server) − 200 ms headroom ≈ 1,200 ms. Pre-tool's outside p99 (857 ms) includes Grok's hook spawn, which is outside curl's own 2 s clock.
Typical Cue wait: at the user-message median, about 1,200 − 250 − 50 − 106 ≈ 800 ms.
Proof (head
dbecf5d247)pre_tool, the session and the call id. On2cad7749d5the row had null identity.pre_tool, the session and the call id. A slow-body moment cut before parsing has them null. On the previous head the row had no kind.over_budget. On the previous head it failed (1,306 ms).MOMENT_BUDGET_MS, loggedcue_status timeout. On the old code it failed (1,548 ms).over_budget. On the old code it failed (2,450 ms).cue_status ok) inside the budget. It was rewritten rather than deleted: the requirement it protects (a slow score that fits is served) now depends on the budget, not a fixed wait.vp test run src/contextmd/: 104 passed. Typecheck 0 errors; lint has no new findings; fmt and Knip clean.Not covered
Serving whose state file failed to open still answers 204 to every caller without checking the credential, as before. A synchronous SQLite step that blocks the event loop longer than the budget delays the guard until the step ends. The pre_tool 2.4 s max above may be such a stall. #248's measurement will separate connect time from response time and show whether it happens.
Upstream: fork-only module, no upstream counterpart.
Elon record
WAIT_MSconstant.Work by Claude Opus 5.5 in Claude Code (Chromeria thread).
🤖 Generated with Claude Code