Repository navigation
fix(ccr): strict whole-body parser for stored-placeholder detection - #457
Conversation
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)In your adapter project: npm install acp-kernel@pr-457Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf acp-kernel-pr457.tgz
npm install ./packageThis comment is automatically updated on each push. |
[bot] 🏷 Review complete — approved for merge. Verified on head ① Original issue (direction) — PASSRead ranxianglei/billion-context#1456 in full. Triage there reproduced the bug on the pinned 0.0.95 (all three paths) and correctly located the root cause kernel-side: the detector conflates "text mentions the marker" with "message is a canonical placeholder". This PR fixes the decision point itself (strict whole-body parser), not a symptom filter downstream — right layer. The issue's proposed API ( ② Regression review — existing behavior inventory on touched pathsVerified against pre-change code, not just the diff:
Intended changes (disclosed in PR, confirmed correct): marker-mention-only text and foreign-ref placeholder-shaped text now flow through normal CCR/absorb/archiving instead of being silently skipped (which previously produced dangling advertised refs after fold). No §7.3 kernel-owned contract is touched (no wire format, node ordering, ref semantics, or state schema change). Note: the new public export makes this strictly outside the §7.4 auto-merge gate anyway — human merge is the right path regardless. Round-trip safety proof (the critical regression risk): a strict parser is only as good as its match to the generator. Checked each generator input: ③ Code review — cleanParser (src/ccr.ts:191-229): anchored whole-body grammar, cross-line ref equality enforced, tolerance limited to one leading render tag (reuses existing ④ Test validity — real teeth
⑤ Diff cleanliness — clean3 files, +452/−14, every line serves the fix: Remaining cross-repo step (tracked in billion-context#1456, not this PR): after this merges and CI publishes, bump the pin there and tighten
|
isStoredPlaceholderText used stripLeadingTag(text).includes("[acp-stored"),
which misclassified ANY text merely mentioning the marker — source defining
the constant, docs quoting a placeholder example — as an internal CCR
placeholder. Such content escaped arrival storage (storeLargeResults),
fold-time archiving (storeCoveredOriginals → dangling retrieve-by-ref)
and absorb candidacy (isAbsorbCandidate).
parseStoredPlaceholder() parses ONLY the exact two-line shape emitted by
buildStoredPlaceholder (5-digit zero-padded ref, groupThousands token
count, cross-line ref equality, one trusted leading render tag, optional
trailing newline). Callers that know the message's own ref compare
parsed.ref === ownRef:
- storeLargeResults: skip only self-citing (or unknown-ref) placeholders;
marker-mentioning content stores normally.
- storeCoveredOriginals: skip only self-citing placeholders; foreign-ref
placeholder-shaped bytes store as genuine originals (entries are written
under the hosting message's own ref only, so no fake hit is possible).
- isAbsorbCandidate inherits the fixed detector via isStoredPlaceholderText.
Placeholder wire format unchanged; canonical self-citing placeholders keep
all prior guarantees (#432/#1340 honest miss preserved — the #1340
regression fixture is corrected to be self-citing, which is what CCR
replacement actually emits).
Cross-repo fix for ranxianglei/billion-context#1456 (kernel-side root cause).
ab036f3 to
4814aaa
Compare
What
Replaces the CCR placeholder detector's substring check with a strict whole-body parser, fixing the misclassification of ordinary text that merely mentions
[acp-stored— cross-repo fix for ranxianglei/billion-context#1456 (kernel-side root cause; plan step 1 of that issue).Old:
isStoredPlaceholderText = stripLeadingTag(text).includes("[acp-stored")New:
parseStoredPlaceholder(text)— matches ONLY the exact two-line shape emitted bybuildStoredPlaceholder(📦 line with 5-digit zero-padded ref + groupThousands token count + optional backtick title; retrieve-hint line citing the SAME ref), modulo one trusted leading render tag and one optional trailing newline.isStoredPlaceholderTextis redefined on top of it (public API kept, semantics fixed).Call sites:
storeLargeResultsrefunknown ORparsed.ref === ownRef)storeCoveredOriginalsparsed?.ref === ownRefisAbsorbCandidateBehavior change disclosure (intended)
Ordinary text merely CONTAINING
[acp-stored(source defining the constant, docs quoting a placeholder example, logs) is NO LONGER treated as an internal CCR placeholder:acp_retrieve(ref)missed with no stored original (dangling advertised ref);minToolTokens) and absorb candidacy.Canonical self-citing placeholders: UNCHANGED — still skipped everywhere; the #432/#1340 anti-poisoning guarantee holds (retrieve-by-ref stays an honest miss when the store entry was lost). Placeholder wire format: UNCHANGED.
New public API:
parseStoredPlaceholder()(+ParsedStoredPlaceholdertype), exported for host use — billion-context will tightenfork-adoption.citedPlaceholderRefs()(the host-side fourth instance of the same root-cause family) with it after the pin bump.Test-fixture change (deliberate)
The #1340 regression test fixture cited a FOREIGN ref (
m00099inside messagem00001). CCR replacement always cites the hosting message's OWN ref, so the faithful poisoning fixture is self-citing — corrected tom00001. Under the old over-wide detector both fixtures behaved identically; under the strict detector the foreign-ref case is now correctly archived as a genuine original. A new dedicated test pins both directions, including "the cited foreign ref never gains a fake hit".Evidence
isStoredPlaceholderText=true,storedCount=0, fold-time store empty,retrieveByRefnot-found; canonical control still detected.npm run typecheck,npm test(1168/1168, incl. 9 new regression tests covering all three affected paths + round-trip suite + 12 negative shapes),npm run build,npm run format:check.