Skip to content

ruff_r2il: emit the 6502 partition as an MGRA v3 graph - #109

Merged
AdaWorldAPI merged 1 commit into
mainfrom
claude/c64-6502-falsifier-shztkk
Aug 26, 2026
Merged

AdaWorldAPI merged 1 commit into
mainfrom
claude/c64-6502-falsifier-shztkk

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

The reachability probe measures a partition and prints a table. That partition is a graph — addresses are nodes, calls and references are edges — and the tier that draws this exact wire already ships: medcare-rs emits MGRA v3 from graph_abi.rs, a2ui-graph renders it over wgpu with a WebGL2 fallback. What was missing was the emitter. No new renderer, no new format.

What landed

src/mgra.rs — the encoder. A pure writer, plus a GraphBuilder holding the address→index mapping the renderer needs (the wire carries node ordinals; a walk produces addresses). It refuses three things the wire cannot express: an endpoint past the node lane, a label over its u16 prefix, a count over the header u32.

The consumer is not defenceless — its edge_pairs() drops ghost ordinals so they cannot index a GPU buffer out of bounds — but a dropped edge is silent data loss: the field renders slightly wrong and nothing says so. Refusing the stream names the offending edge instead.

examples/mgra_emit.rs — the walk. Same recursive descent as the probe, with one extra piece of state: every queue entry carries the entry its descent started from, so a call becomes an edge rather than just a target. Kept separate from the probe's walk deliberately — the probe's numbers are pinned in a merged PR, and rewriting its walk to serve a second consumer is how a measured result quietly moves.

The falsifier

The round-trip test decodes with a2ui-graph's own parser, added as a dev-dependency with default-features = false. Zero wgpu crates enter the lock; 30 transitive ones do (ndarray, the wasm-bindgen/web-sys family). An encoder checked against your own re-read of your own encoder proves only that you were consistent.

It earned its keep immediately — it caught the first of the two mistakes below.

Three things that went wrong, and what they taught

  1. edge()'s third element is the predicate @11; the line style is a separate byte @8 behind edge_kind(). The first version wrote the relation into @8 alone. A call and a data reference differ both in meaning and in how they should be drawn, so both fields carry it.

  2. The first walk observed a node per decoded instruction — nodes == instrs exactly (1349/1349, 7347/7347). That is an instruction dump, not a call graph.

  3. The data arm fired zero times, and rather than assume why, the address operands were counted by space:

    space count in image
    Unique 1257 —
    Register 354 —
    Const 166 none

    6502 absolute addressing lifts its address into a computed temp, so recovering an in-image data address needs constant propagation through the p-code temps — which this walk does not do and does not fake. What Const does catch is the out-of-image absolute, and the emitted addresses are exactly what that predicts: $0007, $0057, $0059, $005b — zero page.

    (in_image is deliberately not applied to a Unique operand: its offset is a temp slot number, not an address. 92 of them compare "inside the image" by coincidence of numbering.)

    A guard now warns when either arm reports zero — that column read 0 and looked like a measurement.

A finding this surfaced elsewhere, not fixed here

reachability_probe's own data_refs set is structurally empty on these images, for exactly the same reason. Its unreached+ref column is not measuring what its name says.

Left alone on purpose: its numbers are pinned in a merged PR and in CLAUDE.md, and quietly rewriting a measured result is how one moves. It wants its own change with the re-run as the evidence.

Measured

image entries referenced calls bytes
LOCODE.unprot.bin 79 4 40 2757
HICODE.unprot.bin 199 10 526 12783

Artifacts are gitignored on the same footing as the ore — a build product derived from a commercial game's image.

Gates

cargo clippy --features lift --all-targets -- -D warnings clean · cargo fmt --check clean · cargo test -p ruff_r2il --lib 46/46 · prek on every changed file, all hooks pass · both probes re-run end to end.


Generated by Claude Code

The reachability probe measures a partition and prints a table. The partition is a
graph, and the tier that draws this exact wire already ships: medcare-rs emits MGRA v3
from graph_abi.rs and a2ui-graph renders it over wgpu with a WebGL2 fallback. What was
missing was the emitter, so that is what this adds — no new renderer, no new format.

src/mgra.rs is the encoder: a pure writer plus a GraphBuilder that holds the
address-to-index mapping the renderer needs, since the wire carries node ordinals and a
walk produces addresses. It refuses three things the wire cannot express — an endpoint
past the node lane, a label over its u16 prefix, a count over the header u32. The
consumer is not defenceless (its edge_pairs() drops ghost ordinals so they cannot index
a GPU buffer) but a dropped edge is silent data loss: the field renders slightly wrong
and nothing says so.

The round-trip test decodes with a2ui-graph's own parser rather than a second reader
written here, added as a dev-dependency with default-features = false. Zero wgpu crates
enter the lock; 30 transitive ones do. An encoder checked against your own re-read of
your own encoder proves only that you were consistent.

Two mistakes the tests and the run caught, both recorded where they happened:

- edge()'s third element is the predicate at @11; the line style is a separate byte at
  @8 behind edge_kind(). The first version wrote the relation into @8 alone. A call and
  a data reference differ both in meaning and in how they should be drawn, so both
  fields carry it.
- The first walk observed a node per decoded instruction, which made nodes == instrs
  exactly (1349/1349, 7347/7347) — an instruction dump, not a call graph.

And one measurement that changed the design. The data arm fired zero times, so rather
than assume why, the address operands were counted by space: of 1777, 1257 land in
Unique, 354 in Register, 166 in Const — and not one Const operand is inside the image.
6502 absolute addressing lifts its address into a computed temp, so recovering an
in-image data address needs constant propagation through the p-code temps, which this
walk does not do and does not fake. What Const does catch is the out-of-image absolute,
and the emitted addresses are exactly what that predicts: $0007, $0057, $0059, $005b —
zero page. A guard now warns when either arm reports zero, because that column read 0
and looked like a measurement.

This also means reachability_probe's own data_refs set is structurally empty on these
images for the same reason. Its unreached+ref column is not measuring what its name
says. Not touched here: its numbers are pinned in a merged PR, and quietly rewriting a
measured result is how one moves.

Measured: LOCODE 79 entries / 4 referenced / 40 calls, HICODE 199 / 10 / 526. Artifacts
are gitignored on the same footing as the ore — a build product from a commercial
game's image.

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

coderabbitai Bot commented Aug 26, 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4ca2ce2e-04bd-45b8-b601-83dcda2fe724


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.

@cursor

cursor Bot commented Aug 26, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_7b48e6ec-208d-4346-ae54-5aeb19f8d835)

@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review August 26, 2026 07:25
@AdaWorldAPI
AdaWorldAPI merged commit 14139c0 into main Aug 26, 2026
32 of 35 checks passed
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