Skip to content

docs: retract an unfounded claim v2.4.1's notes made about v2.3.9 - #431

Merged
doublegate merged 1 commit into
mainfrom
fix/v2.3.9-notes-claim
Aug 20, 2026
Merged

docs: retract an unfounded claim v2.4.1's notes made about v2.3.9#431
doublegate merged 1 commit into
mainfrom
fix/v2.3.9-notes-claim

Conversation

@doublegate

Copy link
Copy Markdown
Owner

v2.3.9's release notes are not wrong. The claim v2.4.1 made about them is, and it was published.

v2.4.1's notes carried a section headed "a claim v2.3.9 made that v2.3.9 did not ship", asserting that v2.3.9's published body described release_anchor_audit.rs while the tag did not contain it.

What v2.3.9 actually says

Under "The release anchors, and two documents that were wrong about more than the version", it says eight documents held six different answers and "All now read v2.3.9." That describes a manual re-synchronisation — and the manual re-synchronisation is in the v2.3.9 tag.

Checked rather than re-asserted: the published body contains no occurrence of release_anchor_audit, "anchor audit", "standing", "pins", "gate", or "15 anchors". Neither does the v2.3.9 CHANGELOG section.

How two true facts made a false one

Both halves stood up separately. The file really is absent from the tag:

$ git cat-file -e v2.3.9:crates/rustynes-test-harness/tests/release_anchor_audit.rs
fatal: path '...' exists on disk, but not in 'v2.3.9'

…and v2.3.9 really is where the anchor drift was found. The step never performed was reading the v2.3.9 body to confirm it claimed the gate. It claimed the fix, which it shipped. A hand correction fixing the instance, followed by a later commit adding the mechanism, is ordinary sequencing — not a release note describing work its tag does not contain.

Why it is retracted in place rather than deleted

The claim was an accusation against a shipped release, published under a heading that made the accusation the section's subject. Deleting it would leave no record that the previous release had been wrongly impugned — the shape of provenance scrubbing this project has a standing rule against. So the section is rewritten to say what is true and to state what it previously said and that it was wrong.

Changed

  • .github/release-notes/v2.4.1.md — section rewritten as "The release anchors, and the gate that arrived after them", with the retraction stated in it.
  • AGENTS.md — carried the same sentence, since the v2.4.1 summary was drafted from it; corrected the same way.

Already applied outside this branch: the published v2.4.1 GitHub release body has been updated from the corrected file, and #430's body now carries the retraction inline, so nothing a reader reaches still asserts it.

Docs only — no source, no manifests. AccuracyCoin and the workspace suites are untouched by construction.

v2.4.1's release notes carried a section headed "a claim v2.3.9 made that
v2.3.9 did not ship", asserting that v2.3.9's published body described
release_anchor_audit.rs while the tag did not contain it. That is false, and it
was published.

What the v2.3.9 body actually says, under the heading "The release anchors, and
two documents that were wrong about more than the version", is that eight
documents held six different answers about the current version and that "All
now read v2.3.9". That describes a MANUAL re-synchronisation, and the manual
re-synchronisation is in the v2.3.9 tag. Checked rather than re-asserted: the
published body contains no occurrence of "release_anchor_audit", "anchor
audit", "standing", "pins", "gate", or "15 anchors", and neither does the
v2.3.9 CHANGELOG section.

Both halves of the original claim were separately true, which is how they
combined into something false. The file really is absent from the tag:

  $ git cat-file -e v2.3.9:crates/rustynes-test-harness/tests/release_anchor_audit.rs
  fatal: path '...' exists on disk, but not in 'v2.3.9'

And v2.3.9 really is where the anchor drift was found. The step that was never
performed was reading the v2.3.9 body to confirm it claimed the gate. It
claimed the fix, which it shipped. A hand correction fixing the instance and a
later commit adding the mechanism is ordinary sequencing, not a release note
describing work its tag does not contain.

The retraction is written into the notes rather than edited out of them. The
claim was an accusation against a shipped release, it was published under a
heading that made the accusation the section's subject, and deleting it would
leave no record that the previous release had been wrongly impugned -- which is
the shape of scrubbing this project has a standing rule against. AGENTS.md
carried the same sentence, since that is where the v2.4.1 summary was drafted
from, and is corrected the same way.

The published GitHub release body for v2.4.1 is updated from this file, so the
repo copy and what users read agree again.
Copilot AI lite review requested due to automatic review settings August 20, 2026 22:48
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8627c0de-8098-484d-bbae-0df840b9104c


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@github-actions

Copy link
Copy Markdown

Antigravity review (Gemini via Ultra)

This PR updates the v2.4.1 release notes and AGENTS.md to retract the inaccurate claim that v2.3.9's release notes described an automated audit mechanism not present in its tag, clarifying that v2.3.9 only claimed a manual correction.

Blocking issues

None found.

Suggestions

  • AGENTS.md: The v2.4.1 "Fabric" section is an enormous wall of text (over 100 lines without a single paragraph break). While this PR only modifies a few sentences within it, consider breaking this block into smaller, readable paragraphs.

Nitpicks

  • AGENTS.md: You used fully capitalized BY HAND for emphasis. The corresponding change in .github/release-notes/v2.4.1.md uses markdown bold (**by hand**). Consider using **by hand** in AGENTS.md as well to match the surrounding style.

Automated first-pass review by agy on a self-hosted runner -- not a human review.

@doublegate
doublegate merged commit 3776610 into main Aug 20, 2026
18 of 19 checks passed
@doublegate
doublegate deleted the fix/v2.3.9-notes-claim branch August 20, 2026 22:51
doublegate added a commit that referenced this pull request Aug 20, 2026
…432)

#431 retracted the claim. This records the cause, because the instance is the
least interesting part of it.

Both inputs to the false statement were real and each had been checked
independently: release_anchor_audit.rs genuinely is absent from the v2.3.9 tag,
and v2.3.9 genuinely is where the anchor drift was found. What was never
checked was the conjunction -- that v2.3.9's release body therefore DESCRIBED
the audit -- and checking it was one command:

  gh release view v2.3.9 --json body

That body says the eight drifted documents "All now read v2.3.9", a manual
re-synchronisation which is in its tag, and contains no occurrence of
"release_anchor_audit", "standing", "gate", or "15 anchors". Verifying every
premise is not verifying the conclusion drawn from them.

Two propagation mechanisms matter more than the instance, and the bullet names
both.

The sentence was written into AGENTS.md during the v2.4.0 work, and the v2.4.1
release summary was then drafted FROM AGENTS.md. That is the laundering step:
an unverified claim entering this file is indistinguishable from a verified one
by the time the next release quotes it, and it then reaches a published release
body, a commit body, a PR body and a report to the maintainer in a single pass.
AGENTS.md is a notes file, not an oracle, and this is the first entry that says
so about itself.

The claim also had the shape this project rewards -- a recursive irony, "the
same failure one level up". That shape actively suppresses the check, because
it reads as an insight rather than as an assertion needing evidence. The
house style's appetite for findings of that form is exactly why it needs a
verification bar rather than less of one.

The bar stated: before writing that a document, release, commit or person SAYS
something, open it and grep for the words.

Nothing else changes -- one bullet, inserted beside the sibling traps it
belongs with (the reviewer-claim bullet it now precedes is the same failure
with a different source).
doublegate added a commit that referenced this pull request Aug 22, 2026
* chore(release): cut v2.4.2 "Cairn" -- the rung-0 compare surface

Bumps the workspace to 2.4.2, promotes the `[Unreleased]` CHANGELOG content into
a dated section, moves all 15 release anchors across 10 documents, and adds the
maintainer-authored release-notes override that `release-auto.yml` prefers over
the CHANGELOG extract.

The release itself is scaffolding for the v2.4.1 -> v2.5.0 "Fabric" line. The
emulation core is untouched -- no behaviour change to
rustynes-{cpu,ppu,apu,mappers,core}, no new hot-path API, and rustynes-cosim
stays excluded from the workspace and absent from the default build.

## Why "Cairn"

A cairn is a marker set along a route so you can tell you are still on it. That
is what a rolling per-cycle hash checkpoint is, and the release's subject is
building that compare surface: 89,343 CPU cycles of AccuracyCoin is 5,372,427
bytes of irq.csv against 352 bytes of ckpt.bin, a factor of 15,263, so the first
mismatch names a 4096-cycle window and only that window is re-run with full
capture.

## What this commit contains

* Cargo.toml `[workspace.package] version` 2.4.1 -> 2.4.2, and the Cargo.lock
  propagation across the ten workspace members that inherit it.
* CHANGELOG.md: `## [Unreleased]` stays permanent and empty at the top; its
  content moves under
  `## [2.4.2] - 2026-08-22 - "Cairn" (checkpoints, and what a device can actually
  observe)`. The header is verified to parse the way release-auto.yml parses it
  -- the ` - YYYY-MM-DD - ` prefix, a quoted codename, then a parenthesised
  theme -- since a malformed header degrades the published release title.
* The 15 anchors in README.md (badge + Current Release), docs/STATUS.md,
  AGENTS.md (x3, including the never-claim-a-later-version guard),
  VERSION-PLAN.md, to-dos/ROADMAP.md, SUPPORT.md, SECURITY.md, ROADMAP.md (x2),
  OVERVIEW.md (x3) and ARCHITECTURE.md. Each demotes the v2.4.1 text to "built
  on" rather than overwriting it, so the release chain stays readable.
* VERSION-PLAN.md gains a v2.4.2 row and `(current)` moves off v2.4.1;
  `the_version_plan_table_marks_exactly_the_current_release` checks this.
* .github/release-notes/v2.4.2.md, 198 lines.

## Two gates earned their place, both failing first

`release_anchor_audit` FAILED CLOSED on a defect this commit introduced. The
VERSION-PLAN edit produced `**Current release: **v2.4.2` -- a doubled bold marker
-- so the pinned marker `**Current release: v` no longer matched, and the audit
refused to report a pass for an anchor it could not find rather than silently
checking 14 of 15. That is the exact failure mode it was written after.

`cosim_manifest_audit` then caught the price of exclusion that AGENTS.md
documents: an excluded package cannot use `version.workspace = true`, so
crates/rustynes-cosim/Cargo.toml still said 2.4.1 after the workspace moved. Its
message says so directly -- "the crate is excluded, so nothing inherits this for
you". Bumped, and its own tracked lockfile regenerated.

`libretro_info_audit` required the LOCAL rustynes_libretro.info display_version
to move with the workspace. Bumped to v2.4.2. NO upstream PR is opened: the
cadence rule limits upstream syncs to vX.Y.0 boundaries (next: v2.5.0) and no
licence changed here, which is the one override. Keeping the local file current
is what makes that eventual sync a copy rather than a re-derivation.

## On v2.4.0, which is deliberately not tagged

Checked rather than assumed. The workspace version was NEVER 2.4.0 on any commit
on any branch -- `git log --all -S'version = "2.4.0"' -- Cargo.toml` is empty,
and PR #428's merge commit b67c4f9 still reads 2.3.9. There is also no
`## [2.4.0]` CHANGELOG section, so release-auto would fail loudly by design
rather than ship empty notes.

So no commit exists that a v2.4.0 tag could honestly point at: every candidate's
own manifest announces a different version. v2.4.0 "Concordance" shipped inside
v2.4.1, which that release's notes and VERSION-PLAN.md both record. A skipped
version number is permitted by SemVer; a tag pointing at a tree that calls itself
something else is not honest, and retroactively contradicting a shipped
release's notes is the same class of record corruption as the v2.3.9 claim this
project retracted in #431. The release notes state this explicitly so the
question is answered where a reader will ask it.

## Verification

* AccuracyCoin 141/141 (100.00%, RAM decoder) and nestest 0-diff -- run, not
  assumed, even though the core is untouched by this commit.
* release_anchor_audit: 8/8 (after the doubled-marker fix).
* cosim_manifest_audit: 4/4. libretro_info_audit: 3/3.
* cargo fmt --all --check: clean.
* markdownlint via pre-commit (pinned v0.39.0, --files not --all-files): Passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj

* docs: address the review -- and one finding is an arithmetic error, not a nit

Six CodeRabbit findings, every one verified against the code or the file before
being acted on rather than accepted on plausibility. All six were real.

## The one that matters: 244 KB is wrong by about 2x

The extrapolated checkpoint size has been 244 KB since the Fabric plan, and it
does not survive its own measurement:

  ENCODED_LEN                                  16 bytes
  measured                     89,343 cycles -> 352 bytes ckpt.bin
  352 / (89343/4096)                           16.1 bytes per checkpoint
  125,000,000 / 4096 * 16                      477 KB
  125,000,000 / 89,343 * 352                   481 KB
  244 KB  ==  30,518 * 8                       an 8-BYTE record

244 KB is what you get from a checkpoint holding only the hash. The implemented
record holds the cycle AND the hash, so the figure predates the implementation
and nobody re-derived it. The 15,263x ratio is measured and unaffected; only the
absolute extrapolation was wrong.

Corrected in the live spec documents -- AGENTS.md (both occurrences),
docs/mister.md, to-dos/ROADMAP.md -- and explained in the v2.4.2 notes, which is
where a reader meets the number.

DELIBERATELY NOT corrected: .github/release-notes/v2.4.1.md (a shipped record is
not silently rewritten), docs/adr/0037 (a decision record), and the research
archive under to-dos/plans/research/. The v2.4.2 notes carry a block naming all
three, so the correction is discoverable from the wrong number rather than only
from the right one.

## The other five

* The obs.bin record count is 89,335 against 89,343 cycles, and the gap is
  exactly the eight-cycle reset `Nes::from_rom` runs before the trace is armed.
  Nothing is filtered. Both counts appear in the notes and the boundary between
  them did not; it does now.
* The stream-length check was attributed to `Observable::decode`, which
  validates ONE 16-byte record. `observables_from_bytes` is what rejects a
  stream whose length is not a multiple of 16 (checkpoint.rs:302), before any
  record is decoded. Reattributed.
* "No public-API change" was unqualified while rustynes-cosim adds public Rust
  and C ABI surface. True for every shipped and default-build package, and now
  says so.
* SECURITY.md declared v2.4.2 current in its prose while its table still labelled
  2.3.x "The current line" with no 2.4.x row at all -- so the supported-version
  table, which is the part a reporter actually reads, named the wrong line. Adds
  a 2.4.x row and moves 2.3.x to Partial.
* to-dos/ROADMAP.md carried three stale status markers, two of them actively
  misleading rather than merely old: line 59 announced "Next up -- v2.4.0
  Concordance" for a release that shipped inside v2.4.1 and is deliberately
  never tagged, and line 100 stated v2.2.6 "Almanac" as the latest release,
  eleven releases behind. Line 84 still read "In development -- the v2.0.0 tag
  itself" for a tag pushed on 2026-07-03. Corrected, with 100 and 84 relabelled
  as historical snapshots rather than deleted.

That line-59 finding is worth naming: the same commit that documents why v2.4.0
has no tag left a bullet elsewhere in the tree announcing it as the next
release. The release anchors are gated; ordinary status prose is not.

## Verification

* release_anchor_audit 8/8, cosim_manifest_audit 4/4, libretro_info_audit 3/3.
* markdownlint via pre-commit (pinned v0.39.0): Passed.
* No emulation-core change; AccuracyCoin 141/141 (RAM decoder) and nestest
  0-diff already verified on this branch and unaffected by a documentation edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj

* test(release): gate ordinary status prose, not just the pinned anchors

`release_anchor_audit` pins 15 fixed markers and fails closed when one goes
missing. That is the right shape for THE canonical current-release statement in
each document, and it is why a doubled bold marker on this very cut failed
loudly instead of silently checking 14 of 15.

It cannot cover prose that has no marker, and the review round found that **the
drift did not stop when the anchors were gated -- it moved into the prose beside
them**:

* `to-dos/ROADMAP.md` announced a "Next up" for v2.4.0, a release that shipped
  inside v2.4.1 and is deliberately never tagged -- in the very change that
  documents why it has no tag,
* the same file still described the v2.0.0 tag as in development, for a tag
  pushed 2026-07-03,
* and `to-dos/README.md` described v1.8.9 the same way, roughly fifteen releases
  stale, which nothing had flagged at all and which the review did not find
  either. The gate did.

So this is a PATTERN check rather than a marker list: a status label (`Next up`,
`In development`, `Planned for`, `Upcoming`) naming a version at or below the
workspace version is a contradiction that needs no judgement to detect.

## Discovery needs no list of its own

`git ls-files` intersected with `.markdownlintignore`. Tracked files ARE the
definition of this project's own content -- the vendored `nesdev_wiki/` beside
this checkout is 2,655 untracked markdown files, and a first draft that walked
the directory tree examined 3,085 files instead of 225. The frozen-tree list is
READ from `.markdownlintignore` rather than duplicated, because a second copy of
"which prose is not policed" is precisely the drift this file exists to catch.

## A companion rule was measured and REJECTED

"A `latest release` or `the current line` claim must name the workspace version"
fires on `docs/ios.md`, which correctly says "The current line is v1.9.9
'Workshop'" -- scoped to the iOS TRAIN, not the project release. The phrase
legitimately scopes to a platform line, so the rule cannot separate a stale claim
from a correct one without judgement.

A gate with false positives gets switched off, which is worse than no gate --
the same sentence already written into `check_rtl_subset.py`. Recorded as a
measured rejection in the module docs rather than shipped and tuned.

## Mutation testing changed the design, twice

The escape hatch was first "any line containing the word historical". The very
first line written against it -- the `to-dos/README.md` fix -- said "this
paragraph is a historical snapshot" for unrelated reasons, so M1, the mutation
reintroducing the exact defect the gate exists for, came back **NOT CAUGHT**:
silently exempted by the prose beside it. An escape claimable by accident fails
in the direction of silence, which is the worst direction.

The marker became an HTML comment. Then the gate failed on its own CHANGELOG
entry, because documenting the defect requires QUOTING it -- the same recursion
that once made a commit body explaining the `Closes #N` anti-pattern close an
issue. A quotation is not a historical snapshot, so the marker is named
`not-a-claim`: it says the line is not asserting state, which is true of both
cases. Five such lines exist, all quotations, all printed and counted on every
run so growth stays visible.

Five mutations, all behaving:

  M1  bare label on a shipped version                    FAIL (caught)
  M1b same line, word "historical" incidentally present  FAIL (the loose escape no longer rescues it)
  M4b explicit `not-a-claim` marker                      PASS (exempts, on purpose only)
  M3  label on a FUTURE version                          PASS (not yet shipped)
  M6  predicate inverted, defect present                 PASS (gate inert -- the comparison is load-bearing)

Plus fail-closed on an unparseable `.markdownlintignore` and on a short file
list, since zero files examined means the discovery is wrong rather than that
every document is consistent.

## Also

* `to-dos/README.md` corrected -- v1.8.9 shipped 2026-06-25.
* Three unit tests pin the version parser, the 60-character window, and that the
  scanner does not panic on a multi-byte line. That last one is not decorative:
  these documents are full of em-dashes, and a byte-slicing implementation
  panics while formatting its own diagnostic, replacing the message explaining
  the failure with a char-boundary error about the reporting code.

## Verification

* release_state_prose_audit 4/4, release_anchor_audit 8/8,
  cosim_manifest_audit 4/4, libretro_info_audit 3/3.
* `cargo fmt --all --check` clean; `cargo clippy -p rustynes-test-harness
  --all-targets -- -D warnings` clean.
* markdownlint via pre-commit (pinned v0.39.0): Passed.
* 225 tracked, non-frozen markdown files examined; 5 exemptions, all listed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants