tools: audit our class names against the cartridge's own RTTI (259 of 541 disagree, and that gates promotion) - #2069
Merged
Merged
Conversation
A coined class name is not just a readability debt -- it is a hard block on TU promotion, and it does not announce itself as a naming problem. Promoting a TU consolidates the RTTI, so the compiler emits _ZTI/_ZTS under our name while the cartridge holds those records under the real one, at a different length. There is no ROM symbol to license them to and tubuild refuses with HOMELESS/COLLIDES-GAP. #2066 found this the expensive way: PoleLift is daObjKm2_Ami_Bou_c in the ROM, so that promotion could never have landed however good its boundary evidence was. Measured tree-wide, 541 _ZTV symbols in config: 276 agree, 259 disagree, 6 unreadable. The mechanism holds across history too -- of the 23 manifests with status: promoted, 15 own a vtable and all 15 agree; none disagree. Intersected with the 41-TU inline-destructor census: 11 agree, 48 disagree, 19 own no vtable. The destructor flip still lands independently, but the promotion half of that list is gated on renames rather than on destructor mechanics. The tool reads the chain directly -- _ZTV-4 -> typeinfo -> name ptr -> the length-prefixed _ZTS string, which verifies itself. Three traps are documented in the docstring because each produced wrong numbers before being caught: read config from origin/main not a stale checkout, resolve each address in its own overlay (ov045/046/047 share a base address), and use the decompressed arm9_dec.bin. An unreadable typeinfo word is reported as unmeasured, never folded into the agreeing column. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WdCK1xgrJdiJzPCh3bAJfQ
✅ PR validation — Passednoverify: no source/build-data changes in this PR Each changed |
This was referenced Aug 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
tools/rtti_name_audit.pyandnotes/rtti-name-audit.md. Tools and prose only — no source, config, manifest or gate changes.Why
#2066 spent a full destructor migration on
PoleLiftbefore discovering the promotion it was meant to unlock could never have landed:PoleLiftisdaObjKm2_Ami_Bou_cin the cartridge. Promoting a TU consolidates the class's RTTI, so the compiler emits_ZTI/_ZTSunder our name; the ROM holds those records under the real name, at a different length, so nothing can license them. That is a naming failure wearing a TU-boundary failure's clothes, and no amount of boundary evidence fixes it.What it measures
Tree-wide, against
origin/main'sconfig/:The mechanism is confirmed against everything that has already landed, not just the one failure. Of the 23 manifests on
mainwithstatus: promoted:Nothing name-mismatched has ever promoted. The zero is the load-bearing number.
What it does to the inline-destructor queue
Intersecting with the 41-TU inline-destructor census: 11 agree (all already have manifests on
main), 48 disagree, 19 own no_ZTV. The destructor flip is unaffected and still lands independently — it touches no RTTI. The promotion half of that list is spent on the agreeing side. Worked top-to-bottom expecting 41 promotions, 48 of them fail attubuild, each after a full TU reconstruction.Disagreements concentrate: ov002 has 35,
arm923, ov064 12, ov022 9, ov029 8.The evidence chain
Direct and self-checking. From
_ZTVaddressV,[V-4]is the typeinfo pointer; a__si_class_type_inforecord is[vptr][name ptr][base ptr], so word 1 leads to a length-prefixed_ZTS:18is exactlylen("daObjKm2_Ami_Bou_c"), so a correct read verifies itself.TI[2]also hands you the ROM-proven direct base.Three traps, all of which produced wrong numbers here first
Documented in the docstring and the note because each one was hit during this work:
config/fromorigin/main, not a checkout. A stale working copy returned 265/543 instead of 259/541 — six renames had landed and two_ZTVsymbols were gone.0x021111a0; an address-only or arm9-first lookup silently reads a different image. The tool takes the overlay from the path of thesymbols.txtthe symbol came from.extracted/arm9_dec.bin.extracted/dsd/arm9/arm9.binis compressed.And one reporting rule the tool enforces: an unreadable typeinfo word is unmeasured, not an agreement. Six are unreadable; folding them into the agreeing column would overstate what is promotable by six classes.
Using it
--classis the one to run before starting a promotion.Verification
Run from a clean worktree off
origin/main, independently reproducing 541/276/259/6.--class PoleLift→ DISAGREES,--class daEyBm_c→ AGREES,--class NoSuchClass→ exit 1.Gates in-worktree:
check_python_namesPASS (261 files, 0 unresolvable),check_dead_referencesclean (377 prose files, 3549 references, no broken markdown links),check_header_offsetsclean over 400 headers. Pre-push: port-refcheck 405/405, duplicate-sources 11158 stems none doubled,check_src_tu_compiles92/92.No ROM was built for this PR and none is needed — it adds no compiled source.
🤖 Generated with Claude Code
https://claude.ai/code/session_01WdCK1xgrJdiJzPCh3bAJfQ