Skip to content

Declare dScMgBase_c slot 33 (Virtual84) across the minigame family - #2108

Merged
andrewboudreau merged 1 commit into
mainfrom
cpp/minigame-slot33
Sep 1, 2026
Merged

Declare dScMgBase_c slot 33 (Virtual84) across the minigame family#2108
andrewboudreau merged 1 commit into
mainfrom
cpp/minigame-slot33

Conversation

@andrewboudreau

Copy link
Copy Markdown
Collaborator

Slot 33 of the dScMgBase_c keystone. Stacked on #2107 (slot 32); base it on cpp/minigame-slot32, land it after that one.

What lands

dScMgBase_c declares virtual void Virtual84(); /* slot 33 */, and the two classes that override it — dScMgSingle3DBase_c and dScMgD3DBase_c — declare it too. All 19 tables that carry the slot now emit it from source; 17 of them inherit.

tables carrying the slot 19
distinct addresses 2
declarations added 3 (base + 2 overrides)
inherited from an ancestor 17

Structurally this is slot 26 again — the same 19 tables, the same two owning classes (dScMgSingle3DBase_c + 13 children, dScMgD3DBase_c + 4), the same 17 inherited. Two things make it different.

1. The only slot in the campaign with nothing to correct

Slots 26, 29, 30, 31 and 32 each retired a name the recovery pass had borrowed across a fork of the hierarchy. Here the pass guessed nothing: there is no recovered name: line on the base body or on either override. Neither body even had a header comment — the two files began straight at #include "types.h". Both now carry one.

Virtual84 is the repo's own no-name spelling after the +0x84 vtable offset, the convention fBase_c already uses for Virtual34/Virtual38. The ROM names nothing here: dScMgBase_c is a scene (fBase_c -> dBase_c -> dScene_c -> dScMgBase_c), and dActor_c — whose names slots 18-30 borrowed by index — has no slot 33 at all.

2. The first override inside a promoted intact-object TU

dScMgSingle3DBase_c's body lives in src/actors/dScMgSingle3DBase_c.cpp, promoted in #2064, so the rename is an in-file identifier rewrite rather than a file move. With the base declared, the body becomes a real member definitionvoid dScMgSingle3DBase_c::Virtual84(), mangling to the same symbol the free function was hand-named. That is exactly what slot 26 did in that same file three commits ago, and that comment ended "Slot 33 below is still waiting on the same declaration."

It was the last vtable slot in that unit still spelled as a mangled free function. The one function left there under a func_<module>_<address> name, 0x0210a534, is in no vtable at all — confirmed by scanning every _ZTV in ov006 for that address and finding zero references. The class emits a byte-exact 34-slot prefix now.

Signature evidence

Return type void. None of the three bodies assigns a result and the one caller ignores whatever falls out. It is also the honest choice rather than a default: the Single3D body is a real member definition now, and a declared int with no return statement would be a lie in source.

No explicit parameters, measured. Scanning arm9 and all 103 overlays for the dispatch pair — ldr rD,[rN,#0x84] with Rn != pc, followed within three instructions by blx rD/bx rD — finds exactly two sites image-wide, of which one is in ov004 or ov006:

020B09C8  mov r0, r4
020B09CC  ldr r1, [r0]
020B09D0  ldr r1, [r1, #0x84]      <- slot 33 dispatch
020B09D4  blx r1

r1 is the loaded pointer, so it cannot also be a second argument. this is carried, and the base body proves it: it writes obj[0x68] and *(int*)(obj+0x6c).

Three refinements over the naive scan, all of which matter:

  • the mask is insn & 0x0FF00FFF == 0x05900000 | off, not 0x0FFF0FFF — bits 19-16 are Rn, so masking them in only ever matches one base register;
  • Rn == 15 is excluded (pc-relative literal-pool loads at the same encoding);
  • up to three intervening instructions are allowed before the branch. Strict adjacency returns zero hits at +0x84 and would have produced a false "this slot is never dispatched" claim.

The scanner was validated against a known answer before being trusted here: re-run at +0x80 it returns ov004:0x020b0900, reproducing slot 32's call site.

What it does, and when

Engine bring-up. Graphics modes for both engines, VRAM banks assigned, both BG-enable shadows (data_0209d45c main, data_0209d454 sub) initialised to 0x10 — the value slots 30 and 31 later save, clear bits out of, and restore. A language-indexed character file is decompressed into both engines' BG char VRAM, OBJ palette file 0xc3 is loaded into both, and the scene object is published into the global registry at data_ov000_020beb74.

The three bodies differ the way 2D and 3D differ: the base is the plain 2D sequence; dScMgD3DBase_c adds DisableAllBanks, texture and texture-palette banks, and keeps the decompressed file pointers alive instead of freeing them; dScMgSingle3DBase_c adds G3X fog setup.

Ordering, from BeforeInitResources (ov004:0x020b0930): slot 33 is dispatched near the top, slot 31 last before the function returns 1, and slot 32 out of AfterInitResources. Bring the engines up (33), dress the sub screen (31), dress the main screen (32).

Verification

  • rombuild.py -j 16 --no-rom: 11,088 / 11,088 reproducing, 106/106 modules exact, 100.000000% of compared bytes.
  • romdata_check --json, diffed against the slot-32 baseline in both directions: verifiedBytes 35,420 → 35,424 (+4), partialBytes 11,872 → 11,996 (+124). That is 128 bytes = 32 tables × 4. Every other counter and the entire differing set are unchanged.
  • check_dead_references, port_refcheck, check_duplicate_sources, check_src_tu_compiles (97/97), check_header_offsets --changed origin/main, langmode ratchet: all pass.

Prose re-counted

dScMgD3DBase_c.h's "one more slot stays undeclared" block is now empty — all nine of that class's dScMgBase_c overrides are spelled out. dScMgAmida_c.h's Unk36 moves from landing on 33 to landing on 34 (still the family's last DIFFERS; declaring slot 35 puts it on 36 and closes it). dScMgSingle3DBase_c.h goes from a 33-slot to a 34-slot prefix and "remaining three (33-35)" to "remaining two". The TU manifest's functions[8].symbol becomes the mangled name, legacy_source left alone per the slot-26 precedent in 638b24c84.

Does NOT establish

  • Virtual84 is a placeholder, not a ROM name. Nothing in the cartridge names this function.
  • The src_tu regeneration is still outstanding. src_tu/actors/unit_ov004_020b0a38.cpp holds the base bodies for slots 31, 32 and 33 under stale func_ov004_* names. It is "status": "text-verified", not enrolled, and src_tu/ is not in the ROM build, so both gates that read it are green — but it is due now, through tools/tubuild.py, as its own follow-up PR. Folding it in here would break the one-slot-per-change safety argument.
  • Retro-renaming slots 18-30 off dActor_c's borrowed names remains the owner's call.

Two slots left: 34 (Virtual88, 4 tables) and 35 (Virtual8C, 1 table). Slot 35 closes _ZTV12dScMgAmida_c and takes _ZTV11dScMgBase_c from PARTIAL to VERIFIED at 36 slots.

Slot 33 of the dScMgBase_c keystone: the base declares `virtual void
Virtual84()` and the two classes that override it declare it too, so all
19 tables that carry the slot emit it from source instead of inheriting a
gap. romdata_check moves verifiedBytes +4 and partialBytes +124 -- the
32 tables x 4 bytes this slot is worth -- with every other counter and
the `differing` set unchanged in both directions.

Structurally this is slot 26 again: the same 19 tables, the same two
owning classes (dScMgSingle3DBase_c plus its 13 children,
dScMgD3DBase_c plus its 4), 17 inherited. Two things make it different.

It is the only slot in the campaign with NOTHING to correct. Slots 26,
29, 30, 31 and 32 each retired a name the recovery pass had borrowed
across a fork of the hierarchy; here the pass guessed nothing, so there
is no `recovered name:` line on the base body or on either override.
The name is the repo's own no-name spelling after the +0x84 vtable
offset, the convention fBase_c already uses for Virtual34/Virtual38.

It is the first slot whose override lives inside a PROMOTED intact-object
TU. dScMgSingle3DBase_c's body is in src/actors/dScMgSingle3DBase_c.cpp,
so the rename is an in-file identifier rewrite, and with the base
declared the body becomes a real member definition -- exactly what slot
26 did in that same file three commits ago. It was the last vtable slot
in that unit still spelled as a mangled free function; the only one left
under a func_<module>_<address> name, 0x0210a534, is in no vtable at all.
The class emits a byte-exact 34-slot prefix now.

Signature evidence. `void`, because none of the three bodies assigns a
result and the one caller ignores what falls out -- and because the
Single3D body is a real member definition now, where a declared `int`
with no return statement would be a lie. No explicit parameters,
measured: scanning arm9 and all 103 overlays for the dispatch pair
`ldr rD,[rN,#0x84]` (Rn != pc) followed within three instructions by
`blx rD`/`bx rD` finds two sites image-wide, one of them in ov004/ov006
-- ov004:0x020b09d0 inside BeforeInitResources, reading
`mov r0,r4; ldr r1,[r0]; ldr r1,[r1,#0x84]; blx r1`, so r1 is the loaded
pointer and cannot also be a second argument. The scanner was validated
by re-running it at +0x80 and reproducing slot 32's known call site.

What it does: engine bring-up. Graphics modes and VRAM banks for both
screens, both BG-enable shadows initialised to 0x10 (the value slots 30
and 31 later save and restore), a language-indexed character file
decompressed into both engines' BG char VRAM, OBJ palette file 0xc3 into
both, and the scene object published into the global registry -- which
is what fixes `this` as the incoming argument. It runs first out of
BeforeInitResources; slot 31 runs last out of the same function and slot
32 out of AfterInitResources, so the order is: bring the engines up
(33), dress the sub screen (31), dress the main screen (32).

Verified: rombuild 11,088/11,088 reproducing, 106/106 modules exact,
100.000000% of compared bytes. check_dead_references, port_refcheck,
check_duplicate_sources, check_src_tu_compiles, check_header_offsets
--changed and the langmode ratchet all pass.

Two slots left: 34-35.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QhhAeJwXBnfPp7B5DNjCwh
@andrewboudreau andrewboudreau added the attribution-override Maintainer accepts this PR's contributor-credit changes; validation reports them as warnings label Aug 31, 2026
@tangos-validator

tangos-validator Bot commented Aug 31, 2026

Copy link
Copy Markdown

✅ PR validation — Passed

Committed merge passes; 2 contributor credit reassignment(s) noted, not a blocker.

Full merge validation

Check Result
Committed test merge yes
Byte-verified functions 10,781 / 11,347 (95.01%, +0)
Byte-verified code bytes 2,004,460 / 2,211,124 (90.65%, +0)
Claimed, not byte-verified 436 functions, 101,220 bytes (+0)
Perfect source moves 0 R100
Enrolled ranges (delinks complete) 11,059 functions, 2,053,148 bytes (92.86%, +0) -- differs from byte-verified by +278
Contributor credit 0 added, 2 changed, 0 lost
Relocation check 302 checked; 302 VERIFIED
Port reference check 405 checked; 0 stale
Module fidelity 106/106 exact; 100.000000% compared bytes
Code linked from verified source 11,088 functions, 2,067,148 bytes (93.49%)
Module bytes from source 2,067,148 / 3,049,600 (67.8%); 811,492 (26.6%) are data no delink entry reaches
ROM data reproduced from source 465 symbol(s) exact, 253 partial, 6 differ

Contributor credit moved (2)

Function Source Before After
ov004:0x020b265c src/func_ov004_020b265c.c -> src/_ZN11dScMgBase_c9Virtual84Ev.c tangosdev andrewboudreau
ov006:0x0210a708 src/actors/dScMgSingle3DBase_c.cpp github-actions[bot] andrewboudreau

Byte-verified means the range carries complete in a delinks.txt, so the ROM build compiled it and compared it to the cartridge. The 436 claimed functions have a src/ file named after the symbol with no NONMATCHING banner, and nothing compiles them -- dsd fills their addresses with the ROM's own bytes. Both together are the 11,217 this project calls matched.

Warnings: contributor attribution changed, not a blocker (2 changed, 0 lost -- src/_ZN11dScMgBase_c9Virtual84Ev.c: tangosdev -> andrewboudreau; src/actors/dScMgSingle3DBase_c.cpp: github-actions[bot] -> andrewboudreau).

Per-file link-check detail

All 192 changed file(s) compile to the ROM byte-for-byte with correct relocation targets.

File Symbol Result Slots checked
src/_ZN10dScMgCup_c13InitResourcesEv.cpp _ZN10dScMgCup_c13InitResourcesEv ✅ verified 1
src/_ZN10dScMgCup_c6RenderEv.cpp _ZN10dScMgCup_c6RenderEv ✅ verified 1
src/_ZN10dScMgCup_c8BehaviorEv.cpp _ZN10dScMgCup_c8BehaviorEv ✅ verified 1
src/_ZN10dScMgCup_cD0Ev.cpp _ZN10dScMgCup_cD0Ev ✅ verified 1
src/_ZN10dScMgCup_cD1Ev.cpp _ZN10dScMgCup_cD1Ev ✅ verified 1
src/_ZN11dScMgBase_c15OnHitByMegaCharEv.cpp _ZN11dScMgBase_c15OnHitByMegaCharEv ✅ verified 1
src/_ZN11dScMgBase_c15graphCallback_c14GraphCallback0Ev.cpp _ZN11dScMgBase_c15graphCallback_c14GraphCallback0Ev ✅ verified 1
src/_ZN11dScMgBase_c15graphCallback_c14GraphCallback1Ev.cpp _ZN11dScMgBase_c15graphCallback_c14GraphCallback1Ev ✅ verified 1
src/_ZN11dScMgBase_c15graphCallback_c14GraphCallback2Ev.cpp _ZN11dScMgBase_c15graphCallback_c14GraphCallback2Ev ✅ verified 1
src/_ZN11dScMgBase_c15graphCallback_c14GraphCallback3Ev.cpp _ZN11dScMgBase_c15graphCallback_c14GraphCallback3Ev ✅ verified 1
src/_ZN11dScMgBase_c16OnAimedAtWithEggEv.cpp _ZN11dScMgBase_c16OnAimedAtWithEggEv ✅ verified 1
src/_ZN11dScMgBase_c19OnHitFromUnderneathEv.cpp _ZN11dScMgBase_c19OnHitFromUnderneathEv ✅ verified 1
src/_ZN11dScMgBase_c25OnAimedAtWithEggReturnVecEv.cpp _ZN11dScMgBase_c25OnAimedAtWithEggReturnVecEv ✅ verified 1
src/_ZN11dScMgBase_c8OnPushedEv.cpp _ZN11dScMgBase_c8OnPushedEv ✅ verified 1
src/_ZN11dScMgBase_c9Virtual84Ev.c _ZN11dScMgBase_c9Virtual84Ev ✅ verified 1
src/_ZN11dScMgBase_cC2Ev.cpp _ZN11dScMgBase_cC2Ev ✅ verified 1
src/_ZN11dScMgBase_cD0Ev.cpp _ZN11dScMgBase_cD0Ev ✅ verified 1
src/_ZN11dScMgBase_cD1Ev.cpp _ZN11dScMgBase_cD1Ev ✅ verified 1
src/_ZN11dScMgBase_cD2Ev.cpp _ZN11dScMgBase_cD2Ev ✅ verified 1
src/_ZN11dScMgCoin_c13InitResourcesEv.cpp _ZN11dScMgCoin_c13InitResourcesEv ✅ verified 1
src/_ZN11dScMgCoin_c13OnYoshiTryEatEi.cpp _ZN11dScMgCoin_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN11dScMgCoin_c6RenderEv.cpp _ZN11dScMgCoin_c6RenderEv ✅ verified 1
src/_ZN11dScMgCoin_c8BehaviorEv.cpp _ZN11dScMgCoin_c8BehaviorEv ✅ verified 1
src/_ZN11dScMgCoin_cD0Ev.cpp _ZN11dScMgCoin_cD0Ev ✅ verified 1
src/_ZN11dScMgCoin_cD1Ev.cpp _ZN11dScMgCoin_cD1Ev ✅ verified 1
src/_ZN11dScMgJump_c13InitResourcesEv.cpp _ZN11dScMgJump_c13InitResourcesEv ✅ verified 1
src/_ZN11dScMgJump_c13OnTurnIntoEggEi.cpp _ZN11dScMgJump_c13OnTurnIntoEggEi ✅ verified 1
src/_ZN11dScMgJump_c16CleanupResourcesEv.cpp _ZN11dScMgJump_c16CleanupResourcesEv ✅ verified 1
src/_ZN11dScMgJump_c6RenderEv.cpp _ZN11dScMgJump_c6RenderEv ✅ verified 1
src/_ZN11dScMgJump_c8BehaviorEv.cpp _ZN11dScMgJump_c8BehaviorEv ✅ verified 1
src/_ZN11dScMgJump_cD0Ev.cpp _ZN11dScMgJump_cD0Ev ✅ verified 1
src/_ZN11dScMgJump_cD1Ev.cpp _ZN11dScMgJump_cD1Ev ✅ verified 1
src/_ZN12dScMg3DEsp_c13InitResourcesEv.cpp _ZN12dScMg3DEsp_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMg3DEsp_c13OnYoshiTryEatEi.cpp _ZN12dScMg3DEsp_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN12dScMg3DEsp_c16CleanupResourcesEv.cpp _ZN12dScMg3DEsp_c16CleanupResourcesEv ✅ verified 1
src/_ZN12dScMg3DEsp_c6RenderEv.cpp _ZN12dScMg3DEsp_c6RenderEv ✅ verified 1
src/_ZN12dScMg3DEsp_c8BehaviorEv.cpp _ZN12dScMg3DEsp_c8BehaviorEv ✅ verified 1
src/_ZN12dScMg3DEsp_cD0Ev.cpp _ZN12dScMg3DEsp_cD0Ev ✅ verified 1
src/_ZN12dScMg3DEsp_cD1Ev.cpp _ZN12dScMg3DEsp_cD1Ev ✅ verified 1
src/_ZN12dScMgAmida_c13InitResourcesEv.cpp _ZN12dScMgAmida_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgAmida_c21AfterCleanupResourcesEj.cpp _ZN12dScMgAmida_c21AfterCleanupResourcesEj ✅ verified 1
src/_ZN12dScMgAmida_c5Unk36Ev.cpp _ZN12dScMgAmida_c5Unk36Ev ✅ verified 1
src/_ZN12dScMgAmida_c6RenderEv.cpp _ZN12dScMgAmida_c6RenderEv ✅ verified 1
src/_ZN12dScMgAmida_c8BehaviorEv.cpp _ZN12dScMgAmida_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgAmida_cD0Ev.cpp _ZN12dScMgAmida_cD0Ev ✅ verified 1
src/_ZN12dScMgAmida_cD1Ev.cpp _ZN12dScMgAmida_cD1Ev ✅ verified 1
src/_ZN12dScMgJump2_c13InitResourcesEv.cpp _ZN12dScMgJump2_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgJump2_c16CleanupResourcesEv.cpp _ZN12dScMgJump2_c16CleanupResourcesEv ✅ verified 1
src/_ZN12dScMgJump2_c6RenderEv.cpp _ZN12dScMgJump2_c6RenderEv ✅ verified 1
src/_ZN12dScMgJump2_c8BehaviorEv.cpp _ZN12dScMgJump2_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgJump2_cD0Ev.cpp _ZN12dScMgJump2_cD0Ev ✅ verified 1
src/_ZN12dScMgJump2_cD1Ev.cpp _ZN12dScMgJump2_cD1Ev ✅ verified 1
src/_ZN12dScMgLuigi_c13InitResourcesEv.cpp _ZN12dScMgLuigi_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgLuigi_c21AfterCleanupResourcesEj.cpp _ZN12dScMgLuigi_c21AfterCleanupResourcesEj ✅ verified 1
src/_ZN12dScMgLuigi_c6RenderEv.cpp _ZN12dScMgLuigi_c6RenderEv ✅ verified 1
src/_ZN12dScMgLuigi_c8BehaviorEv.cpp _ZN12dScMgLuigi_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgLuigi_cD0Ev.cpp _ZN12dScMgLuigi_cD0Ev ✅ verified 1
src/_ZN12dScMgLuigi_cD1Ev.cpp _ZN12dScMgLuigi_cD1Ev ✅ verified 1
src/_ZN12dScMgPanel_c13InitResourcesEv.cpp _ZN12dScMgPanel_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgPanel_c6RenderEv.cpp _ZN12dScMgPanel_c6RenderEv ✅ verified 1
src/_ZN12dScMgPanel_c8BehaviorEv.cpp _ZN12dScMgPanel_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgPanel_cD0Ev.cpp _ZN12dScMgPanel_cD0Ev ✅ verified 1
src/_ZN12dScMgPanel_cD1Ev.cpp _ZN12dScMgPanel_cD1Ev ✅ verified 1
src/_ZN12dScMgSlot1_c13InitResourcesEv.cpp _ZN12dScMgSlot1_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgSlot1_c15OnHitByMegaCharEv.cpp _ZN12dScMgSlot1_c15OnHitByMegaCharEv ✅ verified 1
src/_ZN12dScMgSlot1_c19OnHitFromUnderneathEv.cpp _ZN12dScMgSlot1_c19OnHitFromUnderneathEv ✅ verified 1
src/_ZN12dScMgSlot1_c6RenderEv.cpp _ZN12dScMgSlot1_c6RenderEv ✅ verified 1
src/_ZN12dScMgSlot1_c9betIcon_c6RenderEv.cpp _ZN12dScMgSlot1_c9betIcon_c6RenderEv ✅ verified 1
src/_ZN12dScMgSlot1_c9betIcon_c8BehaviorEv.cpp _ZN12dScMgSlot1_c9betIcon_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgSlot1_cD0Ev.cpp _ZN12dScMgSlot1_cD0Ev ✅ verified 1
src/_ZN12dScMgSlot1_cD1Ev.cpp _ZN12dScMgSlot1_cD1Ev ✅ verified 1
src/_ZN12dScMgSlot3_c13InitResourcesEv.cpp _ZN12dScMgSlot3_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgSlot3_c6RenderEv.cpp _ZN12dScMgSlot3_c6RenderEv ✅ verified 1
src/_ZN12dScMgSlot3_c8BehaviorEv.cpp _ZN12dScMgSlot3_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgSlot3_cD0Ev.cpp _ZN12dScMgSlot3_cD0Ev ✅ verified 1
src/_ZN12dScMgSlot3_cD1Ev.cpp _ZN12dScMgSlot3_cD1Ev ✅ verified 1
src/_ZN12dScMgSound_c13InitResourcesEv.cpp _ZN12dScMgSound_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgSound_c6RenderEv.cpp _ZN12dScMgSound_c6RenderEv ✅ verified 1
src/_ZN12dScMgSound_c8BehaviorEv.cpp _ZN12dScMgSound_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgSound_cD0Ev.cpp _ZN12dScMgSound_cD0Ev ✅ verified 1
src/_ZN12dScMgSound_cD1Ev.cpp _ZN12dScMgSound_cD1Ev ✅ verified 1
src/_ZN13dScMgFlower_c13InitResourcesEv.cpp _ZN13dScMgFlower_c13InitResourcesEv ✅ verified 1
src/_ZN13dScMgFlower_c6RenderEv.cpp _ZN13dScMgFlower_c6RenderEv ✅ verified 1
src/_ZN13dScMgFlower_c8BehaviorEv.cpp _ZN13dScMgFlower_c8BehaviorEv ✅ verified 1
src/_ZN13dScMgFlower_cD0Ev.cpp _ZN13dScMgFlower_cD0Ev ✅ verified 1
src/_ZN13dScMgFlower_cD1Ev.cpp _ZN13dScMgFlower_cD1Ev ✅ verified 1
src/_ZN13dScMgMemory_c13InitResourcesEv.cpp _ZN13dScMgMemory_c13InitResourcesEv ✅ verified 1
src/_ZN13dScMgMemory_c13OnTurnIntoEggEi.c _ZN13dScMgMemory_c13OnTurnIntoEggEi ✅ verified 1
src/_ZN13dScMgMemory_c13OnYoshiTryEatEi.c _ZN13dScMgMemory_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN13dScMgMemory_c15OnGroundPoundedEv.c _ZN13dScMgMemory_c15OnGroundPoundedEv ✅ verified 1
src/_ZN13dScMgMemory_c6RenderEv.cpp _ZN13dScMgMemory_c6RenderEv ✅ verified 1
src/_ZN13dScMgMemory_c8BehaviorEv.cpp _ZN13dScMgMemory_c8BehaviorEv ✅ verified 1
src/_ZN13dScMgMemory_cD0Ev.cpp _ZN13dScMgMemory_cD0Ev ✅ verified 1
src/_ZN13dScMgMemory_cD1Ev.cpp _ZN13dScMgMemory_cD1Ev ✅ verified 1
src/_ZN13dScMgTeresa_c13InitResourcesEv.cpp _ZN13dScMgTeresa_c13InitResourcesEv ✅ verified 1
src/_ZN13dScMgTeresa_c6RenderEv.cpp _ZN13dScMgTeresa_c6RenderEv ✅ verified 1
src/_ZN13dScMgTeresa_c8BehaviorEv.cpp _ZN13dScMgTeresa_c8BehaviorEv ✅ verified 1
src/_ZN13dScMgTeresa_cD0Ev.cpp _ZN13dScMgTeresa_cD0Ev ✅ verified 1
src/_ZN13dScMgTeresa_cD1Ev.cpp _ZN13dScMgTeresa_cD1Ev ✅ verified 1
src/_ZN14dScMgBomroom_c13InitResourcesEv.cpp _ZN14dScMgBomroom_c13InitResourcesEv ✅ verified 1
src/_ZN14dScMgBomroom_c6RenderEv.cpp _ZN14dScMgBomroom_c6RenderEv ✅ verified 1
src/_ZN14dScMgBomroom_c8BehaviorEv.cpp _ZN14dScMgBomroom_c8BehaviorEv ✅ verified 1
src/_ZN14dScMgBomroom_cD0Ev.cpp _ZN14dScMgBomroom_cD0Ev ✅ verified 1
src/_ZN14dScMgBomroom_cD1Ev.cpp _ZN14dScMgBomroom_cD1Ev ✅ verified 1
src/_ZN14dScMgCurling_c13InitResourcesEv.cpp _ZN14dScMgCurling_c13InitResourcesEv ✅ verified 1
src/_ZN14dScMgCurling_c13OnYoshiTryEatEi.cpp _ZN14dScMgCurling_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN14dScMgCurling_c6RenderEv.cpp _ZN14dScMgCurling_c6RenderEv ✅ verified 1
src/_ZN14dScMgCurling_c8BehaviorEv.cpp _ZN14dScMgCurling_c8BehaviorEv ✅ verified 1
src/_ZN14dScMgCurling_cD0Ev.cpp _ZN14dScMgCurling_cD0Ev ✅ verified 1
src/_ZN14dScMgCurling_cD1Ev.cpp _ZN14dScMgCurling_cD1Ev ✅ verified 1
src/_ZN14dScMgD3DBase_c11AfterRenderEj.cpp _ZN14dScMgD3DBase_c11AfterRenderEj ✅ verified 1
src/_ZN14dScMgD3DBase_c12BeforeRenderEv.cpp _ZN14dScMgD3DBase_c12BeforeRenderEv ✅ verified 1
src/_ZN14dScMgD3DBase_c14BeforeBehaviorEv.cpp _ZN14dScMgD3DBase_c14BeforeBehaviorEv ✅ verified 1
src/_ZN14dScMgD3DBase_c16OnAimedAtWithEggEv.cpp _ZN14dScMgD3DBase_c16OnAimedAtWithEggEv ✅ verified 1
src/_ZN14dScMgD3DBase_c18AfterInitResourcesEj.cpp _ZN14dScMgD3DBase_c18AfterInitResourcesEj ✅ verified 1
src/_ZN14dScMgD3DBase_c19BeforeInitResourcesEv.cpp _ZN14dScMgD3DBase_c19BeforeInitResourcesEv ✅ verified 1
src/_ZN14dScMgD3DBase_c21AfterCleanupResourcesEj.cpp _ZN14dScMgD3DBase_c21AfterCleanupResourcesEj ✅ verified 1
src/_ZN14dScMgD3DBase_c25OnAimedAtWithEggReturnVecEv.c _ZN14dScMgD3DBase_c25OnAimedAtWithEggReturnVecEv ✅ verified 1
src/_ZN14dScMgD3DBase_c9Virtual7CEv.c _ZN14dScMgD3DBase_c9Virtual7CEv ✅ verified 1
src/_ZN14dScMgD3DBase_c9Virtual84Ev.c _ZN14dScMgD3DBase_c9Virtual84Ev ✅ verified 1
src/_ZN14dScMgD3DBase_cD0Ev.cpp _ZN14dScMgD3DBase_cD0Ev ✅ verified 1
src/_ZN14dScMgD3DBase_cD1Ev.cpp _ZN14dScMgD3DBase_cD1Ev ✅ verified 1
src/_ZN14dScMgMemory2_c13InitResourcesEv.cpp _ZN14dScMgMemory2_c13InitResourcesEv ✅ verified 1
src/_ZN14dScMgMemory2_c13OnTurnIntoEggEi.c _ZN14dScMgMemory2_c13OnTurnIntoEggEi ✅ verified 1
src/_ZN14dScMgMemory2_c13OnYoshiTryEatEi.c _ZN14dScMgMemory2_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN14dScMgMemory2_c15OnGroundPoundedEv.c _ZN14dScMgMemory2_c15OnGroundPoundedEv ✅ verified 1
src/_ZN14dScMgMemory2_c6RenderEv.cpp _ZN14dScMgMemory2_c6RenderEv ✅ verified 1
src/_ZN14dScMgMemory2_c8BehaviorEv.cpp _ZN14dScMgMemory2_c8BehaviorEv ✅ verified 1
src/_ZN14dScMgMemory2_cD0Ev.cpp _ZN14dScMgMemory2_cD0Ev ✅ verified 1
src/_ZN14dScMgMemory2_cD1Ev.cpp _ZN14dScMgMemory2_cD1Ev ✅ verified 1
src/_ZN15dScMgCurling2_c13InitResourcesEv.cpp _ZN15dScMgCurling2_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgCurling2_c13OnYoshiTryEatEi.cpp _ZN15dScMgCurling2_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN15dScMgCurling2_c6RenderEv.cpp _ZN15dScMgCurling2_c6RenderEv ✅ verified 1
src/_ZN15dScMgCurling2_c8BehaviorEv.cpp _ZN15dScMgCurling2_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgCurling2_cD0Ev.cpp _ZN15dScMgCurling2_cD0Ev ✅ verified 1
src/_ZN15dScMgCurling2_cD1Ev.cpp _ZN15dScMgCurling2_cD1Ev ✅ verified 1
src/_ZN15dScMgHanachan_c13InitResourcesEv.cpp _ZN15dScMgHanachan_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgHanachan_c16CleanupResourcesEv.cpp _ZN15dScMgHanachan_c16CleanupResourcesEv ✅ verified 1
src/_ZN15dScMgHanachan_c6RenderEv.cpp _ZN15dScMgHanachan_c6RenderEv ✅ verified 1
src/_ZN15dScMgHanachan_c8BehaviorEv.cpp _ZN15dScMgHanachan_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgHanachan_cD0Ev.cpp _ZN15dScMgHanachan_cD0Ev ✅ verified 1
src/_ZN15dScMgHanachan_cD1Ev.cpp _ZN15dScMgHanachan_cD1Ev ✅ verified 1
src/_ZN15dScMgPachinko_c13InitResourcesEv.cpp _ZN15dScMgPachinko_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgPachinko_c6RenderEv.cpp _ZN15dScMgPachinko_c6RenderEv ✅ verified 1
src/_ZN15dScMgPachinko_c8BehaviorEv.cpp _ZN15dScMgPachinko_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgPachinko_cD0Ev.cpp _ZN15dScMgPachinko_cD0Ev ✅ verified 1
src/_ZN15dScMgPachinko_cD1Ev.cpp _ZN15dScMgPachinko_cD1Ev ✅ verified 1
src/_ZN15dScMgRoulette_c13InitResourcesEv.cpp _ZN15dScMgRoulette_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgRoulette_c13OnYoshiTryEatEi.cpp _ZN15dScMgRoulette_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN15dScMgRoulette_c16CleanupResourcesEv.cpp _ZN15dScMgRoulette_c16CleanupResourcesEv ✅ verified 1
src/_ZN15dScMgRoulette_c6RenderEv.cpp _ZN15dScMgRoulette_c6RenderEv ✅ verified 1
src/_ZN15dScMgRoulette_c8BehaviorEv.cpp _ZN15dScMgRoulette_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgRoulette_cD0Ev.cpp _ZN15dScMgRoulette_cD0Ev ✅ verified 1
src/_ZN15dScMgRoulette_cD1Ev.cpp _ZN15dScMgRoulette_cD1Ev ✅ verified 1
src/_ZN15dScMgSnowball_c13InitResourcesEv.cpp _ZN15dScMgSnowball_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgSnowball_c16CleanupResourcesEv.cpp _ZN15dScMgSnowball_c16CleanupResourcesEv ✅ verified 1
src/_ZN15dScMgSnowball_c6RenderEv.cpp _ZN15dScMgSnowball_c6RenderEv ✅ verified 1
src/_ZN15dScMgSnowball_c8BehaviorEv.cpp _ZN15dScMgSnowball_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgSnowball_c8OnKickedEv.c _ZN15dScMgSnowball_c8OnKickedEv ✅ verified 1
src/_ZN15dScMgSnowball_cD0Ev.cpp _ZN15dScMgSnowball_cD0Ev ✅ verified 1
src/_ZN15dScMgSnowball_cD1Ev.cpp _ZN15dScMgSnowball_cD1Ev ✅ verified 1
src/_ZN16dScMgPachinko2_c13InitResourcesEv.cpp _ZN16dScMgPachinko2_c13InitResourcesEv ✅ verified 1
src/_ZN16dScMgPachinko2_c6RenderEv.cpp _ZN16dScMgPachinko2_c6RenderEv ✅ verified 1
src/_ZN16dScMgPachinko2_c8BehaviorEv.cpp _ZN16dScMgPachinko2_c8BehaviorEv ✅ verified 1
src/_ZN16dScMgPachinko2_cD0Ev.cpp _ZN16dScMgPachinko2_cD0Ev ✅ verified 1
src/_ZN16dScMgPachinko2_cD1Ev.cpp _ZN16dScMgPachinko2_cD1Ev ✅ verified 1
src/_ZN16dScMgSmartball_c21AfterCleanupResourcesEj.cpp _ZN16dScMgSmartball_c21AfterCleanupResourcesEj ✅ verified 1
src/_ZN16dScMgSmartball_c6RenderEv.cpp _ZN16dScMgSmartball_c6RenderEv ✅ verified 1
src/_ZN16dScMgSmartball_c8BehaviorEv.cpp _ZN16dScMgSmartball_c8BehaviorEv ✅ verified 1
src/_ZN16dScMgSmartball_cD0Ev.cpp _ZN16dScMgSmartball_cD0Ev ✅ verified 1
src/_ZN16dScMgSmartball_cD1Ev.cpp _ZN16dScMgSmartball_cD1Ev ✅ verified 1
src/_ZN17dScMgTrampoline_c13InitResourcesEv.cpp _ZN17dScMgTrampoline_c13InitResourcesEv ✅ verified 1
src/_ZN17dScMgTrampoline_c13OnYoshiTryEatEi.c _ZN17dScMgTrampoline_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN17dScMgTrampoline_c16CleanupResourcesEv.cpp _ZN17dScMgTrampoline_c16CleanupResourcesEv ✅ verified 1
src/_ZN17dScMgTrampoline_c6RenderEv.cpp _ZN17dScMgTrampoline_c6RenderEv ✅ verified 1
src/_ZN17dScMgTrampoline_c8BehaviorEv.cpp _ZN17dScMgTrampoline_c8BehaviorEv ✅ verified 1
src/_ZN17dScMgTrampoline_cD0Ev.cpp _ZN17dScMgTrampoline_cD0Ev ✅ verified 1
src/_ZN17dScMgTrampoline_cD1Ev.cpp _ZN17dScMgTrampoline_cD1Ev ✅ verified 1
src/_ZN18dScMgTrampoline2_c13InitResourcesEv.cpp _ZN18dScMgTrampoline2_c13InitResourcesEv ✅ verified 1
src/_ZN18dScMgTrampoline2_c16CleanupResourcesEv.cpp _ZN18dScMgTrampoline2_c16CleanupResourcesEv ✅ verified 1
src/_ZN18dScMgTrampoline2_c6RenderEv.cpp _ZN18dScMgTrampoline2_c6RenderEv ✅ verified 1
src/_ZN18dScMgTrampoline2_c8BehaviorEv.cpp _ZN18dScMgTrampoline2_c8BehaviorEv ✅ verified 1
src/_ZN18dScMgTrampoline2_cD0Ev.cpp _ZN18dScMgTrampoline2_cD0Ev ✅ verified 1
src/_ZN18dScMgTrampoline2_cD1Ev.cpp _ZN18dScMgTrampoline2_cD1Ev ✅ verified 1
src/actors/dScMgBSC_c.cpp _ZN10dScMgBSC_cD1Ev + _ZN10dScMgBSC_cD0Ev + func_ov006_02124a04 + func_ov006_02124a08 + func_ov006_02124ae4 + func_ov006_02124b58 + func_ov006_02124bb4 + func_ov006_02124cb4 + func_ov006_02124dc0 + func_ov006_02124e1c + func_ov006_02124ec4 + func_ov006_02124fd8 + func_ov006_021250e4 + _ZN10dScMgBSC_c15OnGroundPoundedEv + _ZN10dScMgBSC_c13OnTurnIntoEggEi + _ZN10dScMgBSC_c13OnYoshiTryEatEi + _ZN10dScMgBSC_c6RenderEv + _ZN10dScMgBSC_c8BehaviorEv + _ZN10dScMgBSC_c13InitResourcesEv ✅ verified 19
src/actors/dScMgBase_c.cpp _ZN11dScMgBase_c16OnPendingDestroyEv + _ZN11dScMgBase_c6RenderEv + _ZN11dScMgBase_c12BeforeRenderEv + _ZN11dScMgBase_c8BehaviorEv + _ZN11dScMgBase_c14BeforeBehaviorEv + _ZN11dScMgBase_c21AfterCleanupResourcesEj + _ZN11dScMgBase_c18AfterInitResourcesEj + _ZN11dScMgBase_c19BeforeInitResourcesEv ✅ verified 8
src/actors/dScMgCard_c.cpp _ZN11dScMgCard_cD1Ev + _ZN11dScMgCard_cD0Ev + func_ov006_020d96e0 + func_ov006_020d96f0 + func_ov006_020d970c + func_ov006_020d978c + func_ov006_020d9998 + func_ov006_020d99a4 + func_ov006_020d99ec + func_ov006_020d9a14 + func_ov006_020d9bd0 + func_ov006_020d9bdc + func_ov006_020d9c5c + func_ov006_020da00c + func_ov006_020da0ac + func_ov006_020da154 + func_ov006_020da174 + func_ov006_020da420 + func_ov006_020da4ac + func_ov006_020da5e8 + func_ov006_020da834 + func_ov006_020da860 + func_ov006_020da88c + func_ov006_020da8b8 + func_ov006_020da8e4 + func_ov006_020da974 + _ZN11dScMgCard_c16CleanupResourcesEv + _ZN11dScMgCard_c6RenderEv + _ZN11dScMgCard_c8BehaviorEv + func_ov006_020dac34 + _ZN11dScMgCard_c15OnGroundPoundedEv + _ZN11dScMgCard_c13OnTurnIntoEggEi + _ZN11dScMgCard_c13OnYoshiTryEatEi + _ZN11dScMgCard_c13InitResourcesEv ✅ verified 34
src/actors/dScMgMCarlo2_c.cpp _ZN14dScMgMCarlo2_cD1Ev + _ZN14dScMgMCarlo2_cD0Ev + func_ov006_020f8ff0 + func_ov006_020f9000 + func_ov006_020f94f4 + func_ov006_020f9560 + func_ov006_020f95f0 + func_ov006_020f9668 + func_ov006_020f96e0 + func_ov006_020f9760 + func_ov006_020f98dc + func_ov006_020f9994 + func_ov006_020f9bec + func_ov006_020f9cbc + func_ov006_020f9d68 + func_ov006_020f9db8 + func_ov006_020f9f40 + _ZN14dScMgMCarlo2_c16CleanupResourcesEv + _ZN14dScMgMCarlo2_c6RenderEv + _ZN14dScMgMCarlo2_c8BehaviorEv + _ZN14dScMgMCarlo2_c13OnTurnIntoEggEi + _ZN14dScMgMCarlo2_c13OnYoshiTryEatEi + _ZN14dScMgMCarlo2_c13InitResourcesEv ✅ verified 23
src/actors/dScMgMCarlo_c.cpp _ZN13dScMgMCarlo_cD1Ev + _ZN13dScMgMCarlo_cD0Ev + func_ov006_020f7730 + func_ov006_020f7740 + func_ov006_020f7994 + func_ov006_020f7a00 + func_ov006_020f7a90 + func_ov006_020f7b10 + func_ov006_020f7b90 + func_ov006_020f7c10 + func_ov006_020f7e2c + func_ov006_020f7ee4 + func_ov006_020f8154 + func_ov006_020f8224 + func_ov006_020f82d0 + func_ov006_020f8320 + func_ov006_020f84a8 + func_ov006_020f8540 + _ZN13dScMgMCarlo_c6RenderEv + _ZN13dScMgMCarlo_c8BehaviorEv + _ZN13dScMgMCarlo_c13OnTurnIntoEggEi + _ZN13dScMgMCarlo_c13OnYoshiTryEatEi + _ZN13dScMgMCarlo_c13InitResourcesEv ✅ verified 23
src/actors/dScMgSingle3DBase_c.cpp _ZN19dScMgSingle3DBase_cD1Ev + _ZN19dScMgSingle3DBase_cD0Ev + func_ov006_0210a534 + _ZN19dScMgSingle3DBase_c24OnHitByCannonBlastedCharEv + _ZN19dScMgSingle3DBase_c21AfterCleanupResourcesEj + _ZN19dScMgSingle3DBase_c12BeforeRenderEv + _ZN19dScMgSingle3DBase_c14BeforeBehaviorEv + _ZN19dScMgSingle3DBase_c18AfterInitResourcesEj + _ZN19dScMgSingle3DBase_c9Virtual84Ev ✅ verified 9
src/func_ov004_020b0a54.cpp func_ov004_020b0a54 ✅ verified 1
src/func_ov006_0210d6b8.cpp func_ov006_0210d6b8 ✅ verified 1

The private worker commits a test merge, builds the stock ROM profile, compares every executable module, measures matched and source-built code, checks contributor lineage, and verifies affected relocations. The mod profile is opt-in and is not part of this merge gate.

@andrewboudreau

Copy link
Copy Markdown
Collaborator Author

Self-review — I wrote this, so this is a record of what I checked, not an approval. Nobody in this repo can approve a PR (one shared account), so the sign-off is the comment.

Static gates, on the merge tree rather than the branch. premerge_check.py --base origin/main --fetch 2102 2106 2107 2108 — all eight gates (converted-ratchet, dead-references, duplicate-sources, header-offsets, langmode-ratchet, layout-check, src-tu-refs, source-coverage) pass on both base and merge tree for every PR in the chain. Nothing goes green -> red. Merge tree for this PR: 32641c686d21.

Byte verification. rombuild -j 16 --no-rom: 11,088/11,088 reproducing, 106/106 modules exact, 100.000000% of compared bytes. romdata_check --json diffed against slot 32 in both directions: only verifiedBytes 35,420 -> 35,424 (+4) and partialBytes 11,872 -> 11,996 (+124) changed. 128 bytes = 32 tables x 4 words, the campaign's per-slot signature. No key added or removed, every other counter and the whole differing set identical.

Things I went looking for and did not find:

  • A skipped override. slotapply asserts declared == len(overrides) for exactly this reason — a missed declaration stays green in rombuild and only romdata_check sees it, as a table that quietly stops matching one slot early. 2 declared, 2 in the census.
  • A borrowed name. This is the first slot in the campaign with nothing to correct: no recovered name: line on the base body or on either override. Which is also why the two legacy bodies were the only two files in the campaign with no header comment at all — added here.
  • An in-TU rename going wrong. This is the first slot whose override lives inside a promoted intact-object TU (src/actors/dScMgSingle3DBase_c.cpp, promoted in TU: promote ov006/dScMgSingle3DBase_c — nine functions, vtable-proven boundary #2064), so the change there is an identifier rewrite rather than a file rename. The regex is guarded with (?<!/)\b so that prose src/func_... path tokens survive — otherwise check_dead_references goes red on the merge tree only, which is the failure mode from two-green-prs-can-make-a-red-main.

What I'd want a second pair of eyes on:

  1. The signature. void(), from one dispatch site (ov004:0x020b09d0) reading mov r0,r4; ldr r1,[r0]; ldr r1,[r1,#0x84]; blx r1 — r1 is the loaded pointer and so cannot also be a second argument. One site is thinner evidence than slot 34's seven. It is consistent with all three bodies, which take nothing and return nothing.
  2. Virtual84 is a placeholder. The ROM's RTTI carries class names only. It is named after the +0x84 vtable offset, the same convention fBase_c already uses for Virtual34/Virtual38.
  3. The TU manifest edit. functions[8].symbol goes func_ov006_0210a708 -> _ZN19dScMgSingle3DBase_c9Virtual84Ev; legacy_source deliberately stays, recording where the body came from (precedent set at slot 26, commit 638b24c84). The manifest round-trips in 4 diff lines.

Known outstanding, not blocking: src_tu/actors/unit_ov004_020b0a38.cpp holds slots 31, 32 and 33 under stale func_ov004_* names and config/tu_manifest.d/ov004/unit020b0a38.json still lists the old legacy_source paths. Harmless today — "status": "text-verified", not enrolled, src_tu/ is not in the ROM build, and both reading gates are green — and now marked DUE in notes/dScMgBase_c-slots-18-35.md. It is a follow-up PR of its own rather than folded in here, because one slot per change is the whole safety argument for this campaign.

Slot 34 is up as #2110; slot 35 is the last one.

@andrewboudreau andrewboudreau left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Reviewed at a3d94efa1a0d. This is the strongest PR in the stack, and I think it settles the question that is holding the other five. One ask, and it is about a claim's checkability, not its truth.

I verified every ROM claim in this PR independently against the cartridge. All of them hold. Details below, because on a campaign this long the useful thing is a second reading of the same bytes, not agreement.

What this one does that the previous five did not

It declares void, and for the right reason. virtual void Virtual84(); /* slot 33 */. Your argument — that one of the three bodies is about to become a real member definition, "where a declared int with no return statement would be a lie the compiler has to paper over" — is exactly the argument I made on #2107 for slot 32, and it is better stated here than I stated it. This PR adds zero new header/definition splits. It is the first in the stack that doesn't.

It converts a mangled free function into a real member. extern "C" void func_ov006_0210a708(char *obj)void dScMgSingle3DBase_c::Virtual84(), with objthis, inside the promoted TU. That is the project goal rather than a rename, and it retires the last vtable slot in that unit still spelled func_<module>_<address>.

The arity claim is now conclusive, and you validated the scanner first. On #2107 I said the +0x80 evidence did not carry, because the three sites there put the pointer in r1/r2/r3 and the mov r4,r1 park tracks caller liveness rather than callee signature. At +0x84 the site reads mov r0,r4; ldr r1,[r0]; ldr r1,[r1,#0x84]; blx r1r1 holds the loaded pointer, so it cannot also carry a second argument. That is the structurally decisive form. And re-running the scan at +0x80 to reproduce slot 32's known site is a positive control. MEASURED is earned here. I withdraw nothing from what I said on #2107 and I am not asking for anything on this one.

It tracks the index shift it causes. include/dScMgAmida_c.h updates Unk36 from "lands on 33" to "lands on 34". That is the kind of thing that silently rots.

Independent verification of the vtable claims

Dumped from the cartridge (extracted/overlays/overlay_000{4,6}.bin), slot indices from each _ZTV's recorded address:

table slot 33 own slots in 18-35 real extent
_ZTV11dScMgBase_c @020bc0c0 (ov004) 020b265c 36 words
_ZTV12dScMgAmida_c @0213b918 020b265c (inherited) Unk36 at 36 37 words
_ZTV19dScMgSingle3DBase_c @0213e448 0210a708 26, 33 36 words
_ZTV14dScMgD3DBase_c @0213c62c 020e7124 24-31, 33 36 words

Every one agrees with this PR:

  • Slot 33 of the base is 020b265c, the ov004 function you named.
  • dScMgSingle3DBase_c's own slots among 18-35 are exactly 26 and 33 — the "identical reference sets" argument in the TU manifest is correct, and slot 26 (0210a600) and slot 33 (0210a708) are both this class's.
  • dScMgD3DBase_c's own slots are exactly 24, 25, 26, 27, 28, 29, 30, 31, 33 — nine, as the header says. Slot 32 is 020b27f4, inherited, which is why #2107 correctly did not declare it here.
  • dScMgAmida_c's table is 37 words and Unk36 really is slot 36 (020d1188), so "declaring slot 35 puts it on 36" is right.

The one ask: dScMgD3DBase_c's "byte-exact 34-slot prefix" cannot be checked

include/dScMgD3DBase_c.h now says:

its table is a byte-exact 34-slot prefix rather than a 31-slot one.

The claim about the cartridge is true — I read all 36 slots and they are one contiguous run of code addresses, with the first non-code word at index 36. The problem is the word "byte-exact", because for this one class nothing can establish it.

_ZTV14dScMgD3DBase_c's recorded extent stops at 20 words:

_ZTV14dScMgD3DBase_c  kind:data(any) addr:0x0213c62c
data_ov006_0213c67c   kind:data(any) addr:0x0213c67c  ambiguous     <- slot 20

So a 34-slot prefix is being asserted against a symbol whose tracked extent covers 20 of those 34 slots. Its two siblings are fine — dScMgBase_c and dScMgSingle3DBase_c both run the full 36 to the next symbol.

data_ov006_0213c67c is not a real object. It is the slot-20 word itself:

ov006/relocs.txt   from:0x0213c67c kind:load to:0x020b2990 module:overlays(0,4)
config/arm9/relocs.txt  from:0x02090ba0 kind:load to:0x0213c67c module:overlays(6,98)

The first row is the vtable slot doing its job — 020b2990 is exactly the word I dumped at index 20. The second is an arm9 pointer table entry that dsd could not resolve to one overlay, so it marked it ambiguous and fanned it into ov006. Overlays share address space; the pointer is overlays(6,98)'s to disambiguate, and the symbol it produced in ov006 is an artifact of that.

Two things follow, and I want to be clear about which is yours:

Not yours, and please do not fix it here. The truncated extent is pre-existing debt on main. I have it open separately, and I have measured that correcting it moves a ratchet — it is its own PR with its own baseline conversation. Repairing it as a rider on this one would put a ratchet movement inside a slot-declaration PR, which is exactly the mixing I have been asking the stack to avoid.

Yours, and it is one sentence. The header states byte-exact for a class where the tracked extent ends at slot 20. Either drop byte-exact for that class specifically, or add a clause noting the extent is truncated at 20 words by an ambiguous cross-overlay symbol and that the 34-slot agreement is read from the cartridge rather than from tracked config. The dScMgSingle3DBase_c header can keep its wording unchanged — its extent is genuinely 36.

While I was there: no workflow runs romdata_check.py. It appears in source-coverage.yml only inside a comment, and tool-tests.yml runs test_romdata_check, its unit tests, not the gate. It is not in the pre-push hook either. So no CI check on this PR — or any of the six — evaluates whether an emitted vtable agrees with the cartridge. That is not an objection to this PR; it is why I read the bytes myself, and why the wording of a byte-exact claim matters more here than it normally would.

Gates

vs origin/cpp/minigame-slot32 @567649493a6b   merge tree 04718d0ca6a3   8/8 pass -> pass
vs origin/main @5e88bfb5ed0f                  merge tree 32641c686d21   8/8 pass -> pass

All seven GitHub checks green, PR validation SUCCESS. The config half carries no coined data symbols — I check for that specifically after #2096 and #2104, and there are none: all four renames are address- and size-preserving function renames.

Off-by-one, unchanged status

This PR does not add one. Slot 33 has three bodies and a void reading, so it correctly breaks the "consecutive slot no body pins" chain rather than extending it. The two stale sentences are still inherited from below:

:606  slot 31 -- "the third consecutive slot no body pins"    <- should be fourth
:693  slot 32 -- "and the FOURTH consecutive slot no body pins" <- should be fifth

Fix them in whichever of #2106/#2107 lands second, as I asked there — not here, or all three PRs conflict on the same lines.

Ordering, and what I would like to happen

Stack is #2099#2100#2102#2106#2107#2108. The five below all carry changes-requested from me on one thing: header declares int, definition defines void, eight symbols, no tool in the tree compares the two surfaces.

This PR resolves that question, and I would like the stack to adopt its answer. Slot 33 declares void because the bodies return nothing and one of them is a real member definition where int would force a manufactured return 0;. That reasoning applies unchanged to slots 28 through 32 — none of those bodies sets a result either, and #2064-style promotion will eventually reach them too. Flip those five declarations to void at the bottom of the stack and every changes-requested I hold on this campaign clears in one edit.

On content this is the first PR in the stack I would approve. It is held only by its base.

Base automatically changed from cpp/minigame-slot32 to main September 1, 2026 06:54
@andrewboudreau
andrewboudreau merged commit d3856d5 into main Sep 1, 2026
8 of 9 checks passed
@andrewboudreau
andrewboudreau deleted the cpp/minigame-slot33 branch September 1, 2026 07:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

attribution-override Maintainer accepts this PR's contributor-credit changes; validation reports them as warnings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant