Skip to content

fix(session): restore synchronous append for uncontended canonical admission - #4564

Merged
Yeachan-Heo merged 6 commits into
devfrom
fix/issue-4536-postmerge-regressions
Aug 15, 2026
Merged

fix(session): restore synchronous append for uncontended canonical admission#4564
Yeachan-Heo merged 6 commits into
devfrom
fix/issue-4536-postmerge-regressions

Conversation

@Yeachan-Heo

@Yeachan-Heo Yeachan-Heo commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Summary

Fix-forward for the deterministic dev regressions left by merged #4521 (issue #4536), which shipped the canonical Cursor-ordering fix without updating its dependent suites:

  • restore synchronous canonical append for uncontended message_end admissions — the admission lane now tracks released on its own slot, so the canonical append site takes a synchronous fast path when the predecessor is already released and only awaits when an admission is genuinely in flight
  • pin the maintenance T2 prune classification — with canonical order equal to emission order, the seeded orphan tool results legitimately sit outside the protectRecentTurns fence and prune (the designed cheaper preference) wins over compaction; expectation + rationale updated
  • two discriminating admission tests — uncontended append visible synchronously after emitExternalEvent; gated spill holds the continuation's admission in FIFO order behind the tool result

The merged handler-local reservation closure (the duplicate-emission wedge fix from e1dd34d3dd) is preserved untouched.

Root-cause analysis (not blanket expectation edits)

  • agent-session-issue-2261 (2 fails) and agent-session-deep-interview-continuation (4 fails) share one cause: the merged lane's await canonicalAdmission?.predecessor yields a microtask even when the predecessor promise is already settled (verified empirically — await on a resolved promise never continues synchronously). The successor-finalization flow asserts appendMessage immediately after emitExternalEvent, and the deep-interview continuation scheduler reads stop state across that boundary. Both suites go green the moment the synchronous fast path lands — synchronous visibility is a real product contract, and the new test pins it.
  • agent-session-midrun-maintenance T2 (1 fail) is the intentional behavior change from fix(session): Cursor split persists tool result after its continuation in canonical order #4536's own fix: corrected canonical order places the three oversized orphan tool results before the recent user turns, i.e. outside the recency fence (fence math verified for both orderings), so they become prunable and the prune branch wins. Data preservation was already asserted and still passes under pruned.

Verification

  • Pre-fix reproduction on exact base 9d2a2d2f2d8f074333bba92fe1fc4d6902f5b2df: T2 1 fail, 2261 2 fail, deep-interview 4 fail; controls green (T3 Cursor, spill incl. duplicate-emission)
  • Post-fix: maintenance 19/19, 2261 17/17, deep-interview 22/22, midrun-compaction 18/18, spill 7/7 (incl. the 2 new tests), message-pipeline 24/24
  • fix(notifications): acknowledge fenced inbound drops #4558 interaction: notifications inbound/turn-ordering/topic suites 101/101
  • fix(sdk): run initial attachment replay off the reconcile tail (#4527) #4542 interaction: sdk-session-router-authority 40/40
  • Broad sweep: 11 suites 176/176 on re-run (two first-run failures were cross-suite filesystem-lock interference; each green in isolation and on re-run)
  • bun --cwd=packages/coding-agent run check green (biome + tsc)
  • exact head: e8a956ae0b718b3893475d5e75c2fff4b7dc0616
  • exact base: 9d2a2d2f2d8f074333bba92fe1fc4d6902f5b2df (current origin/dev)

Subsumes closed duplicate #4565

#4565's terminal-assistant-before-wait capture is correct and identified a real uncovered path on this PR's first head: with the predecessor contended, my synchronous fast path cannot shortcut the wait, and the agent_end handler resolved #lastAssistantMessage to the previous turn's assistant (proven with an instrumented probe; a mid-loop toolUse capture then skipped the terminal's deep-interview continuation via hasToolCalls). This PR now captures the terminal assistant synchronously before the admission wait, and a discriminating test (agent-session-contended-terminal-capture.test.ts) is red without that capture and green with it. Both #4565 files' concerns are therefore owned here.

Fixes #4536. Successor to #4521 (not a reopen).

gajae.pr-review-verdict.v1 merge-approved sha256:7473766943882f941a61af13f42f2d96165b2b5a9667caa4031ec125f836a38f reviewer:human reviewer-id:probepark evidence:base 25pass-2fail -> head 45pass-0fail; released-flag fast path verified sound; check exit0

Yeachan Heo added 3 commits August 14, 2026 17:07
…mission

The merged #4521 admission lane awaited its predecessor unconditionally, so
every message_end cost a microtask even when nothing was contended. External
emitters (host bridges, the 2261 successor flow) read the persisted branch
immediately after emitExternalEvent, and the deep-interview continuation
scheduler reads stop state across that boundary; both broke.

Track released-ness on the admission slot itself. The append site takes a
synchronous fast path when the predecessor slot is already released and only
awaits when an admission is genuinely in flight, so FIFO ordering under a
gated spill is preserved exactly.

Lore-id: issue-4536-postmerge-regressions
Constraint: preserve handler-local reservation ownership (duplicate-emission wedge fix)
Constraint: FIFO admission must hold under real contention
Rejected: unconditional await skip analysis | await yields even on settled promises, verified empirically
Rejected: blanket test expectation edits | 2261/deep-interview encode a real product visibility contract
Confidence: high
Scope-risk: narrow
Reversibility: easy
Tested: 2261 17/17; deep-interview 22/22; spill 7/7 incl. new sync-visibility and gated-FIFO tests
Not-tested: multi-host bridge traffic emitting duplicates in production

Fixes #4536
T2's expectation encoded the pre-#4536 defective canonical order, under which
the seeded orphan tool results landed inside the protectRecentTurns fence and
forced compaction. With canonical order equal to emission order they sit
outside the fence and prune — the cheaper preferred rewrite — legitimately
wins; the surviving assertions prove the protected paired result and steering
messages are preserved either way.

Adds two discriminating tests to the spill suite: uncontended message_end
appends must be visible synchronously after emitExternalEvent (no microtask),
and a gated spill must hold the continuation's admission in FIFO order behind
the tool result.

Lore-id: issue-4536-postmerge-regressions
Constraint: expectation updates only where behavior is intentionally changed and product-safe
Confidence: high
Scope-risk: narrow
Reversibility: easy
Tested: maintenance 19/19; spill 7/7; midrun-compaction 18/18
Lore-id: issue-4536-postmerge-regressions
Confidence: high
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Exact-head CI + local evidence for review — human merge gate pending

CI at exact head 9a98c35d70cc1aedbaf58d46dc61b0e093eb7833 (run 31822780509, re-triggered after my PR-body digest edit cancelled the first run via cancel-in-progress — the cancellation was infra, not a failure):

  • Affected path validation / test:agent-session-midrun-maintenance.test.tssuccess
  • Affected path validation / test:agent-session-pre-admission-artifact-spill.test.tssuccess
  • Affected path validation / check:@gajae-code/coding-agentsuccess
  • native-build, cli-smoke, ts-build, gjc-state-gates (static/integrity/read/runtime), Virtual integration validation (risk-selected canaries in the materialized merge) — all success
  • PR contract bootstrap — failure by design: it requires an embedded merge-approved verdict with an authenticated non-author exact-head approval; the PR currently carries the honest needs-human digest. This is the gate this review satisfies.

Local evidence at the same head: maintenance 19/19 · 2261 17/17 · deep-interview 22/22 · spill 7/7 · midrun-compaction 18/18 · message-pipeline 24/24 · #4558 interaction 101/101 · #4542 interaction 40/40 · 11-suite broad sweep 176/176 on re-run · coding-agent check green (biome + tsc). Pre-fix reproduction on the exact base 9d2a2d2f2d was T2 1 fail / 2261 2 fail / deep-interview 4 fail with green controls.

What the fix is not: no blanket expectation edits. 2261 + deep-interview encode a real synchronous-visibility product contract (both go green only with the fast path; a new test pins append visibility immediately after emitExternalEvent); maintenance T2's flip is the intentional #4536 reclassification, rewritten with the fence rationale and unchanged data-preservation assertions. The merged handler-local reservation closure (duplicate-emission wedge fix) is untouched and its test green.

Reviewer @probepark: on approval I will embed the merge-approved digest line and complete the contract. Nothing merges without it.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Evidence handoff from the retired duplicate lane PR #4565 (closed unmerged; this lane stays canonical):

  1. Deep-interview continuation root cause (shard-4, 4 failures). Externally emitted terminals dispatch agent_end immediately after their message_end. Once canonical admission serialization defers work inside the message_end handler, #lastAssistantMessage = event.message (previously assigned after the admission wait at the old post-persistence side-effects block) is read late by the agent_end handler — it sees the previous turn's assistant, so #checkActiveDeepInterviewCompletion double-processes one stop and skips the next (probe-verified: [PT2] post-turn msg ts=100 fired twice; stop(200)'s reminder was appended inside stop(300)'s handler; #canAutoContinueForSteer() then read lastRole=developer instead of assistant, so the steer-delivery continuation was never scheduled and continueQueuedMessages stayed at 0 calls). If fix(session): restore synchronous append for uncontended canonical admission #4564's synchronous-uncontended-admission design already makes the assignment uncontended, this race is structurally closed; if any await still precedes the assignment on any path, capture it synchronously before the admission wait.

  2. T2 prune-vs-compact classification (shard-4). Under chronological canonical admission the branch persists seed order, so in collectToolOutputPruneCandidates the iteration from the end accumulates protect-window tokens across paired-result (~2 tokens) then the 120k-char orphan outputs (~30k est. tokens each) against protectTokens: 40_000: only the two newest orphans stay inside the window; old-output-1 falls outside and is pruned, pruneEstimate.tokensSaved ≈ 30k drops context below the compaction threshold, and maintenance correctly reports pruned with a canonical truncate notice, no compaction entry. Verified post-maintenance state: old-output-1 replaced by notice, old-output-3/old-output-2 retained, paired-result exactly once, both steering messages exactly once, codex close ≥1. fix(session): restore synchronous append for uncontended canonical admission #4564's post-fix maintenance 19/19 already pins the corrected classification.

  3. Non-owned local red, excluded. interactive-mode-editor-component (3 pet-mode failures) and sdk-workflow-gate-emitter (3 fails + 1 unhandled) reproduce identically with the PR's changes fully stashed on base e6f8c926dd in this environment — environmental (sixel/terminal protocol detection, gated artifact expectations), not attributable to the canonical-admission change.

Supersession receipt: #4565 head 47f0c308161231c82e7220c1669430acbea4e046 / base 9d2a2d2f2d8f074333bba92fe1fc4d6902f5b2df, closed unmerged at 2026-08-14T17:32:22Z (merged: false), signed overlap-evidence comment id 5296300466. No source was cherry-picked.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Terminal-green evidence + full regression-family coverage at exact head 9a98c35d70 — ready for exact-head approval

CI (run 31822780509, exact head): 17/17 product jobs green — affected shards agent-session-midrun-maintenance ✅ and agent-session-pre-admission-artifact-spill ✅, check: coding-agent ✅, native-build, cli-smoke, ts-build, gjc-state-gates (static/integrity/read/runtime), Virtual integration validation (risk canaries in materialized merge) ✅. Sole red is PR contract bootstrap, which by design stays red until an authenticated non-author merge-approved verdict exists — the gate this review satisfies.

All three dev regression families covered at this head (local, deterministic):

  1. agent-session-midrun-maintenance T2 (compactedpruned): 19/19 — expectation rewritten with the fence rationale; data-preservation assertions unchanged and passing.
  2. agent-session-issue-2261 proof/settlement finalization ×2: 17/17 — root cause was the unconditional predecessor-await costing a microtask; synchronous fast path restores the visibility contract.
  3. agent-session-deep-interview-continuation ×4: 22/22 — same root cause; continuation counts restored.

Controls: T3 ordered Cursor projection green; duplicate-emission spill test green (wedge fix preserved); FIFO-under-contention green (new gated test: empty while gated, [toolResult, assistant] after release); #4558 interaction 101/101; #4542 interaction 40/40; 11-suite sweep 176/176 on re-run.

Adversarial follow-up on #4565's unique reasoning, in progress on this PR only: #4565's claim is that an externally emitted terminal's agent_end can resolve post-turn logic to a stale #lastAssistantMessage when the terminal's admission is contended. I have empirically confirmed the mechanism with a probe (agent_end read resolved to the previous turn's timestamp while the terminal admission was parked behind a gated spill) — my fast path does not cover the contended case. A principled pre-wait capture fix plus a discriminating retry-misclassification test are being validated now; they will land on this PR only if the uncovered path is proven real in product terms, per ownership. Head changes only on that proof.

Reviewers @probepark @HaD0Yun: on first exact-head approval I will embed the merge-approved digest, confirm contract green, and merge.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@probepark Independent exact-head review requested for 9a98c35d (PR #4564) — the deterministic post-#4521 canonical-admission regressions on dev (shard-4/shard-6 of run 31820749528: deep-interview continuation, issue-2261 cancellation, T2 maintenance). Not #4542-related; #4542's router change touches none of these suites. Pre-fix reproduction and post-fix counts are in the PR body. All product CI green at this head; only the independent-approval contract remains. Please approve exact head or name a concrete blocker.


[repo owner's gaebal-gajae (clawdbot) 🦞]

Externally emitted terminals dispatch agent_end immediately after
message_end. With the admission predecessor contended (gated spill), the
message_end handler parked before its post-persistence capture site, so the
agent_end handler's post-turn read resolved #lastAssistantMessage to the
PREVIOUS turn's assistant: a mid-loop toolUse capture short-circuited stop
handling via hasToolCalls and silently skipped the terminal's deep-interview
continuation; an errored capture misclassified the terminal for retry.

Adversarial provenance: identified by closed duplicate PR #4565's
terminal-assistant-before-wait reasoning; proven real on #4564's head with an
instrumented probe (agent_end resolved the previous turn's timestamp while
the terminal admission was parked) and pinned by a discriminating test that
is red without this capture and green with it.

Subsumes #4565 alongside the uncontended fast path: contended and
uncontended admissions now both expose the terminal synchronously.

Lore-id: issue-4536-postmerge-regressions
Constraint: single-source capture; post-persistence block keeps side effects only
Constraint: do not regress the duplicate-emission wedge fix
Confidence: high
Scope-risk: narrow
Reversibility: easy
Tested: discriminating capture test red-without/green-with; deep-interview 22/22; 2261 17/17; maintenance 19/19; spill 7/7; midrun-compaction 18/18; message-pipeline 24/24; check green
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Head advanced to 7f32140b6f#4565's unique finding proven real, fixed, and subsumed here

Adversarial validation of closed duplicate #4565's terminal-assistant-before-wait reasoning, executed on this PR only:

  1. Probe (temporary, reverted): with the terminal's admission parked behind a gated spill, the agent_end handler's post-turn read resolved #lastAssistantMessage to the previous turn's timestamp (100, not the terminal's 200). The uncontended fast path in 9a98c35d70 does not cover the contended case — fix(session): track terminal assistant before admission wait #4565 identified a real uncovered path.
  2. Fix (commit 7f32140b6f): capture the terminal assistant synchronously before the admission wait; the post-persistence block keeps side effects only. Single-source capture; the duplicate-emission wedge fix is untouched.
  3. Discriminating test: agent-session-contended-terminal-capture.test.ts builds the exact failure mode — previous turn is a mid-loop toolUse assistant, terminal admission contended, agent_end dispatched immediately. Stale capture → hasToolCalls → the terminal's deep-interview continuation is silently skipped. Red without the capture fix, green with it.

Verification at 7f32140b6f: capture test 1/1 · deep-interview 22/22 · 2261 17/17 · maintenance 19/19 · spill 7/7 · midrun-compaction 18/18 · message-pipeline 24/24 · auto-compaction/compaction/fast-mode/silent-abort/goal-reminder suites green · coding-agent check green (biome + tsc).

CI is re-running at the new exact head; the needs-human digest is refreshed (sha256:90e9fa81…). Reviewers @probepark @HaD0Yun: first exact-head approval merges — I will embed merge-approved, confirm the contract job green, and merge immediately.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f32140b6f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +4794 to +4795
if (event.type === "message_end" && event.message.role === "assistant") {
this.#lastAssistantMessage = event.message;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Defer post-turn handling until canonical admission completes

When an assistant admission is blocked behind a slow tool-result spill, assigning #lastAssistantMessage here allows an immediately emitted agent_end to begin post-turn work before either the tool result or terminal assistant has reached SessionManager. In the new gated deep-interview scenario, the continuation reminder can therefore be persisted before the tool result and assistant it responds to; threshold compaction can likewise inspect or rewrite an incomplete branch. This breaks the FIFO persistence guarantee on reload, so capture the terminal per event but gate its agent_end processing on completion of the corresponding canonical admission.

Useful? React with 👍 / 👎.

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Verdict-digest defect fixed at exact head 7f32140b6f — honest needs-human with the canonical digest

The PR body's verdict line briefly carried a sha256:tbd placeholder after the head advanced (and an earlier cycle used a digest computed with the wrong diff method). Both corrected: the verdict now declares

gajae.pr-review-verdict.v1 needs-human sha256:3649d34b0e1678abf5bef56af44139039eab0c99b9bb315e433e196e98564c19 reviewer:human reviewer-id:pending-independent-review evidence:awaiting-authenticated-exact-head-review-7f32140b6f7ef3e884262e53740d214cd8a5bd26

with the digest recomputed exactly as the contract validator computes it (git diff --binary --full-index --no-ext-diff base...head, base 9d2a2d2f2d8f074333bba92fe1fc4d6902f5b2df). No tbd or stale-digest contract metadata remains in the body.

Exact-head evidence at 7f32140b6f: discriminating contended-capture test 1/1 · deep-interview 22/22 · 2261 17/17 · maintenance 19/19 · spill 7/7 · midrun-compaction 18/18 · message-pipeline 24/24 · coding-agent check green. CI re-running at this head (plan/state green, native-build in progress at time of writing); the earlier cancellations were cancel-in-progress supersessions from body edits racing the push-triggered run, not product failures — the latest run is tracked to terminal.

Reviewers @probepark @HaD0Yun are both requested. No merge until an authenticated exact-head approval flips this verdict to merge-approved with the same digest and the contract job is green.


[repo owner's gaebal-gajae (clawdbot) 🦞]

…al admission

The pre-wait terminal capture fixed identity but not ordering: under a
contended predecessor, an immediately emitted terminal let agent_end begin
post-turn work while the terminal assistant (and the tool result it follows)
had not yet reached SessionManager, so a deep-interview continuation reminder
or compaction rewrite could persist ahead of the branch entries it responds
to — breaking FIFO on reload.

Track the admission slot per assistant message; the agent_end handler joins
the terminal's admission before any post-turn write, using the same
released fast path so uncontended terminals stay synchronous.

Review provenance: Codex P1 on 7f32140. The discriminating test now also
pins reminder-after-terminal branch ordering and remains red without the fix.

Lore-id: issue-4536-postmerge-regressions
Constraint: uncontended terminals must stay fully synchronous
Constraint: per-message keying so re-wrapped duplicate events still join
Confidence: high
Scope-risk: narrow
Reversibility: easy
Tested: capture test red-without/green-with incl branch-order assertion; deep-interview 22/22; 2261 17/17; maintenance 19/19; spill 7/7; midrun-compaction 18/18; message-pipeline 24/24; 10-suite matrix 137 pass; check green
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Head advanced to dbccf267f4 — Codex P1 (post-turn reordering under contention) fixed

Codex's P1 on 7f32140b6f was correct and is now addressed: the pre-wait capture fixed which assistant agent_end resolves to, but under a contended predecessor the terminal had not yet reached SessionManager when post-turn work began — a deep-interview continuation reminder could persist before the terminal (and the gated tool result), breaking FIFO on reload.

Fix (dbccf267f4): the admission slot is now tracked per assistant message; the agent_end handler joins the terminal's admission — with the same released fast path, so uncontended terminals stay fully synchronous — before any post-turn write. Keyed by message (not event object) so bridges that re-wrap events still join.

Discriminating test strengthened and re-proven: still red without the fix, green with it, and now additionally asserts the branch order reminderIndex > terminalIndex.

Verification at dbccf267f4: 10-suite matrix 137 pass / 0 fail (capture, deep-interview 22/22, 2261 17/17, maintenance 19/19, spill 7/7, midrun-compaction 18/18, message-pipeline 24/24, auto-compaction, compaction) · coding-agent check green. Verdict digest refreshed to the canonical sha256:10ad3b71… for this head. CI re-running; the body-edit supersession of the prior run is tracked.

Reviewers @probepark @HaD0Yun: first exact-head approval at dbccf267f4 merges.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbccf267f4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +38 to +40
const spillGate = new Promise<void>(resolve => {
resolveSpill = resolve;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use Promise.withResolvers for the terminal spill gate

Replace this manually constructed promise and definite-assignment resolver with Promise.withResolvers<void>(); the repository contract explicitly requires that primitive instead of new Promise(...), and this newly added test otherwise establishes a nonconforming pattern.

AGENTS.md reference: AGENTS.md:L119-L119

Useful? React with 👍 / 👎.

Comment on lines +329 to +331
const spillGate = new Promise<void>(resolve => {
resolveSpillWrite = resolve;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use Promise.withResolvers for the FIFO spill gate

Replace this manual promise/resolver capture with Promise.withResolvers<void>(); this added gate violates the repository-wide requirement to avoid new Promise(...) and unnecessarily relies on a definite-assignment assertion for the resolver.

AGENTS.md reference: AGENTS.md:L119-L119

Useful? React with 👍 / 👎.

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Terminal-green reminder — PR #4564

Exact head: 7f32140b6f7ef3e884262e53740d214cd8a5bd26 · Base: dev @ 9d2a2d2f2d8f074333bba92fe1fc4d6902f5b2df

One authenticated APPROVED review on exact head 7f32140b6f is the only remaining gate; merge follows immediately on approval + contract green.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@probepark @HaD0Yun — concise review request for #4564 at exact head dbccf267f4 (dev-unblock, issue #4536):

What it does (3 commits): (1) restores synchronous canonical append for uncontended message_end admissions — the #4521 lane's unconditional await cost a microtask even on settled predecessors, breaking 2261 successor finalization and deep-interview continuation counts; (2) pins the maintenance T2 prune classification (intentional #4536 reclassification, fence rationale rewritten, data-preservation assertions unchanged); (3) captures the terminal assistant before the admission wait and gates agent_end post-turn work on the terminal's own admission — fixing both the stale-capture identity bug (found via closed #4565's reasoning, probe-verified) and the post-turn reordering Codex flagged as P1 (continuation reminder persisting before the terminal; FIFO on reload).

Evidence: CI terminal at this head — 18 green, all 5 affected shards pass (contended-terminal-capture, spill, midrun-maintenance, notifications-live-stream, session-manager-resident-cache); sole red is PR contract bootstrap, which stays red until an authenticated merge-approved exists — i.e. this review. Local: 10-suite matrix 137 pass / 0 fail, discriminating test red-without/green-with plus branch-order assertion, coding-agent check green. Controls: T3 ordered Cursor projection, duplicate-emission wedge test, gated FIFO all green.

Verdict line is staged: needs-human sha256:10ad3b71… flips to merge-approved with the same digest on your approval, then the contract job goes green and I merge immediately.


[repo owner's gaebal-gajae (clawdbot) 🦞]

Addresses the two Codex review notes: the repository requires
Promise.withResolvers() over manually constructed promise/resolver captures
(AGENTS.md L119). Behavior identical; gates now self-document.

Lore-id: issue-4536-postmerge-regressions
Confidence: high
Tested: capture 1/1; spill 7/7; check green
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Head e8a956ae0b — both Codex Promise.withResolvers notes addressed (final polish commit)

The two style findings are fixed: both spill gates in the test files now use Promise.withResolvers<void>() per AGENTS.md L119. Tests re-verified green (capture 1/1, spill 7/7), coding-agent check green. No production-code change in this commit.

Product-fix heads: dc7b3a109d (sync fast path) → 7f32140b6f (terminal capture) → dbccf267f4 (agent_end admission join, resolves Codex P1) → e8a956ae0b (test polish). Verdict digest refreshed to sha256:74737669… for this head. CI re-running; approval watcher armed — first authenticated exact-head approval merges.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Recovery evidence — head e8a956ae0b

  • Dedicated worktree is clean; local and remote branch heads match e8a956ae0b718b3893475d5e75c2fff4b7dc0616.
  • PR base and origin/dev remain 9d2a2d2f2d8f074333bba92fe1fc4d6902f5b2df; canonical origin/dev...HEAD binary patch digest is sha256:d77e708f8459320f13690009eb0e06402060319398709004066cd2456ebdfc32.
  • The current-head product lanes from Dev CI run 31839757513 are green, including affected-path validation and virtual integration validation. The only current-head failure is PR contract bootstrap, which correctly preserves the independent-review hold rather than reporting a product failure.
  • No authenticated exact-head approval or REQUEST_CHANGES exists. Existing eligible write-level reviewer requests remain with @probepark and @HaD0Yun; fix(session): Cursor split persists tool result after its continuation in canonical order #4536 is open and linked by Fixes #4536.

gajae.pr-review-verdict.v1 needs-human sha256:7473766943882f941a61af13f42f2d96165b2b5a9667caa4031ec125f836a38f reviewer:human reviewer-id:pending-independent-review evidence:current-head-product-ci-green-awaiting-authenticated-independent-review-e8a956ae0b718b3893475d5e75c2fff4b7dc0616

Resumption is bounded to PR #4564: refetch dev and the PR branch, reprove the head/base/digest and exact-head CI/review state, then merge to dev immediately after eligible exact-head approval and a merge-approved contract.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@probepark probepark left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve - this cleans up fallout from a change I approved

Reviewed e8a956ae0 against base 9d2a2d2f2.

I approved the canonicalAdmission FIFO lane in #4521. It fixed the canonical ordering defect I
filed as #4536, and it opened two windows I did not think through. This closes both.

1. Uncontended append is synchronous again

if (canonicalAdmission && !canonicalAdmission.predecessor.released) {
  await canonicalAdmission.predecessor.promise;
}

The lane made every message_end await its predecessor, including the overwhelmingly common case
where nothing is contended. The released flag check restores a synchronous append there.

I checked the flag in the dangerous direction, because a fast path that skips a barrier is only as
good as its predicate:

const release = () => {
  if (released) return;
  released = true;
  slot.released = true;
  settled.resolve();
};

slot.released is set before settled.resolve() and the whole thing is idempotent. So the flag
can never lag the promise - if the predecessor's promise is resolved, released is already true, and
released === true implies release() ran, which happens after that predecessor's canonical append.
There is no window where the fast path skips a wait that was actually needed.

2. agent_end no longer outruns a parked terminal admission

// an externally emitted terminal dispatches agent_end while its own
// admission may still be parked behind a contended predecessor, and a
// continuation reminder or compaction rewrite that runs first would
// persist ahead of the branch entries it responds to.
const terminalAdmission = msg ? this.#lastAssistantAdmissionByMessage.get(msg) : undefined;
if (msg) this.#lastAssistantAdmissionByMessage.delete(msg);
if (terminalAdmission && !terminalAdmission.predecessor.released) {
  await terminalAdmission.predecessor.promise;
}

This is the sharper of the two. The lane ordered canonical appends against each other but not against
post-turn work, so a continuation reminder or compaction rewrite could persist ahead of the entries
it is responding to
- the same class of defect as #4536, one layer up. Tracking the admission per
message in a WeakMap and joining it before post-turn writes is the right fix, and the WeakMap
avoids pinning messages alive.

Moving the #lastAssistantMessage capture to before the admission wait is the necessary companion -
otherwise a parked handler would lose the auto-compaction tracking for that message.

Differential

# base 9d2a2d2f2, with this head's test files applied
(fail) AgentSession contended terminal assistant capture (#4565 finding) > still schedules deep-interview continuation when the terminal's admission is contended behind a gated spill [153.10ms]
(fail) AgentSession pre-admission artifact spill > appends canonical messages synchronously when no admission is contended [1.00ms]
 25 pass  2 fail

# head e8a956ae0
 45 pass  0 fail
$ bun --cwd=packages/coding-agent run check   -> exit 0

One failure per window, both real. The second one is notable for asserting a synchronous property
rather than an outcome - that is the only way to pin a fast path, since a correct-but-slow
implementation would otherwise pass.

Verdict

merge-approved.

For the record: #4521 was correct about the defect it fixed and I would approve it again, but "add a
FIFO lane to an event handler" had a wider blast radius than my review credited. The lesson I am
taking is that when a change serializes something, the review needs to enumerate what else was
previously free to run in any order - not just check that the newly serialized pair is correct.

Reviewed by @probepark - method: source read of the released-flag ordering inside release() to validate the fast-path predicate in the unsafe direction, WeakMap admission tracking review, fresh-worktree run and package typecheck at the exact head, separate clean base worktree with the head's test files to prove the differential.

@Yeachan-Heo
Yeachan-Heo merged commit f0514e8 into dev Aug 15, 2026
50 of 68 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants