Skip to content

fix(compaction): scope legacy checkpoint recognition by era - #7017

Merged
Hmbown merged 2 commits into
codewhale-hq:mainfrom
asto18089:up/era-aware-recompaction
Oct 18, 2026
Merged

Hmbown merged 2 commits into
codewhale-hq:mainfrom
asto18089:up/era-aware-recompaction

Conversation

@asto18089

@asto18089 asto18089 commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

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:

  • A history that contains a stamped carrier recognizes only stamped carriers as checkpoints. 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, so a stampless replacement of a modern history is a dropped receipt even where a retained pasted turn would loosely count as one.
  • 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: /edit or 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.
  • Two fixture-matrix cases (pasted-legacy-header-survives-post-provenance pass / -dropped- fail) run through both the Rust enforcement and the mjs validator (16 fixtures green).
  • cargo test -p codewhale-tui --lib compaction 186 passed / 0 failed; clippy -D warnings clean (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)

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>
@asto18089
asto18089 requested a review from Hmbown as a code owner October 18, 2026 02:06

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@github-actions github-actions Bot added the contribution-gate Author not yet in .github/APPROVED_CONTRIBUTORS; a maintainer grants access with /lgtm label Oct 18, 2026
@Hmbown
Hmbown merged commit 24077dc into codewhale-hq:main Oct 18, 2026
27 of 28 checks passed
Hmbown pushed a commit that referenced this pull request Oct 18, 2026
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
@Hmbown

Hmbown commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

🤖 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 main (e3e5632). A session that has never been compacted has no stamped carrier either, so a pasted legacy header still reads as a checkpoint at the first compaction. SURVIVAL_CONTRACT.md and the history_is_post_provenance doc now say that, instead of "predates stamping". Not in a release yet.

— Written by Claude Opus 5.5 (AI agent) on behalf of the maintainers.

Hmbown pushed a commit that referenced this pull request Oct 18, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contribution-gate Author not yet in .github/APPROVED_CONTRIBUTORS; a maintainer grants access with /lgtm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants