Repository navigation
fix(pipeline): discriminate post-fold resends from new instances in reconcile-live-ids (#462) - #463
Conversation
…econcile-live-ids (#462) #459 renumbered every live id whose root was covered, but stateless hosts resend the full raw history every turn, so the folded originals' own echoes carry exactly the covered bare id — renumbering them minted fresh refs and made them escape prune's covered check (baseIdOf strips only "#tail"), so folded content rejoined the wire beside its summary every turn and downstream range anchoring failed (billion-context e2e 502 on 0.0.96). The discriminator is now cross-pass continuity via state.lastPassIds (the previous pass's inbound ids, snapshotted in processTurn): - exact id covered AND present last pass = the folded original's echo → keeps its id; prune drops it and the first-user pin keeps a stable ref - exact id covered AND absent last pass = genuinely new identical instance (#1476) → renumbered past folded-claimed and live-claimed numbers - everything else keeps the converter's numbering - missing snapshot (pre-feature state) = renumber nothing for one pass
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)In your adapter project: npm install acp-kernel@pr-463Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf acp-kernel-pr463.tgz
npm install ./packageThis comment is automatically updated on each push. |
Adds the two regression tests missing from the PR diff: renumber must skip a _k claimed by the previous pass inbound (stale-ref aliasing guard in the while loop), and processTurn must write this pass's inbound ids into state.lastPassIds (the compress.ts hunk was previously only pinned indirectly via the e2e flow).
[bot] 🏷 Review complete — mergeable (human merge, per §7.3/§7.4). Full review below; I also pushed two small fixes directly to the branch (details in ④/⑥). ① Original issue (#462) — direction verifiedRoot cause reproduced against code, not just the report: ② Regression audit — existing behaviors touched
Untouched §7.3 contracts: wire-artifact format, node order (reconcile-live-ids remains first), prompts, protected-tool filtering, tool-pair atomicity. One structural note: Known limitation (already in PR body, agreed): if a host deletes messages from its raw history between passes, a new instance can slide into a covered slot present in ③ Code reviewLogic verified line-by-line: One non-blocking hardening suggestion for a follow-up (semantic change ⇒ your call): when choosing ④ Test validityExisting tests have teeth (assert exact ids/refs across two passes; the bug regression breaks them). Two gaps found and fixed directly on the branch:
Result: 1188/1188 local (Node 22), typecheck + build clean. ⑤ Diff cleanlinessClean: 4 files, all on-topic, no lockfile churn (my local ⑥ CI — was red on the original head, now greenHead Verdict: root cause correctly identified and fixed; all behavior deltas intended and disclosed; residual gaps documented. Ready for you to merge, then release 0.0.97 → billion-context #1488 re-pin. 中文摘要: 修复了 #459 把折叠后重发的原始消息误判为新实例、导致折叠内容绕过 prune 每轮重回 wire 的 P0 问题(用跨轮 |
|
Reviewed the design. The core idea — cross-pass continuity via However, this PR is incomplete as-is: #465 is a strict superset of this PR: same core plus exactly that threading ( Recommendation: close in favor of #465 or #466 rather than layering the threading changes onto this branch. My overall recommendation is #466 (stateless positional replay — no schema growth, no cross-pass id-stability assumption), but that's a maintainer call between the two. |
…ngerprint Replaces #463's cross-pass snapshot (shipped in v0.0.97) with reconcile-live-ids' per-(state,body) positional classification: deterministic, no cross-pass id-stability assumption, and correct on the FIRST pass after any state restore — the snapshot was dropped by mergeCompressionState's field whitelist on every reload, which degraded exactly one pass to 0.0.95 semantics (renumber nothing), re-exposing both #461 and #1476 for that pass. No persisted-state compat concern: the load path never carried the field, so old blobs' stray key was already ignored; adapters never set it directly. Behavior change vs v0.0.97: echo-vs-new-instance discrimination is now structural (rendered-summary presence x covered-base presence) instead of prior-pass membership.
Fixes #462
What changed
reconcileLiveIdsNode(#459) renumbered EVERY live message whose id root was covered, on the assumption that "live id ∈ covered ⇒ new instance". That assumption is wrong for the folded originals themselves: stateless hosts resend the full raw history every turn, so the original re-derives exactly the covered bare id as an ECHO. Renumbering the echo minted a fresh ref and — becauseprunematches viabaseIdOf(strips only#tail, not_n) — let the folded content escape prune and rejoin the wire beside its summary, every turn. On billion-context 0.0.96 this re-inflates the wire and kills downstream range anchoring (tests/e2e/e2e-codex-fake.test.tsoverflow test → preflight 502 → turn lost).The fix: cross-pass continuity
New optional
CompressionState.lastPassIds— exact ids of the previous pass inbound, snapshotted atprocessTurnentry and written into the returned state:lastPassIds→ echo → keeps its id; prune drops it (already summarized) and the first-user pin keeps a stable ref (also stops per-turn ref churn of the pinned message)lastPassIds→ genuinely new identical instance (#1476) → renumbered to the first_kclaimed by neither folded copies nor other live instances of the rootValidation
1186/1186tests,tsc --noEmitclean_1minted, original ref untouched), first-user pinned echo keeps id+ref across post-fold passes, missing-snapshot fallback, renumber skips live-claimed numbers; #1476 e2e now models the real two-pass flow (pass A without the instance → pass B with it)1 !== 0at load turn 4) now passes; fulle2e-codex-fake.test.ts2/26c9dcad(fix: re-mint live ids that collide with a folded copy (billion-context#1476) #459 merge) already failsKnown limitation (follow-up, not blocking)
billion-context preflight resolves advertised range endpoints over the RAW pre-pipeline array; a renumbered new-instance
_1id still will not anchor there in overflow situations. The echo path (the P0) resolves correctly now; the new-instance shape is the rare #1476 case and is documented for a bili-side resolution pass later.Chain: merge this → release 0.0.97 → billion-context #1488 re-pins.