Skip to content

Cleanup ov063/daTrsTrap_c: BBH animated-furniture traps - #2709

Merged
andrewboudreau merged 10 commits into
tangosdev:mainfrom
lunavyqo:cleanup-datrstrap
Sep 18, 2026
Merged

andrewboudreau merged 10 commits into
tangosdev:mainfrom
lunavyqo:cleanup-datrstrap

Conversation

@lunavyqo

Copy link
Copy Markdown
Contributor

Deslops the Big Boo's Haunt animated-furniture traps (one class, four registry profiles): 9 shards merged into 2 real files + 2 kept dtor shards, named fields, typed resource rows, 4x return new factories, deslop + Leftover: markers.

  • 3-way split forced by ROM layout (state bodies/callbacks interleave the class's runs; one delinks entry = one contiguous range); dtors stay single-function (merging buys nothing). Rationale documented in-TU.
  • 11/11 functions VERIFIED, 2 new manifests in sync, 2 deliberate decls banked, 3 converted identities rewritten onto the merged TU (ratchet green)
  • Header-only shared change (own class header)

Stack: on origin/main, standalone. Note: touches ov063/delinks.txt adjacent to #2705 (BBH) rows — rebase order may matter at merge time.

Made with Cursor

@tangos-validator

tangos-validator Bot commented Sep 14, 2026

Copy link
Copy Markdown

✅ PR validation — Passed

Committed merge introduces no reconstruction or attribution regression.

Full merge validation

Check Result
Committed test merge yes
Byte-verified functions 11,178 / 11,344 (98.54%, +1)
Byte-verified code bytes 2,137,264 / 2,211,124 (96.66%, +880)
Claimed, not byte-verified 146 functions, 50,404 bytes (-1)
Perfect source moves 0 R100
Contributor credit 0 added, 0 changed, 0 lost
Relocation check 11 checked; 11 VERIFIED
Port reference check 423 checked; 0 stale
Module fidelity 106/106 exact; 100.000000% compared bytes
Code linked from verified source 11,207 functions, 2,151,304 bytes (96.12%)
Module bytes from source 2,151,304 / 3,049,600 (70.5%); 806,508 (26.4%) are data no delink entry reaches
Retail-gap contribution 893,312 module bytes (86,804 function-code; 806,508 data/non-function)
ROM data reproduced from source 720 symbol(s) exact, 232 partial, 4 differ

Byte-verified means the range carries complete in a delinks.txt, so the ROM build compiled it and compared it to the cartridge. The 146 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,324 this project calls matched.

Per-file link-check detail

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

File Symbol Result Slots checked
src/game/actors/daTrsTrap_c/_ZN11daTrsTrap_cD0Ev.cpp _ZN11daTrsTrap_cD0Ev ✅ verified 1
src/game/actors/daTrsTrap_c/_ZN11daTrsTrap_cD1Ev.cpp _ZN11daTrsTrap_cD1Ev ✅ verified 1
src/game/actors/daTrsTrap_c/d_a_trs_trap.cpp _ZN11daTrsTrap_c16CleanupResourcesEv + _ZN11daTrsTrap_c16OnPendingDestroyEv + _ZN11daTrsTrap_c6RenderEv + _ZN11daTrsTrap_c8BehaviorEv + _ZN11daTrsTrap_c13InitResourcesEv ✅ verified 5
src/game/actors/daTrsTrap_c/d_a_trs_trap_classinits.cpp daTrsTrap_c_classInit_TERESAPIT + daTrsTrap_c_classInit_MERRYGOROUND + daTrsTrap_c_classInit_BOOKSHELF + daTrsTrap_c_classInit_KAIDAN ✅ verified 4

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.

lunavyqo and others added 3 commits September 14, 2026 19:28
One class, four registry profiles (KAIDAN stairs, TERESAPIT trapdoor,
BOOKSHELF, MERRYGOROUND): merge 9 shards into d_a_trs_trap.cpp (5 methods)
and d_a_trs_trap_classinits.cpp (4 x return new). Split 3 ways because ROM
interleaves state bodies/callbacks between the class's runs; dtors stay
single-function. Header gains named fields + leaf operator new; delinks 9
rows -> 2; two new manifest entries license Vector3D1/Matrix4x3D1.

linkcheck: 11 checked, 11 verified, 0 blocking. decl-agreement: 2
deliberate typed-vs-slop rows (data_ov063_0211e27c/28c SharedFilePtr*[]
vs decl_common int[]), listed not banked. resync --check in sync x2.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

@andrewboudreau andrewboudreau left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Humanizer review of e406d2aa0d5f6cccd7e801dc356fd228d2e33c93.

TRAP-2709-01 (reconstruction; correct the associated provenance claim), src/game/actors/daTrsTrap_c/d_a_trs_trap.cpp:35-36,63-65,221: the opaque C PMF receiver is unnecessary. On the complete candidate TU, replace:

-struct C;
-typedef void (C::*PMF)();
+typedef void (daTrsTrap_c::*PMF)();
-    (((C *)this)->*data_ov063_0211ef38[idx])();
+    (this->*data_ov063_0211ef38[idx])();

Under 2004/b56, all 8 emitted function bodies and their relocation offset/type/target records remain identical, with no added or removed function. linkcheck.py on _ZN11daTrsTrap_c8BehaviorEv, ov063 0x0211ce74, size 0x8c, returns VERIFIED, diffs: [], blind: 0. Remove the fake receiver and the statement that the polymorphic class cannot use the ROM representation, then refresh candidate proof.

The exact head also passes port_refcheck.py: 423 checked, zero stale references. This is initial blocking source review, not full-ROM/composition acceptance. Retained compiler constraints need the pinned experiment evidence required by notes/agents/SOURCE-REVIEW-CUTOVER.md; any accepted deferred reconstruction needs its issue and next owner. Current-main composition and independent source acceptance remain required before landing.

andrewboudreau and others added 2 commits September 14, 2026 15:51
Main folded FallBlockBbh into src/game/actors/d_a_obj_th_fall_block.cpp under
its ROM RTTI name, while this branch folded daTrsTrap_c; each fold leaves the
other's per-function paths stale in config/converted-baseline.json, and git
merged that file silently into a set that was neither side's.

Both generated baselines are regenerated rather than merged. The converted
baseline is rebuilt as the union of both sides intersected with what the tool
actually scores today, which drops exactly the seven dead paths (four
FallBlockBbh, three per-function daTrsTrap_c) and keeps every live identity;
the ratchet then reports 0 orphaned. config/decl-agreement-baseline.json is
re-banked from main's copy: the two new contradictions are this branch's own
d_a_trs_trap.cpp SharedFilePtr spellings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y4FxdKHG3a6hQRYRAbx29c
TRAP-2709-01. The file bound the four ROM dispatch records to an opaque
forward-declared `struct C` and cast `this` to it, on the stated theory that
a pointer-to-member of the polymorphic daTrsTrap_c does not share the ROM's
{ptr, adj} record shape.

That is false for this TU. Review reproduced the real-class spelling under
2004/b56: all 8 emitted function bodies and their relocation offset/type/target
records are identical, with no function added or removed, and linkcheck on
_ZN11daTrsTrap_c8BehaviorEv (ov063 0x0211ce74, size 0x8c) returns VERIFIED,
diffs: [], blind: 0.

Remove the fake receiver and the representation claim that justified it.
Reverified here: 106/106 exact, mismatching 0, ROM-build analysis PASS.

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

Copy link
Copy Markdown
Collaborator

TRAP-2709-01: fixed in 395312cb4.

Applied your diff exactly:

-struct C;
-typedef void (C::*PMF)();
+typedef void (daTrsTrap_c::*PMF)();
-    (((C *)this)->*data_ov063_0211ef38[idx])();
+    (this->*data_ov063_0211ef38[idx])();

The opaque receiver and the representation claim that justified it are both gone. The deslop leftovers bullet that asserted "a pointer to member of the polymorphic daTrsTrap_c does not share the {ptr, adj} record shape" now records that the claim was tested and is false, rather than restating it.

Reverified on this head — full build, not a scoped linkcheck:

8753 reused from cache, 1 compiled
intact TU gates: dsd modules PASS, zero new symbol errors, storage aliases exact
source-built functions: 11,207  reproducing: 11,207  mismatching: 0
module fidelity: 106/106 exact, 100.000000% of compared bytes
ROM-build analysis: PASS

The 1 compiled is d_a_trs_trap.cpp itself, so the change did reach the compiler rather than being served from cache.

Head also carries the merge of current main (48ed22b76) that this PR needed for composition; that merge was byte-gated separately before this commit.

Still open on this PR and not claimed as done: the retained compiler constraints still need the pinned experiment evidence notes/agents/SOURCE-REVIEW-CUTOVER.md requires, and any deferred reconstruction still needs its issue and next owner. I have not represented this as a source-review pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Y4FxdKHG3a6hQRYRAbx29c

lunavyqo and others added 2 commits September 15, 2026 12:51
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

@andrewboudreau andrewboudreau left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Independent recheck at 1477adc72dd9d2b59c0b9cca5f84524430b37a38: TRAP-2709-01 is fixed. The dispatch table is bound to daTrsTrap_c, the fake C receiver is gone, and the disproved representation claim has been corrected. The additional direct mStateTimer reset also passes the fresh check: all 5 configured methods in d_a_trs_trap.cpp are VERIFIED, with zero warnings/blocking results.

This resolves the specific finding. It is not a whole-candidate Source review pass or current-main composition acceptance. I am coordinating integration and retaining those independent gates before landing the source PR.

TRAP-2709-01 was already fixed on this branch: 395312c removed the opaque
`struct C` PMF receiver and the false claim that a polymorphic class cannot use
the ROM's representation, and 1477adc unified the mStateTimer spelling. The
reviewer confirmed that at 1477adc. Nothing is re-applied here.

What was still outstanding from the review was the evidence around what the
candidate RETAINS, and two committed claims that had gone stale against it:

- notes/experiments/trap-2709-statetimer.md still said the disproved dual
  spelling was "left in place" and that "the branch comment over-claims".
  1477adc had already adopted the unified spelling, so the note contradicted
  the source it documents. It now records the variant as the shipped form.
- d_a_trs_trap.cpp's InitResources comment cited the swapped strh at
  +0x29c/+0x2a0; the pinned experiment measured +0x2a0/+0x2a4. The comment now
  matches its own evidence, and trap-2709-v16order.md drops the stale "off by
  one slot" aside. Comment-only, so it moves no byte.
- Every experiment note now states its disposition in the vocabulary
  notes/agents/SOURCE-REVIEW-CUTOVER.md defines, and the deferred entry names
  its durable thread (this PR, until a daTrsTrap_c class issue exists), its next
  owner and the concrete work that unblocks each of its three items.
- notes/agents/handoffs/pr-2709-source-review-fixes.md collects the finding ->
  disposition -> artifact table and the re-proof below.

Re-proved here, not taken from the review:

- rombuild.py -j16 --no-rom --no-cache: all 8754 enrolled files compiled from
  source with no cache; 11,207 source-built functions reproducing, 0
  mismatching; module fidelity 106/106 exact; ROM-build analysis PASS. Re-run
  cached after the comment correction: 8753 reused, 1 compiled, same verdicts.
- linkcheck.py over all 11 of the class's configured functions, including
  _ZN11daTrsTrap_c8BehaviorEv (ov063 0x0211ce74, size 0x8c): every one VERIFIED,
  diffs [], blind 0.
- No function added or removed: e406d2a's pre-fix source and this head's
  source compile, under the build's exact flags, to the byte-identical object
  (sha256 240001deaa87109e2bdc68ad52c44e805ad1391f7f0ae8c60037981aa20bd8c3,
  3648 bytes). It defines exactly the five configured methods, 0x44 + 0x4 +
  0x40 + 0x8c + 0x370 = 0x484, exactly the delinks range 0x0211cdec..0x0211d270.
- check_dead_references.py, check_decl_agreement.py and check_src_tu.py clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G1Gdj5fTjMsW2VjRLpXxYA
andrewboudreau
andrewboudreau previously approved these changes Sep 18, 2026

@andrewboudreau andrewboudreau left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

TRAP-2709-01: resolved. Verified on the current head, not on the response text.

d_a_trs_trap.cpp:63 now reads typedef void (daTrsTrap_c::*PMF)(); and the
dispatch at line 228 is (this->*data_ov063_0211ef38[idx])(). The opaque
struct C forward declaration and the ((C *)this) receiver cast are gone, and
the comment now states the records are "bound to this trap's own class" — so the
claim that the polymorphic class could not use the ROM representation is
withdrawn along with the construct it justified. The one remaining "cannot" in
the file is about block-scope declarations in a C++-named member, which is a
different and correct statement.

PR validation is green. review and Source review are red, but both are
advisory: only PR validation is a required check on main, and the review
queue has been dormant since 2026-09-11, so those reds carry no information
about this PR.

Clearing my block. As my original review said, this was an initial blocking
source review rather than whole-PR acceptance — this approval resolves the
finding I raised and does not certify the remaining deferred items.

Resolved on each file's key structure, not textually.

config/converted-baseline.json (the only textual conflict)
  Merged as a SET, not as lines. base=2812, ours=2812 (+3 -3),
  theirs=2813 (+6 -5); no identity is added by one side and removed by
  the other. Result 2813 = 2812 + 3 + 6 - 3 - 5, with count == list
  length == deduplicated length == 2813, re-emitted in
  tiers_ratchet.write_baseline()'s exact form (sorted, indent=2, LF).
  Main's copy had the four daObjCtKaitendai_c rows inserted out of
  order; sorting restores the canonical shape --update produces.

config/decl-agreement-baseline.json (git auto-merged; audited anyway)
  Re-merged per key over known[symbol][file]: base=13413, ours=13413,
  theirs=13385 entries -> 13385 merged (13280 unchanged, 4 ours-only,
  215 theirs-only), zero keys both sides moved differently, zero
  entries matching neither side. The 4 ours-only keys are exactly this
  PR's shard-to-TU move. Key-for-key identical to git's textual result
  (0 keys either-only, 0 value differences), so the textual merge was
  correct here; the file is re-serialized in write_baseline() form,
  which also re-sorts the 7 symbols main left unsorted.

attribution.json (git auto-merged; audited anyway)
  This branch never touched it, so the merge is main's file verbatim.
  Proved as a key union regardless: base=3422, ours=3422, theirs=3437,
  merged=3437 == |ours union theirs|, with nothing lost from either
  side, no value changed, and no key from nowhere.

config/arm9/overlays/ov063/delinks.txt (git auto-merged; audited anyway)
  Both sides edit this file in disjoint address ranges -- this PR folds
  daTrsTrap_c at 0x0211cdec.., main folds daTrs_c at 0x0211ae40...
  Audited as blocks: 131 = 141 base + 2 ours + 3 theirs - 9 ours
  - 6 theirs, every kept block's body equal to one side's, and the 127
  .text ranges still tile 0x02115ee0-0x0211e1c0 with zero gaps and zero
  overlaps.

symbols/actor_renames.tsv
  Append log, touched only by main (3620 -> 3626 rows); this branch's
  copy is identical to the merge base, so the merge is main's file
  byte for byte. No row lost, none duplicated.

No modify/delete conflict arose, and none was hidden: for all 9 files
this PR deletes, main's blob is identical to the merge base's, and no
daTrsTrap_c path appears anywhere in main's diff, so accepting the
deletions reverts nothing of main's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G1Gdj5fTjMsW2VjRLpXxYA
The promotion folds these functions into the surviving TU, and
attribution.json was given one owner for all of them -- the surviving
file's file-level owner -- so every function a different contributor
matched lost its credit. Each row below restores the owner the
attribution gate reports for that function at the merge base.

Eight are tangosdev; OnPendingDestroy is andrewboudreau.

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

Copy link
Copy Markdown
Collaborator

Restored the credit this promotion dropped

Folding the per-function sources into the daTrsTrap_c TU wrote one owner onto
every absorbed function -- the surviving file's file-level owner -- so each
function a different contributor actually matched lost its credit. Neither gate
on main can see this today: prepush_attribution.py compares the surviving
basename as a file before it reaches the promotion checks, and chaos_db_ci.py
ignores path#symbol keys entirely. #2753 repairs both.

Measured with the repaired gate against the merge base:

consolidated with credit intact changed lost
before 0 0 9
after 9 0 0

The owners below are the gate's own prior-owner column, not git blame:
ownership is the chaos-DB match finisher / first matcher, which is frequently
not the last person to touch the file.

destination function owner restored
src/game/actors/daTrsTrap_c/d_a_trs_trap.cpp _ZN11daTrsTrap_c13InitResourcesEv tangosdev
src/game/actors/daTrsTrap_c/d_a_trs_trap.cpp _ZN11daTrsTrap_c16CleanupResourcesEv tangosdev
src/game/actors/daTrsTrap_c/d_a_trs_trap.cpp _ZN11daTrsTrap_c16OnPendingDestroyEv andrewboudreau
src/game/actors/daTrsTrap_c/d_a_trs_trap.cpp _ZN11daTrsTrap_c6RenderEv tangosdev
src/game/actors/daTrsTrap_c/d_a_trs_trap.cpp _ZN11daTrsTrap_c8BehaviorEv tangosdev
src/game/actors/daTrsTrap_c/d_a_trs_trap_classinits.cpp daTrsTrap_c_classInit_BOOKSHELF tangosdev
src/game/actors/daTrsTrap_c/d_a_trs_trap_classinits.cpp daTrsTrap_c_classInit_KAIDAN tangosdev
src/game/actors/daTrsTrap_c/d_a_trs_trap_classinits.cpp daTrsTrap_c_classInit_MERRYGOROUND tangosdev
src/game/actors/daTrsTrap_c/d_a_trs_trap_classinits.cpp daTrsTrap_c_classInit_TERESAPIT tangosdev

Every row is a member-level path#symbol override. No path-wide override was
added for the promoted file -- that would re-create exactly the masking the gate
was fixed to see through.

🤖 Generated with Claude Code

https://claude.ai/code/session_01G1Gdj5fTjMsW2VjRLpXxYA

@andrewboudreau
andrewboudreau merged commit 2e9087a into tangosdev:main Sep 18, 2026
16 of 17 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