Repository navigation
Revert "fix: reclaim dead message refs, reuse exhausted capacity (#176)" — ref slot reuse is unsafe - #191
Conversation
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)In your adapter project: npm install acp-kernel@pr-191Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf acp-kernel-pr191.tgz
npm install ./packageThis comment is automatically updated on each push. |
[bot] 🏷 Agent review 1/2 — VERIFIED ✅ (LGTM to merge) I checked out the PR commit ( Revert correctness (this is the load-bearing question for a revert)
CI gates (all green on the PR commit, real Node v22)
Safety argument — I agree, and here's why there's no cheaper fixConfirmed the mechanism in code: Accepted trade-off — accurately characterizedConfirmed One heads-up for the follow-up REF_WIDTH PR (non-blocking here)Widening 5→7 digits changes the tag format width. Any host-side parsing that assumes a fixed Verdict: clean, complete, well-scoped revert; all CI gates green; no regressions. Approving as agent review 1/2. |
The monotonic ref map bricks sessions at m99999: refs are additive (sync.ts), the cursor restarts at highestUsedIndex+1, and hosts that pass the full log die on the FIRST turn after a restart. #191 named widening REF_WIDTH as the proper fix; this is it, hybrid-style: - indices ≤ 99,999 render byte-identical (5-digit zero-padded, the REF_WIDTH floor); padStart is a no-op above it, so m100000…m9999999 widen naturally. Zero bytes change for sessions under the old cap. - REF_PATTERN and boundaries' MESSAGE_REF_PATTERN widen to {1,7}; leading-zero tolerance preserved (m1 ≡ m00001). - CCR placeholder grammar accepts CANONICAL shapes only (5-digit padded | natural width ≥ 100000, never leading-zero): m100000 placeholders round-trip while near-example prose like "m004234" stays rejected (#1456 firewall intact). Fixes #483
Reverts merge commit 4d0b61f (PR #176, released in 0.0.48/0.0.49).
Why revert
PR #176 introduced ref slot recycling: prune
byRaw/byReftoview ∪ active-block effectiveMessageIdseach turn, plus two reuse paths (wrap-around scan from MIN_INDEX after forward exhaustion; cursor drop viahighestUsedIndex(pruned)+1). Maintenance review judged this design unsafe and it contradicts the architecture's own "GC-free" key design principle:effectiveMessageIdskeeps only anchor ids (observed: a 7-message folded range retained 2). Summary text cites tags (mNNNNN) whose raw ids are NOT anchors and NOT in view → their mappings get pruned → slot freed → a later message reuses the slot → the model decompresses the old tag and receives the WRONG message's content, silently. Wrong content is strictly worse than an error.highestUsedIndex+1was monotonic and slots were never reused; the model could trust any tag it has ever seen. fix: reclaim dead message refs, reuse exhausted capacity, classify boundary failures (billion-context#386) #176 breaks that trust contract for every host.Accepted trade-off
The original #386 leak (monotonic growth toward the 99999 cap →
allocateFreeRefthrow → host-side silent stall) is REOPENED by this revert. That is accepted for now; the proper fix is wideningREF_WIDTH(5→7 digits) so monotonic growth can never reach the cap — proposed separately.Impact
acp-kernel@0.0.47(predates fix: reclaim dead message refs, reuse exhausted capacity, classify boundary failures (billion-context#386) #176) — unaffected today; this revert protects the next bump.pruneDeadRefsor reuse semantics (checked billion-context, billion-context-pi).Verification
npm run typecheck✓npm test558/558 ✓grep -rn pruneDeadRefs src/ tests/→ empty; refs.ts wrap-around removedMerge needs 2-agent review per AGENTS.md; human merges.