Skip to content

test(session): prove canonical Cursor compaction - #4521

Merged
Yeachan-Heo merged 6 commits into
devfrom
fix/issue-4505-canonical-contract
Aug 14, 2026
Merged

test(session): prove canonical Cursor compaction#4521
Yeachan-Heo merged 6 commits into
devfrom
fix/issue-4505-canonical-contract

Conversation

@Yeachan-Heo

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

Copy link
Copy Markdown
Owner

Summary

Fix-forward for #4505 and #4536:

  • terminally fail the mocked provider EventStream when its detached producer rejects or is aborted
  • require T3's maintenance checkpoint to report maintenanceOutcome: "compacted" and persist a compaction entry
  • assert the canonical Cursor projection in provider order: preamble -> server result -> continuation
  • prove the unsplit original usage anchor is absent from canonical post-compaction context
  • serialize canonical message_end admission across pre-admission artifact spilling so a yielded tool result cannot be overtaken by its continuation
  • own each canonical admission reservation by its emission's handler, so duplicate emission of the same message_end event object (host bridge/replay) cannot overwrite the reservation and deadlock every later canonical admission

The production fix preserves raw Agent event chronology, the provider-context transformation barrier, and listener abort/reentrancy semantics; it does not globally serialize Agent listeners.

Verification

  • Cursor T3: passed three consecutive exact-head runs
  • agent-session-midrun-compaction.test.ts: 18/18, three consecutive runs
  • agent-session-pre-admission-artifact-spill.test.ts: 5/5 including the new duplicate-emission regression (red with a timeout on the prior code, green after the fix)
  • cursor-exec-handlers.test.ts + agent-session-concurrent.test.ts: 35/35
  • session-manager-resident-cache.test.ts + notifications-live-stream.test.ts: 23/23
  • bun --cwd=packages/agent run check: passed
  • bun --cwd=packages/coding-agent run check: passed
  • exact head: e1dd34d3dd030aea774c59c492769567258a8f0c
  • exact base: e6f8c926dd6f388be8d87868eaeee1afff651b40

Fixes #4536. Follow-up to #4505.

gajae.pr-review-verdict.v1 merge-approved sha256:b7dd375651ee48a75e68b553235f7879c014f2a71afd5ae74917d2305c5a6d27 reviewer:human reviewer-id:probepark evidence:canonicalAdmission fixes #4536; base 17pass-1fail on ordered assertion -> head 18pass-0fail

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from ed81a8a to 958e273 Compare August 13, 2026 20:15

@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: ed81a8aa8e

ℹ️ 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 +666 to +668
expect(canonicalMessages.indexOf(canonicalContinuation!)).toBeLessThan(
canonicalMessages.indexOf(canonicalServerResult!),
);

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 Preserve the Cursor tool-result order

When a Cursor response reports a provider-side tool result mid-stream, the split contract is Assistant(preamble) -> ToolResults -> Assistant(continuation) (packages/agent/src/agent.ts:2141-2145). This assertion requires the opposite order in the durable display context, so it makes the test accept a compaction-reordered transcript and would reject a fix that preserves provider chronology. Assert that canonicalServerResult precedes canonicalContinuation so this test detects the canonical-context corruption instead of encoding it.

Useful? React with 👍 / 👎.

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from 958e273 to 85fef72 Compare August 13, 2026 20:31

@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: 85fef72a1e

ℹ️ 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 +653 to +656
const content = JSON.stringify((message as { content?: unknown }).content ?? "");
return content.includes("Cursor preamble and continuation") && content.includes("cursor-call");
}),
).toBe(false);

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 Assert the split messages survive canonical compaction

In this revision, the positive Cursor-message assertions have been removed altogether: this condition only proves that the unsplit anchor is absent. If compaction drops the server-side tool result, the continuation, or every Cursor message, the maintenance event and compaction entry still exist and this test passes, so it no longer protects the externally observable preservation contract it is intended to cover. Assert that the canonical context contains the split preamble, tool result, and continuation in provider order.

AGENTS.md reference: AGENTS.md:L156-L160

Useful? React with 👍 / 👎.

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from 85fef72 to 6953b60 Compare August 13, 2026 20:54
@Yeachan-Heo
Yeachan-Heo requested a review from probepark August 13, 2026 20:58
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@probepark Exact-head approval requested for 6953b609008f546597463111df2e92c7004ab9df.

Independent architect review found no findings and marked the head safe to merge. The one-file test-only diff makes the mocked provider producer terminally fail its EventStream, requires maintenanceOutcome: compacted plus a persisted compaction entry, and checks canonical absence of the unsplit original Cursor usage anchor. No production, timeout, retry, or sleep changes.

Local exact-head evidence: 54/54 focused/related tests (3,231 assertions) and coding-agent package check/types passed. Please submit an APPROVED review on this exact head; COMMENTED is neutral under the repository contract.

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@HaD0Yun Exact-head APPROVED review requested for 6953b609008f546597463111df2e92c7004ab9df. Independent architect review is clean; replacement CI is green; local focused/related suites are 54/54 and package check/types pass. Please submit an APPROVED GitHub review on this exact head; COMMENTED does not satisfy the repository contract.

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from 6953b60 to a8d1ae7 Compare August 13, 2026 21:05
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@HaD0Yun Final replacement head is now a8d1ae74d8ad5bb9c16f5d9bb0e990a4d0be761a after fixing the architect's retained-split finding. Exact diff is still one test file. Local evidence: 54/54 focused/related tests, 3,234 assertions, package check/types green. Please submit an APPROVED GitHub review on this exact SHA; prior-head or COMMENTED reviews do not satisfy the gate.

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Authoritative #4521 status refreshed at exact head a8d1ae74d8ad5bb9c16f5d9bb0e990a4d0be761a, base/current dev 38f3b4077c870e41d061f8f2aa7f5c873a30e25f. Local, remote branch, and PR head are identical; the lane is clean.

The final fix retains canonical Cursor preamble, continuation, and server-side result deterministically, rejects the unsplit original payload, requires a compacted maintenance outcome and compaction entry, and terminally settles detached fixture errors. Local exact-head evidence is 54/54 focused/related tests with 3,234 assertions plus coding-agent package check/types.

Current bootstrap failure is solely the required non-author authenticated exact-head approval; requested reviewers remain probepark, HaD0Yun, and IYENTeam. Previous-head reviews and COMMENTED reviews remain stale/neutral.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@HaD0Yun Current exact head is 15a17062384d362899b9df926ee34d2ca340467c. It fixes both Codex P1 findings: canonical compaction positively retains all three split artifacts, and raw provider events assert preamble → server result → continuation chronology. Focused file passed three consecutive runs; related suites and package check/types are green. Please submit an authenticated APPROVED review on this exact head.


[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: 15a1706238

ℹ️ 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 +664 to +666
expect(canonicalPreamble).toBeDefined();
expect(canonicalContinuation).toBeDefined();
expect(canonicalServerResult).toBeDefined();

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 Assert chronology in the canonical context

When compaction persists the split messages in the wrong order, these presence-only checks still pass; the chronology assertion below examines transient loop.agentEvents, not canonicalMessages, so it cannot detect a durable Assistant(preamble) -> Assistant(continuation) -> ToolResult regression that affects subsequent display/model context. Fresh evidence in this revision is that lines 667–681 add provider-event ordering while the canonical checks remain presence-only; compare the three canonical indices and require preamble < server result < continuation.

AGENTS.md reference: AGENTS.md:L156-L160

Useful? React with 👍 / 👎.

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Ownership is unified in the sole authoritative SDK lane. Local/remote/PR head are 15a17062384d362899b9df926ee34d2ca340467c; base/current dev is 38f3b4077c870e41d061f8f2aa7f5c873a30e25f.

The detached production experiment was preserved as /tmp/issue-4505-live-sdk-dirty.patch (SHA-256 dc86b731d871bf4baafb0b3deddae7e81b385585ec0990684753955081682cdf) and discarded as unsafe/unnecessary: it changed global listener semantics, lacked complete rejection/reentrancy guarantees, and produced unrelated regression risk. The no-session experiment was preserved as /tmp/issue-4505-no-session-unique.patch (SHA-256 fdbfcbb76f0e47bb46d8db404e8170fe3aeb54e273842cf0e4e464fc0f2af25c) and retired with no unique valid work.

Authoritative local evidence on head 15a17062: target file 18/18, related maintenance/auto-compaction/EventStream suites 36/36, coding-agent package check/types green. The current test positively asserts canonical survival of preamble/server result/continuation and independently asserts provider emission chronology.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@HaD0Yun Current exact head is 6705817082d6df15d3462269e49adbf089cd8d86. Codex exposed a real canonical persistence race, now fixed in production: Cursor preamble segments and server-side results publish at provider callback boundaries, with only the remaining continuation emitted at response completion. Canonical and raw chronology are both asserted. Focused/related Cursor suites and agent/coding-agent checks are green. Please submit an authenticated APPROVED review on this exact head.


[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: 6705817082

ℹ️ 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 thread packages/agent/src/agent.ts Outdated
this.appendMessage(toolResult);
this.#emit({ type: "message_end", message: toolResult });
}
// Provider-side tool results were emitted at their callback boundary.

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 Skip re-appending an already published terminal prefix

When a Cursor turn invokes a server-side tool after all of its assistant text has streamed, splitPoint >= fullText.length. The callback path has already appended that entire text prefix and the tool result, but this branch still appends assistantMessage before returning, so the assistant text is duplicated in the durable session and subsequent model context. This is especially common for turns with one tool callback and no post-tool continuation; guard the final append using #cursorPublishedTextLength or emit only text that was not already published.

Useful? React with 👍 / 👎.

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from 6705817 to db05c8a Compare August 13, 2026 22:07
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@HaD0Yun Final exact head is db05c8aaa9ef0d11d1264c3a8abc82cca09373ff. It includes the Codex duplicate-prefix fix and a direct regression test for a fully published Cursor prefix with no continuation. Exact local evidence: T3 file passed three consecutive runs; related Cursor/maintenance suites 58/58; agent and coding-agent checks/types green. Please submit an authenticated APPROVED review on this exact head.


[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: db05c8aaa9

ℹ️ 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 thread packages/agent/src/agent.ts Outdated
});
if (prefixContent.length > 0) {
const preambleMessage: AssistantMessage = { ...partialMessage, content: prefixContent };
this.#emit({ type: "message_start", message: preambleMessage });

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 Zero usage on additional Cursor prefix segments

When one Cursor response executes multiple server-side tools with text between them, this path appends a new assistant message for every prefix segment, but each shallow copy retains the same mutable usage object from the provider's partial message. Cursor continues updating that object through token deltas and final cost calculation, so after the turn every prefix is charged with the full response usage; AgentSession.getSessionStats() and other message-end usage consumers consequently multiply tokens and cost by the number of tool callbacks. Preserve the usage anchor on only one split message and zero the usage on subsequent prefix segments, as is already done for the final continuation.

Useful? React with 👍 / 👎.

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Exact PR status: head db05c8aaa9ef0d11d1264c3a8abc82cca09373ff, base/current dev 38f3b4077c870e41d061f8f2aa7f5c873a30e25f, active CI run https://github.com/Yeachan-Heo/gajae-code/actions/runs/31749018651.

GitHub currently has zero authenticated non-COMMENTED exact-head approvals. The sole canonical verdict line has therefore been corrected to needs-human with exact diff digest 300f0856efe0c872a9512d2042d82032085f814daf11c31245e1a02ccf876986. Merge remains intentionally blocked until a requested non-author reviewer submits APPROVED on this exact head; only then will the verdict be replaced with an honestly bound merge-approved receipt and fresh full CI driven terminal.

Local evidence remains green: target repeated three times, related Cursor/maintenance suites 58/58, and agent/coding-agent checks/types passed. Current CI is still in progress; cancellation-derived failures are not treated as product verdicts.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Cross-PR dependency evidence for #4518: review-event run 31749018651, shard-3 job 94612651694 fails exactly because this branch does not contain PR #4523. acp-builtins.test.ts lacks deterministic authStorage.listCredentialInventory authority (3 /usage failures), and sdk-operation-inventory.test.ts leaves agent_session:setCredentialPin / setCredentialAuto pending review. PR #4523 exact head 1296931597649bc849c37ae409775234248df5c2 fixes both and previously passed exact shard 3 (174/174). Rebase #4521 after #4523 lands; no Cursor changes are requested here.

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Exact-head CI run https://github.com/Yeachan-Heo/gajae-code/actions/runs/31749018651 is terminal cancelled after aggregate failure propagation. Its #4521 source verdict is clean for Cursor compaction; the primary failures are external dependencies:

Dedicated dependency PR #4523 (1296931597649bc849c37ae409775234248df5c2) has green exact targeted checks for the #4518 contracts. No #4518/default-model files are being absorbed into #4521. The canonical verdict remains honestly needs-human pending an authenticated exact-head approval and dependency merge/rebase.


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

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from db05c8a to 15a1706 Compare August 13, 2026 22:38
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

The callback-boundary production design at db05c8aaa9ef0d11d1264c3a8abc82cca09373ff was independently blocked: it could publish before the provider prefix was consumed, drop tool-call blocks/final usage metadata, and create duplicate assistant lifecycles. That head has been removed from the PR branch rather than shipped.

PR #4521 is restored to safe test-only head 15a17062384d362899b9df926ee34d2ca340467c, exact base 38f3b4077c870e41d061f8f2aa7f5c873a30e25f, with honest needs-human digest 3d1bbfdf75ba11be013d60a55f5f9580652927466ba1e7bef0e8ebaa206e1af8. The unresolved canonical-persistence chronology finding remains a real merge blocker; no unsafe production workaround or false merge-approved receipt remains.

Dependency CI failures remain separately owned by #4518/#4523 and default-model admission owners.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

#4521 remains intentionally held at safe test-only head 15a17062384d362899b9df926ee34d2ca340467c. The attempted production chronology designs were rejected by adversarial review and removed; no unsafe listener/callback changes remain.

The next authorized transition is dependency-first: merge #4523, then reconstruct #4521 onto the new dev, refresh exact digest/review/CI, and reassess the canonical persistence-order blocker against that current code. Until then, the verdict remains needs-human; no approval or CI result is being fabricated.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@HaD0Yun Authenticated non-author APPROVED review is requested for exact current head 15a17062384d362899b9df926ee34d2ca340467c against base/current dev 38f3b4077c870e41d061f8f2aa7f5c873a30e25f. Prior-head requests and COMMENTED reviews are stale/neutral. Current authoritative CI: https://github.com/Yeachan-Heo/gajae-code/actions/runs/31750834088.

The PR remains dependency-held behind #4523/#4518 and #4519-owned contracts; none of those files are being absorbed here. Please submit an exact-head GitHub APPROVED review only after reviewing this head.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Exact hold census for PR #4521:

Target TypeScript build is green and the exact target test is still running. Only a causal #4521-owned failure will change source; dependency/aggregate cancellation propagation will not.


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

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from 26e03a9 to 410dbfa Compare August 14, 2026 04:25
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Composition refresh for PR #4521:

  • exact head: 410dbfaa1fb49ed79696292c8570917d632a15ee
  • exact base/current dev: 34f5db331b484726c447f6ab026f35c8b391a879
  • exact diff SHA-256: 0ff0a8404ccd153a4ace456cad7b5b38e844b34c1a4a24e4d02fd79f5db55606
  • changed path: packages/coding-agent/test/agent-session-midrun-compaction.test.ts only

Resolved composition red: agent-session-before-agent-start-attribution.test.ts now passes 11/11 after #4524/#4519 landed. Exact shard 2 is running on this head.

Intentional product-dependency red remains isolated: ordered T3 still receives preamble -> continuation -> server-result instead of preamble -> server-result -> continuation, exactly issue #4536. The ordered assertion and strict original-anchor eviction proof remain unchanged; no #4536 code is absorbed here.

All prior reviews and CI are stale. Verdict remains needs-human pending #4536 landing and a fresh exact-head approval.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Exact composition verification completed on head 410dbfaa1fb49ed79696292c8570917d632a15ee / base 34f5db331b484726c447f6ab026f35c8b391a879:

The stale #4519 composition failures are fully resolved. The only intentional red acceptance remains T3's #4536 canonical order (preamble -> continuation -> server-result instead of preamble -> server-result -> continuation). No assertion was weakened and no #4536 source was added.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Exact-head run https://github.com/Yeachan-Heo/gajae-code/actions/runs/31769818674 is terminal and causally classified:

This run contains no new #4521-owned implementation failure. The branch remains an active bounded dependency hold until #4536 lands.


[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.

Both asks are met, the assertion is correct - and it is red, which is the honest outcome

Re-reviewed at 410dbfaa1. Test-only, one file.

You fixed exactly what I asked for

const canonicalCursorOrder = canonicalMessages.flatMap(message => {
  if (message === canonicalPreamble) return ["preamble"];
  if (message === canonicalServerResult) return ["server-result"];
  if (message === canonicalContinuation) return ["continuation"];
  return [];
});
expect(canonicalCursorOrder).toEqual(["preamble", "server-result", "continuation"]);
expect(canonicalMessages).not.toContainEqual(originalAnchor!);

Ordered projection instead of three unordered .find() presence checks, and the anchor-removal
assertion I flagged as deleted is restored. Nothing left from my previous review.

It fails, and that is correct

$ bun test packages/coding-agent/test/agent-session-midrun-compaction.test.ts
expect(canonicalCursorOrder).toEqual(["preamble", "server-result", "continuation"]);
                             ^
(fail) T3 exercises the Cursor split path without retaining the original usage anchor
 17 pass  1 fail

This is #4536 reproducing: the canonical projection is preamble -> continuation -> server-result,
the tool result persisted after the assistant continuation that follows it, while the raw event
assertion five lines below still passes with ["assistant","toolResult","assistant"].

So the test is now telling the truth about a real bug rather than certifying the wrong order as
correct. That is a much better state than the green it had before - but it does mean this PR cannot
merge as-is.

One diagnostic that should save you time

The failure aborts the test at that line, so the restored anchor assertion 23 lines further down
never executes and its status was unknown. I checked it in a scratch worktree by flipping only the
expected order to the observed one:

# ordering expectation flipped to ["preamble","continuation","server-result"], nothing else changed
 18 pass  0 fail

So the anchor assertion does hold - compaction genuinely evicts the 180k anchor - and the
canonical ordering is the only remaining defect in this scenario. Your test file is complete and
correct; nothing else in it is waiting to fail behind this one.

Verdict

merge-blocked, but on #4536 rather than on anything in this diff.

Two ways forward, both fine by me:

  1. Fold the #4536 fix into this PR. It becomes fix + regression test in one change, which is
    the shape I would prefer - the test then goes green for the right reason and the ordering
    contract lands pinned.
  2. Keep it test-only and make it depend on #4536. Mark it blocked-by and merge it immediately
    after, so it never sits on dev red.

What I would not do is relax the assertion to match current behaviour. The order in #4536 is wrong
on the wire-versus-persisted comparison, not a matter of taste, and this assertion is now the only
thing in the repo that would catch a regression once it is fixed.

Verdict line digest recomputed for the current head. Happy to re-review the moment either path
lands.

Reviewed by @probepark - method: diff read against my previously reviewed head, exact-head run in a clean detached worktree with real bun install and rebuilt natives, scratch flip of the ordering expectation to confirm the remaining assertions hold and isolate the single defect, independent digest computation.

@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from 410dbfa to 787901e Compare August 14, 2026 11:52
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

PR #4521 is rebased onto current dev and now includes the #4536 production fix at exact head 787901ef89a4e6ef8f509c27764730c53721efae.

The fix reserves every message_end synchronously and serializes only canonical admission across the existing pre-admission artifact-spill boundary. It does not globally serialize Agent listeners, alter raw provider event order, or remove the provider-context barrier. The ordered canonical test now passes as preamble -> server-result -> continuation, and original-anchor eviction remains asserted.

Local exact-head evidence: Cursor T3 passed three consecutive runs; full mid-run compaction 18/18; pre-admission spill 4/4; agent and coding-agent check/types passed. Fresh CI is running.

@probepark Please re-review and submit an authenticated APPROVED review on exact head 787901ef89a4e6ef8f509c27764730c53721efae if the implementation resolves your blocker.


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

@Yeachan-Heo
Yeachan-Heo requested a review from probepark August 14, 2026 11:55

@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: 787901ef89

ℹ️ 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 +4315 to +4316
#canonicalMessageAdmissionTail: Promise<void> = Promise.resolve();
#canonicalMessageAdmissions = new WeakMap<object, { predecessor: Promise<void>; release: () => void }>();

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 Add the coding-agent changelog entry

This adds production behavior to packages/coding-agent by serializing canonical message admission, but the commit does not update packages/coding-agent/CHANGELOG.md. Consequently, the Cursor transcript-ordering fix will be omitted from the package's release notes; add an entry under ## [Unreleased] as required by the repository contract.

AGENTS.md reference: AGENTS.md:L188-L188

Useful? React with 👍 / 👎.

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

@probepark 존중을 담아 exact-head 재리뷰를 요청드립니다. 현재 PR/base/branch는 모두 고정되어 있습니다.

  • exact head: 787901ef89a4e6ef8f509c27764730c53721efae
  • exact base/current dev: 10144d55f50ad03615994f4cff2bd5583686ff9e
  • exact diff SHA-256: 61643f4db44e194c8f846fadef6a7ade792f3643d3ba46cf3b5e76b368902960

410dbfaa1fb49ed79696292c8570917d632a15ee에서 지적해 주신 두 blocker는 다음과 같이 유지·해결했습니다.

  1. 삭제됐던 original-anchor eviction proof

    • expect(canonicalMessages).not.toContainEqual(originalAnchor!)가 canonical display projection을 대상으로 그대로 존재합니다.
    • unsplit Cursor anchor를 거부하는 별도 negative assertion도 유지했습니다.
  2. membership-only canonical checks / 실제 canonical order defect

    • canonical projection은 단일 ordered assertion으로 preamble -> server-result -> continuation을 요구합니다.
    • 새 production fix는 Agent listener 전체를 직렬화하지 않고, 각 message_end를 synchronous event boundary에서 예약한 뒤 canonical admission만 predecessor 순서로 통과시킵니다.
    • tool-result의 기존 pre-admission artifact-spill await와 provider-context transformation barrier는 유지됩니다. raw provider event chronology, abort/reentrancy semantics, extension delivery는 변경하지 않았습니다.
    • admission은 canonical append 직후, extension delivery 및 unrelated post-message work 전에 release되며 outer handler finally가 실패/조기 종료 경로를 release합니다.

Exact-head 검증:

  • Cursor T3: 3회 연속 통과
  • full agent-session-midrun-compaction.test.ts: 18/18, 107 assertions
  • agent-session-pre-admission-artifact-spill.test.ts: 4/4, 23 assertions
  • bun --cwd=packages/agent run check: 통과
  • bun --cwd=packages/coding-agent run check: 통과

CI run 31797985249의 aggregate job 94759439576은 제품/aggregate 구현 실패가 아닙니다. assertion input은 PLAN=success, NATIVE=cancelled, SHARDS=cancelled였고, cancellation은 needs-human PR contract bootstrap failure의 downstream propagation입니다. aggregate나 코드는 이 분류 때문에 수정하지 않습니다.

현재 verdict는 정직하게 needs-human이며 exact-head authenticated approval 전에는 변경하지 않겠습니다. 이 head가 blocker를 해결했다고 판단되시면 GitHub APPROVED review를 exact head 787901ef89a4e6ef8f509c27764730c53721efae에 제출해 주십시오. 승인 확인 후 동일 verdict line만 reviewer/digest/evidence에 정확히 바인딩하여 merge-approved로 바꾸고 fresh CI에서 native, shards, aggregate 전부 green을 요구하겠습니다.


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

Yeachan Heo added 5 commits August 14, 2026 12:34
The original #4505 fix removed the circular provider wait but its assertions still observed transient events and an object-identity anchor. Make detached fixture failures terminally settle the stream, require a compacted maintenance outcome, and verify the Cursor split and original-anchor absence in canonical display context.

Lore-id: issue-4505-canonical-contract

Constraint: keep the existing 30s timeout and production compaction unchanged

Rejected: raw event ordering only | does not prove canonical post-compaction state

Confidence: high

Scope-risk: narrow

Reversibility: easy

Tested: focused file and related maintenance suites
Codex found that the canonical retention checks did not independently prove provider emission order. Keep the positive canonical survival assertions and add raw provider-event assertions for preamble -> server result -> continuation.

Lore-id: issue-4505-cursor-chronology

Constraint: preserve the existing 30s timeout and test-only scope

Rejected: canonical persistence order | asynchronous persistence is not the provider chronology contract

Confidence: high

Scope-risk: narrow

Reversibility: easy

Tested: focused file repeated three times and related maintenance suites
Probepark found that membership-only assertions masked both original-anchor retention and a durable order defect. Assert the original anchor is absent from canonical projection and require preamble -> server result -> continuation; the ordered assertion intentionally remains red until separately-owned #4536 lands.

Lore-id: issue-4505-bounded-overlap-4536

Constraint: do not implement issue 4536 in PR 4521

Rejected: unordered membership | masks canonical persistence defect

Confidence: high

Scope-risk: narrow

Reversibility: easy

Tested: T3 reproduces #4536; T2/T4/T5/T7/T8 and related suites pass
Reserve every message_end at the synchronous agent-event boundary and gate canonical append on its predecessor, so a tool-result artifact spill cannot be overtaken by the Cursor continuation. Release the lane before extension delivery and on every failure path.\n\nFixes #4536\n\nLore-id: issue-4536-cursor-canonical-order\n\nConstraint: preserve provider-context spill barriers and raw event chronology\n\nRejected: serialize Agent listeners globally | changes abort and reentrancy semantics\n\nConfidence: high\n\nScope-risk: narrow\n\nReversibility: easy\n\nTested: Cursor T3 repeated; full midrun compaction; pre-admission spill; agent and coding-agent checks
Lore-id: issue-4536-cursor-canonical-order

Constraint: keep release notes scoped to the canonical admission fix

Rejected: omit changelog | violates coding-agent production change contract

Confidence: high

Scope-risk: narrow

Reversibility: easy

Tested: Cursor T3 x3; midrun compaction; pre-admission spill; agent and coding-agent checks
@Yeachan-Heo
Yeachan-Heo force-pushed the fix/issue-4505-canonical-contract branch from 787901e to e28422b Compare August 14, 2026 12:42
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

PR #4521 is refreshed on current dev and the latest Codex blocker is fixed.

Exact-head local verification is green: Cursor T3 passed three consecutive runs; full mid-run compaction 18/18; pre-admission artifact spill 4/4; agent and coding-agent package checks/types passed. The PR body retains exactly one honest needs-human verdict bound to this head/digest.

@probepark 존중을 담아 exact-head 재리뷰를 요청드립니다. 기존 두 assertion blocker와 #4536 production blocker, 그리고 최신 changelog blocker가 모두 반영되었습니다. 검토 후 해결되었다고 판단되시면 exact head e28422b18cf6839cf2ebc99411c26346dde77f7a에 GitHub APPROVED review를 제출해 주십시오. 승인 전에는 merge-approved로 변경하지 않겠습니다.


[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: e28422b18c

ℹ️ 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".

released = true;
settled.resolve();
};
this.#canonicalMessageAdmissions.set(event, { predecessor, release });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep each admission reservation handler-local

When an external bridge or replay emits the same message_end tool-result event object twice before the first spill finishes, this WeakMap.set replaces the first handler's reservation. After its spill, the first handler retrieves the second reservation and waits for the first reservation to release, but its finally also retrieves and releases only the second reservation; both handlers and every later canonical admission therefore remain blocked indefinitely. Capture the reservation in the handler closure, or store multiple reservations per event object, rather than keying the active admission solely by event identity.

Useful? React with 👍 / 👎.

The canonical message admission reservation was keyed by the event
object in a WeakMap, so a host bridge or replay emitting the same
message_end event object twice overwrote the first handler's
reservation. The first handler then awaited the second reservation
while releasing only that same entry, leaving both handlers and every
later canonical admission blocked forever.

The reservation is now returned to and owned by each emission's own
handler closure, and the regression is pinned by a duplicate-emission
settlement test in the pre-admission spill suite.

Lore-id: 0f2a1c3e
Constraint: must not globally serialize Agent listeners or alter raw provider event order
Constraint: canonical Cursor order preamble -> server tool result -> continuation must stay asserted
Rejected: multiple reservations per event object keyed in a WeakMap | handler-local closure removes the shared mutable state entirely
Confidence: high
Scope-risk: narrow
Reversibility: trivial
Tested: duplicate-emission regression red on prior code (timeout) and green after; 58/58 focused/related suites; coding-agent and agent package checks/types/biome
Not-tested: external bridge implementations that emit duplicate events in production traffic
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

Exact-head fix-forward for PR #4521:

  • exact head: e1dd34d3dd030aea774c59c492769567258a8f0c
  • exact base/current dev: e6f8c926dd6f388be8d87868eaeee1afff651b40
  • exact diff SHA-256: b7dd375651ee48a75e68b553235f7879c014f2a71afd5ae74917d2305c5a6d27

The final Codex finding on the prior head is fixed: the canonical admission reservation is now owned by each emission's own handler closure instead of a WeakMap keyed by the event object, so a host bridge or replay emitting the same message_end event object twice can no longer overwrite the reservation and deadlock every later canonical admission. A duplicate-emission regression test pins it (red with a settlement timeout on the prior code, green after the fix).

Exact-head local verification is green: Cursor T3 passed three consecutive runs; mid-run compaction 18/18; spill suite 5/5; cursor-exec-handlers + concurrent 35/35; resident-cache + live-stream 23/23; agent and coding-agent package checks/types/biome passed. The PR body retains exactly one honest needs-human verdict bound to this head/digest.

@probepark @HaD0Yun Authenticated non-author exact-head APPROVED review is requested for e1dd34d3dd030aea774c59c492769567258a8f0c. Prior-head and COMMENTED reviews are stale/neutral.


[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: e1dd34d3dd

ℹ️ 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".

// Only the admission predecessor and this event's own pre-admission work are
// inside the lane; release before extension delivery and unrelated post-work.
if (event.type === "message_end") {
await canonicalAdmission?.predecessor;

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 Preserve message lifecycle order for uncontended admissions

When #flushPendingBackgroundExchanges synchronously emits message_start/message_end pairs for multiple custom messages (agent-session.ts:19274-19281), this unconditional await yields even when the predecessor is already resolved. The next message's start is therefore delivered before the prior message's end, producing start1, start2, end1, end2 for session, SDK, and extension subscribers instead of properly paired lifecycles. Avoid yielding for an uncontended admission, or include the associated lifecycle events in the ordered lane.

Useful? React with 👍 / 👎.

@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 now fixes #4536 instead of just reporting it

Reviewed e1dd34d3d. When I blocked this PR it was test-only and correctly red, because its ordered
assertion reproduced the canonical-ordering defect I filed as #4536. You took the first of the two
options I offered: fold the production fix in.

The fix

-	#handleAgentEvent = async (event: AgentEvent, activePromptHandle?: string): Promise<void> => {
+	#handleAgentEvent = async (
+		event: AgentEvent,
+		activePromptHandle?: string,
+		canonicalAdmission?: { predecessor: Promise<void>; release: () => void },
+	): Promise<void> => {
-		// Canonical persistence must happen synchronously before listener work can await
+		// Canonical persistence follows synchronous message_end reservation order.
+			await canonicalAdmission?.predecessor;
...
+			canonicalAdmission?.release();

A reservation is taken synchronously at emission and the handler awaits its predecessor before the
canonical append, so persistence follows the order the events were emitted rather than the order
their handlers happen to resume. That is the serialization #4536 asked for, and it is placed at the
admission boundary rather than by removing the await that the artifact-spill barrier needs -
which was the constraint that made the naive fix wrong.

Releasing before extension delivery and unrelated post-work keeps the lane narrow; only the
predecessor wait and this event's own pre-admission work are inside it.

It discriminates - checked both directions

# head e1dd34d3d
$ bun test packages/coding-agent/test/agent-session-midrun-compaction.test.ts
 18 pass  0 fail  107 expect() calls

# base e6f8c926d (no canonicalAdmission), with this head's test file applied
673 | expect(canonicalCursorOrder).toEqual(["preamble", "server-result", "continuation"]);
- Expected  - 1
+ Received  + 1
(fail) T3 exercises the Cursor split path without retaining the original usage anchor
 17 pass  1 fail

Same failure signature I reproduced when filing #4536 - the canonical projection was
preamble -> continuation -> server-result. It now passes on the fix and still fails without it, so
the assertion is a live regression guard rather than a snapshot of current behaviour.

The anchor assertion I asked you to restore two rounds ago
(expect(canonicalMessages).not.toContainEqual(originalAnchor!)) is still present and, per my
earlier scratch check, genuinely holds.

Verdict

merge-approved, superseding my merge-blocked. Please close #4536 with this PR - the issue is
fixed here, not merely covered.

Worth noting for the record: this PR started as three unordered .find() calls that reported green
over a real defect, and ends as an ordered assertion plus the fix that makes it pass. That is the
whole argument for not relaxing an assertion to match observed behaviour.

Reviewed by @probepark - method: source read of the canonicalAdmission reservation and release placement, fresh-worktree run at the exact head, base run with the head's test file to confirm the assertion still fails without the fix, independent digest recomputation.

@Yeachan-Heo
Yeachan-Heo merged commit 7538826 into dev Aug 14, 2026
81 of 90 checks passed
@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

PR #4521 is merged to dev at 7538826 (exact merged head e1dd34d, exact base e6f8c92).

Gate evidence at the exact merged head:

  • Authenticated exact-head APPROVED review: @probepark at 2026-08-14T15:49:32Z on e1dd34d.
  • PR body verdict: exactly one gajae.pr-review-verdict.v1 merge-approved line, digest b7dd375651ee48a75e68b553235f7879c014f2a71afd5ae74917d2305c5a6d27, reviewer-id probepark (non-author).
  • PR contract run 31816385190: success.
  • Exact-head Dev CI run 31816382580: success (18 green jobs, 5 platform-skipped, zero failures).
  • Post-merge bun run --cwd=packages/coding-agent build: success; focused suites re-verified on canonical dev (23/23).

Linked issue #4536 is closed with the merge reference. Canonical dev is now 7538826. A merged-commit Dev CI run was cancelled mid-flight by a native-build runner cancellation (rust-cache restore interrupted, not a source failure); failed jobs are being rerun. No release/main mutation occurred.


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

@Yeachan-Heo

Copy link
Copy Markdown
Owner Author

PR #4521 terminal state and post-merge repair handoff:

Merged: PR #4521dev at merge commit 753882632e66e9c4e506667188a8b8d7968176db (exact head e1dd34d3dd030aea774c59c492769567258a8f0c). Issue #4536 closed with the merge reference. Authenticated exact-head APPROVED by @probepark; PR contract run 31816385190 success; exact-head Dev CI 31816382580 success (18 green / 5 skipped / 0 fail).

Post-merge fallout (owned, being fix-forwarded): merged-commit Dev CI shard 4 exposed two deterministic reds introduced by the canonical-admission serialization commits (65128cc, e1dd34d):

  1. agent-session-deep-interview-continuation.test.ts — 4 failures. Root cause: externally emitted agent_end raced its own message_end; the agent_end handler read #lastAssistantMessage before the message_end handler assigned it (assignment sat after the admission wait), so post-turn deep-interview continuation logic double-processed one stop and skipped another.
  2. agent-session-midrun-maintenance.test.ts T2 — outcome pruned vs compacted. Root cause: chronological canonical admission persists seed order, so the oldest orphan tool result now falls outside the protectRecentTurns fence; the old expectation encoded the misordered persistence artifact.

Repair: PR #4565 (branch fix/issue-4536-postmerge-chronological-fallout, exact head 47f0c30816, exact base/current dev 9d2a2d2f2d) captures the terminal assistant synchronously before the admission wait and updates T2 to the chronological contract with strengthened assertions (prune notice present, compaction entry absent). Local: 22/22, 19/19, 18/18, 5/5, 58/58, package check green. Pre-existing local-env red (sixel pet-mode, sdk-workflow-gate-emitter) reproduces identically on the pre-merge base and is out of scope.

Lane ownership continues on #4565 until exact-head product CI is green and an independent exact-head review lands.


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

Yeachan-Heo pushed a commit to grantjayy/gajae-code that referenced this pull request Aug 15, 2026
…mission

The merged Yeachan-Heo#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 Yeachan-Heo#4536
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