Repository navigation
fix(compaction): scope legacy checkpoint recognition by era - #7017
Conversation
The restore lane already prefers the provenance-stamped carrier, but the recompaction family still ran the loose predicate, which matches any user turn whose text merely starts with a legacy summary header. In a history that carries the stamped carrier that misread silently drops the turn: last-round anchoring walks past it, old-turn retention skips it, and the coverage floor classifies user prompts through the same loose predicate so it cannot catch the loss. The survival contract meanwhile counts the retained turn as a duplicated summary, so a replacement that does keep the turn fails closed. Recognition in the recompaction family is now era-scoped through history_is_post_provenance: a history that contains a stamped carrier recognizes only stamped carriers as checkpoints, so a pasted bare-header turn anchors the round, is retained verbatim, and does not count as a duplicated summary. A history without a stamped carrier predates the stamp — there the pasted header is indistinguishable from the saved bare carrier, so the loose form keeps applying, now pinned explicitly. The receipt count reads the replacement in its own era, except that a post-provenance original raises the bar to a stamped carrier: the engine stamps every replacement it builds, and the stamp is the only form request rewriting relocates. Retention derives the era from the history the slice belongs to, not the slice: the pre-round prefix's carrier may sit inside the round. The /context inspector's last-round heuristic reads the same era-aware anchoring. validate_survival_contract.mjs mirrors the era rule and the fixture matrix gains the pasted-header pass/fail pair; SURVIVAL_CONTRACT.md documents the raised receipt bar and the era signal (the history's content, not the session's age — one-way and destructible). Pinned by the pasted-turn survival/retention tests, the legacy bare-header boundary test, and the two new fixture-matrix cases. Signed-off-by: asto <asto18089@126.com>
Maintainer follow-ups from the review of three merged contributor PRs from @asto18089. #7014 (Claude 5 sampling gate): the "never send both" assertion sat after the older-model loop, so it checked the first claude-opus-4-8 body, which never carries top_p, and could not catch a regression. It now runs inside the loop for each 4.x model, and a top_p-only request is checked to pass through, as the PR body described. #7015 (Kimi empty `items` repair): once an empty `items` is dropped, a required array with minItems >= 1 still failed mfjs_schema_can_terminate with InvalidSchemaNode, so that tool was still excluded. MFJS allows `items` to be absent, and an unconstrained array can always be satisfied, so absent `items` now counts as terminating. #7017 (era-scoped checkpoint recognition): the docs said an unstamped history "predates stamping". A session that has never been compacted has no stamped carrier either, so a pasted legacy header still reads as a checkpoint at a session's first compaction. SURVIVAL_CONTRACT.md and the history_is_post_provenance doc now state that limit. Refs #7014 Refs #7015 Refs #7017 Verified: scripts/dev-test.sh tui body_drops_sampling schema_sanitize moonshot kimi compaction: 355 run, 355 passed (includes body_drops_sampling_params_for_models_that_reject_them and 141 kimi/moonshot tests). validate_survival_contract.mjs: ok 17 fixtures. cargo fmt --check clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
|
🤖 This reply is from Claude Opus 5.5, an AI agent working on behalf of the Codewhale maintainers. It is posted through @Hmbown's account, but Hunter did not write it. Merged in 24077dc. Thank you @asto18089. The era rule closes a real gap: in a history that already has a stamped carrier, a pasted Codex handoff could no longer anchor the round, and the duplicate-summary count treated it as a second summary. Your matrix cases show both. One doc follow-up on — Written by Claude Opus 5.5 (AI agent) on behalf of the maintainers. |
Adds [Unreleased] entries for #7014, #7015, #7017, #7018, #7019 and #7020, crediting @asto18089 (and @zhuowp for the fork ports). Each merged without a changelog line. The entry for #7020 names its behavior change: the app-server's legacy [providers.custom] table now refuses a non-Chat wire with provider_wire_format_unsupported instead of forwarding a Chat body. Refs #7014 Refs #7015 Refs #7017 Refs #7018 Refs #7019 Refs #7020 Refs #6997 Verified: sync-changelog --check up to date; web check-facts OK; check-contributor-credit "Every contributor in the window is credited on all three surfaces". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
What
The restore lane already prefers the provenance-stamped compaction carrier, but the recompaction family still ran the loose predicate, which matches any user turn whose text merely starts with a legacy summary header. In a history that carries the stamped carrier, that misread silently drops the turn: last-round anchoring walks past it, old-turn retention skips it, and the coverage floor classifies user prompts through the same loose predicate, so it cannot catch the loss. The survival contract meanwhile counts the retained turn as a duplicated summary, so a replacement that does keep the turn fails closed — fixing the drop alone would have made every such rewrite refuse.
Checkpoint recognition in the recompaction family is now era-scoped through
history_is_post_provenance:/contextinspector's last-round heuristic reads the same era-aware anchoring.validate_survival_contract.mjsmirrors the era rule and the fixture matrix gains the pasted-header pass/fail pair;SURVIVAL_CONTRACT.mddocuments the raised receipt bar and the era signal (the history's content, not the session's age — one-way and destructible:/editor a host rewind can truncate away the only stamped carrier).Tests
pasted_legacy_header_turn_is_content_in_a_post_provenance_history— the pasted turn anchors the round, is retained verbatim, a replacement keeping it validates with exactly one receipt, and dropping it fails the coverage floor.legacy_history_still_recognizes_a_bare_header_checkpoint— the legacy-era boundary both ways.pasted-legacy-header-survives-post-provenancepass /-dropped-fail) run through both the Rust enforcement and the mjs validator (16 fixtures green).cargo test -p codewhale-tui --lib compaction186 passed / 0 failed; clippy-D warningsclean (lib).Ported from the Pinvou/CodeWhale fork (#103), rescoped to the recompaction family: upstream's wire-only edit targeting and restore preference are already stricter than the era result there, so those lanes are untouched.
No-Issue: recompaction dropped a pasted legacy-header user turn in a history with a stamped checkpoint (port of fork PR #103)