Skip to content

feat(harness): pin Load Block's inclusive texel count against Angrylion - #184

Merged
doublegate merged 3 commits into
mainfrom
fix/load-block-count
Jul 29, 2026
Merged

feat(harness): pin Load Block's inclusive texel count against Angrylion#184
doublegate merged 3 commits into
mainfrom
fix/load-block-count

Conversation

@doublegate

Copy link
Copy Markdown
Owner

First Load Block coverage, and a settled ambiguity

Load Block (0x33) had zero vector coverage — every texture vector loaded
through Load Tile — while Ocarina of Time issues 4,374 Load Blocks of its
74,508 commands. Dominant load path in a live retail stream, entirely unpinned.

The ambiguity

§0x33's prose says "lower_right.s - upper_left.s determines the number of
texels"
no +1 — while Load Tile is inclusive and load_block computes
shi - slo + 1. The two readings genuinely disagree, and prose cannot decide it.

A minimal vector can

load_block_count_16 uses uls = 0, lrs = 1 — a load of either one texel or
two — on a single line with dxt = 0.

That minimality is the whole design. Two earlier, larger Load Block vectors were
authored and discarded because their goldens showed Angrylion reading unwritten
TMEM; the fix was to remove layout from the experiment rather than keep guessing
at it. With one line, two texels and no dxt, neither the odd-line swap nor any
multi-line TMEM arrangement can confound the answer.

Angrylion loads two. The count is inclusive, shi - slo + 1 is correct,
and RustyN64 matches the golden byte-for-byte.

  • Mutation-checked: dropping the +1 turns it red.
  • Battery is now 52 probes (39 RDP + 13 VI).

What this does not claim

Load Block is no longer wholly unpinned, but the coverage is minimal by
construction
. Still untested on this path:

  • multi-line loads,
  • the odd-line 32-bit word swap under a real dxt,
  • non-16-bit texel sizes.

The ledger says so explicitly rather than implying the command is now covered —
one narrow vector is not coverage of a command, and recording it as such is how
the next person avoids assuming otherwise.

Net effect on R-18

The leading Load Block hypothesis joins the others as refuted. R-18's video
cause remains open, and the honest position is that four suspects have now been
eliminated by oracle rather than by argument.

Gates

cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings,
cargo test --workspace, RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps, pre-commit run markdownlint --all-files — each run separately, exit
status checked.

Oracle: no emulation behaviour change (a new vector + docs), so n64-systemtest
is unchanged at 90 suite-wide, Phase 1 Failed: 0, per docs/STATUS.md.

🤖 Generated with Claude Code

…on (R-18)

Load Block (0x33) had zero vector coverage - every texture vector loaded through
Load Tile - while Ocarina issues 4,374 Load Blocks of its 74,508 commands. It was
the dominant load path in a live retail stream and entirely unpinned.

The open question was the texel count. 0x33's prose says "lower_right.s -
upper_left.s determines the number of texels" with no +1, while Load Tile is
inclusive and load_block computes shi - slo + 1. The two readings disagree and
prose cannot settle it.

A minimal vector can. load_block_count_16 uses uls=0, lrs=1 - a load of either
one texel or two - on a single line with dxt=0, so neither the odd-line swap nor
any multi-line TMEM layout can confound the answer. That minimality is the point:
two earlier, larger Load Block vectors were authored and discarded because their
goldens showed Angrylion reading unwritten TMEM, and the fix was to remove
layout from the experiment rather than to keep guessing at it.

Angrylion loads two. The count is inclusive, our shi - slo + 1 is correct, and
RustyN64 matches the golden byte-for-byte. Mutation-checked: dropping the +1
turns it red. Battery is 52 probes (39 RDP + 13 VI).

So the leading Load Block hypothesis joins the others as refuted. The path is no
longer wholly unpinned, but the coverage is minimal by construction - multi-line
loads, the odd-line swap under a real dxt, and non-16-bit texel sizes all remain
untested, and the ledger says so rather than implying the command is now covered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@doublegate, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0f104d0e-170c-4a60-875b-aa256217ad87

📥 Commits

Reviewing files that changed from the base of the PR and between 27ace5b and 11033f4.

📒 Files selected for processing (2)
  • crates/rustyn64-test-harness/vectors-gen/driver.c
  • docs/STATUS.md
📝 Walkthrough

Walkthrough

Adds an Angrylion golden vector and replay test for 16-bit Load Block inclusive texel counting, registers it in the conformance battery, and updates coverage documentation and the R-18 accuracy-ledger entry.

Changes

Load Block oracle coverage

Layer / File(s) Summary
Generate the Load Block probe
crates/rustyn64-test-harness/vectors-gen/driver.c
Adds a minimal two-texel 16-bit probe and emits the load_block_count_16 golden vector.
Integrate and replay the vector
crates/rustyn64-test-harness/src/conformance.rs, crates/rustyn64-test-harness/tests/rdp_conformance.rs, crates/rustyn64-test-harness/tests/vectors/load_block_count_16.rvec
Registers the RVEC payload and verifies the replayed framebuffer against the Angrylion golden.
Record coverage status
CHANGELOG.md, docs/STATUS.md, docs/accuracy-ledger.md
Documents inclusive texel counting, updates probe totals to 52, and revises accuracy-ledger entry R-18.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 10
✅ Passed checks (10 passed)
Check name Status Explanation
Title check ✅ Passed The Conventional Commit format is correct, and the title matches the new Load Block oracle coverage.
Description check ✅ Passed The description is on-topic and matches the new Load Block coverage, docs, and vector harness changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Oracle Number Is Stated ✅ Passed PASS: this is docs/vector coverage only, and docs/STATUS.md states n64-systemtest is 90 suite-wide with Phase-1 Failed: 0.
Docs-As-Spec Sync ✅ Passed PASS: the diff only touches test harness/docs (plus R-18/STATUS ledger lines); no rustyn64-{cpu,rsp,rdp,audio,cart,core} code changed, so no subsystem docs sync was required.
Changelog Entry For User-Visible Changes ✅ Passed PASS: CHANGELOG.md has an [Unreleased] Added entry for the new Load Block oracle coverage, which satisfies the user-visible-change rule.
Measured, Never Tuned ✅ Passed PASS: no model constant/timing changed; the new Load Block figures are test inputs, and R-18 is ledgered with measurement provenance and N64brew citations.
Unsafe Stays Out Of The Chip Crates ✅ Passed PASS: no touched Rust file adds unsafe; core/chip crates still have #![forbid(unsafe_code)], and the only unsafe hits are existing prose comments, not code.

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/STATUS.md`:
- Line 257: Regenerate the page-wide STATUS metrics from the current test run:
update the stale “passes 712 tests” claim near the test-count summary to include
the newly added load_block_count_16_matches_angrylion test, and revise the
paragraph after the accuracy table to reflect that the accuracy battery is
available and passes 100% (52/52), matching the table.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 17186546-0ad1-4a8f-9495-9f4f6cab4e13

📥 Commits

Reviewing files that changed from the base of the PR and between b39205f and 27ace5b.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • crates/rustyn64-test-harness/src/conformance.rs
  • crates/rustyn64-test-harness/tests/rdp_conformance.rs
  • crates/rustyn64-test-harness/tests/vectors/load_block_count_16.rvec
  • crates/rustyn64-test-harness/vectors-gen/driver.c
  • docs/STATUS.md
  • docs/accuracy-ledger.md

Comment thread docs/STATUS.md
… length

Review follow-up, both suggestions adopted.

TEX_BLOCK_COUNT read like a quantity while holding texel colours; it is now
TEX_BLOCK_COUNT_TEXELS. The vector is about a COUNT question, which made the old
name actively misleading next to the lrs/uls fields it sits beside.

The preload length is now sizeof(...) / sizeof(uint16_t) rather than a literal 2,
so it cannot drift if the array changes. Note the divisor is load-bearing: the
field is a texel count, not a byte count, so a bare sizeof would declare twice
the payload - which is why I rejected the same suggestion in its unqualified form
on #182. Here it was offered correctly.

The other 20 vectors still pass literals. Not swept in this PR: that is a
mechanical change across the whole generator and would bury a one-vector fix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@doublegate

Copy link
Copy Markdown
Owner Author

Both Antigravity suggestions adopted.

TEX_BLOCK_COUNT names a quantity but holds colours. Now TEX_BLOCK_COUNT_TEXELS. The name mattered more than usual here because this vector is about a count question and sits next to the lrs/uls fields — the old name read like it was one of them.

Hardcoded 2 for the preload length. Now sizeof(TEX_BLOCK_COUNT_TEXELS) / sizeof(uint16_t), so it cannot drift if the array changes.

Worth flagging the difference from #182, where I rejected what looked like the same suggestion: there it was offered as bare sizeof(...), which would have declared 24 bytes for a 12-texel array and doubled the payload — the field is a texel count, not a byte count. With the / sizeof(uint16_t) divisor it is correct, and strictly better than a literal.

The other 20 vectors still pass literals. Deliberately not swept here: that is a mechanical change across the whole generator and would bury a one-vector fix in it.

…xecuted

Two stale claims in the file that is meant to be the single source of truth for
current numbers.

The test count said 712. The actual figure from cargo test --workspace is 803, so
it had been stale across many PRs rather than by the one this branch adds - the
review flagged it as off by one, and it was off by 91.

The corpus paragraph still listed the accuracy battery among the oracles that are
"staged only - an oracle on disk that no gate executes yet", directly
contradicting both the 100% (52/52) row in the table above it and the line that
says the probe battery is now real. The battery does execute; only the real-ROM
visual goldens and the commercial ROMs remain staged, and the sentence now says
that.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Antigravity review (Gemini via Ultra)

This PR adds a minimal 16-bit single-line conformance vector (load_block_count_16) to pin the RDP Load Block (0x33) texel count as inclusive (lrs - uls + 1) against Angrylion, and updates harness tests and project documentation accordingly.

Blocking issues

None found.

Suggestions

  • crates/rustyn64-test-harness/vectors-gen/driver.c (lines 1217-1218): TEX_BLOCK_COUNT_TEXELS is declared as a module-level static array, whereas other vector definitions keep their arrays local or alongside their vector structs. Keep definition scoping consistent in driver.c to prevent top-level namespace pollution as new vectors are added.
  • crates/rustyn64-test-harness/tests/rdp_conformance.rs (lines 108-122): The doc comment heavily duplicates prose from CHANGELOG.md and docs/accuracy-ledger.md. Reduce doc comment verbosity on unit tests to avoid text drift across documentation locations when test harness details are updated.

Nitpicks

  • crates/rustyn64-test-harness/tests/rdp_conformance.rs (line 108): Nested backticks within bold markers (**Load Block's ...**) can degrade doc rendering in rustdoc.

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

@doublegate
doublegate merged commit c270e2d into main Jul 29, 2026
10 of 11 checks passed
@doublegate
doublegate deleted the fix/load-block-count branch July 29, 2026 10:15
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.

1 participant