Skip to content

Fix main: name the tubuild test's real input by symbol, not by a promoted path - #2073

Merged
andrewboudreau merged 1 commit into
mainfrom
fix/tubuild-test-dead-reference
Aug 31, 2026
Merged

Fix main: name the tubuild test's real input by symbol, not by a promoted path#2073
andrewboudreau merged 1 commit into
mainfrom
fix/tubuild-test-dead-reference

Conversation

@andrewboudreau

Copy link
Copy Markdown
Collaborator

dead references is red on main. One docstring line, and the cause is worth recording.

FAIL: 1 prose reference(s) name a path that does not exist:

  tools/test_tubuild.py
      names `src/func_ov006_020f8224.c`, which is not in the tree

Red at 6d8f8e529run 33378442037. Reproduced in a clean worktree at ad9dbc8c0, green after this commit.

How two green PRs made a red main

tools/test_tubuild.py landed in #2072. Its Allman-brace regression case documents the real-world input it was built from:

"""The real input: src/func_ov006_020f8224.c (ov006/dScMgMCarlo_c), whose
shadow struct puts its opening brace on the next line. ..."""

#2071 promoted that file into src/actors/dScMgMCarlo_c.cpp about an hour later. The path is gone; the prose still names it.

Neither PR could have caught this:

when its gate ran what it saw
#2072 before #2071 landed src/func_ov006_020f8224.c present — reference resolves
#2071 premerge_check vs merge tree 4e0d92d28a7d test_tubuild.py did not exist yet

Both were individually correct and 8/8 on their own merge trees. This is the merge-tree hazard one step removed: gating each PR against main does not gate a pair of PRs against each other, and the window here was 65 minutes.

I own this one twice over — I merged both, and the citation exists because my #2071 review asked for it: "Please put both failing inputs in the test file — the fix without the inputs leaves us re-deriving them next time." That was the right ask. Citing the input by path was the part that had a shelf life.

The fix

"""The real input was the legacy source for `func_ov006_020f8224`, since
promoted into the ov006/dScMgMCarlo_c TU -- named by symbol rather than by
path on purpose, because the path no longer exists and check_dead_references
reads any `a/b` token in prose as a live repo-rooted reference. ..."""

The symbol is the durable identifier: func_ov006_020f8224 survives both TU promotion and class rename, and check_dead_references only resolves a/b-shaped path tokens, so a bare symbol cannot dangle. The example loses nothing — the symbol is already asserted twice in the test body below it.

The docstring says why the path is absent. Without that, the next reader restores it as a helpful clarification and we are back here.

ov006/dScMgMCarlo_c is kept as-is: it is a/b-shaped but demonstrably does not resolve as a reference today, since it was already in the failing file and the gate flagged only the src/ token.

Verified

check_dead_references  before: FAIL: 1 prose reference(s)
check_dead_references  after : no new dead references / no broken markdown links
check_python_names     PASS   (262 files, 0 unresolvable)
test_tubuild.py        52 passed, 2 failed

Those 2 failures are pre-existing and unrelated — I measured them against the unmodified file in the same worktree and they fail identically:

test_verify_reproduces_pilot_1s_7_of_7_and_clean_objisolate
test_compile_report_matches_the_pilots_object_inventory

Both compile src_tu/actors/PoleLift.cpp for real, so they only execute on a toolchain-wired worktree — in CI they cannot run, which is why tool tests is green on main while these are red locally. Filing that separately; it is not this PR's business, but it does mean the tool tests green is hollow for those two cases.

Deliberately not bundled

--update also wants to drop a now-stale baseline entry:

- { "file": "notes/src-domain-buckets.md", "ref": "src/game/actors" }

That path exists on main now, so the baseline is carrying a dead entry that would mask a future real break at src/game/actors. Real, but unrelated cleanup in a tracked config file that every ledger PR conflicts on — and main is red right now. Separate PR.

…oted path

`dead references` is red on main. tools/test_tubuild.py, landed in #2072,
cites `src/func_ov006_020f8224.c` as the real-world input its Allman-brace
case was built from. #2071 promoted that file into the ov006/dScMgMCarlo_c
TU an hour later, so the path is gone and the prose reference dangles.

Neither PR could see it. #2072's dead-references run happened while the
file still existed; #2071's premerge_check ran against a merge tree that
predated #2072. The two are individually green and red in combination --
the merge-tree hazard, one step removed.

Fix names the input by symbol instead of by path. `func_ov006_020f8224`
survives both promotion and rename, and check_dead_references reads only
`a/b`-shaped path tokens, so a symbol cannot dangle. The docstring says
why, so the path does not get helpfully restored later.

Not bundled, deliberately: `--update` would also drop the now-stale
`src/game/actors` baseline entry. That is real but unrelated cleanup in a
tracked config file, and main is red now.
@tangos-validator

tangos-validator Bot commented Aug 31, 2026

Copy link
Copy Markdown

✅ PR validation — Passed

noverify: no source/build-data changes in this PR

Each changed src/*.c|*.cpp is compiled and its relocated bytes compared to the binary data on a private build box. Passing requires every changed file to reproduce the ROM byte-for-byte with correct relocation targets — this catches WRONG-DEST relocations and non-reproducing near-misses that ledger-scoped linkcheck skips.

@andrewboudreau
andrewboudreau merged commit 1090f44 into main Aug 31, 2026
6 checks passed
@andrewboudreau
andrewboudreau deleted the fix/tubuild-test-dead-reference branch August 31, 2026 09:43
andrewboudreau added a commit that referenced this pull request Aug 31, 2026
Both are pre-existing on main and both resolve today, so no gate is red --
but they are the per-symbol shape that dies twice over, on rename AND on TU
promotion, and one of them is live ammunition right now:

    src/_ZN8PoleLiftD1Ev.cpp   src_tu/actors/PoleLift.cpp already exists
    src/_ZN5Stage11RenderModelEv.cpp

A PoleLift promotion deletes the first one out from under this docstring and
takes main red on dead references, which is exactly how main broke earlier
today at 6d8f8e5 (fixed in #2073).

Named by mangled symbol instead. check_dead_references reads only a/b-shaped
path tokens, so `_ZN8PoleLiftD1Ev` cannot dangle, and the symbol survives both
rename and promotion. The concrete evidence in both comments -- the local
ModelComponents stand-in, and the 0x80/0x158/0x50 padding numbers -- is
unchanged; only the citation spelling moved.
andrewboudreau added a commit that referenced this pull request Aug 31, 2026
…prove work (#2074)

* Use prose examples the cartridge agrees with, and make the gate test prove work

Re-cut of #2070. Its diagnosis was right -- a class-specific path hard-coded
in tool prose is a live reference that check_dead_references resolves, so it
goes red the moment the class is renamed. Its substitute had the same defect.

`tools/rtti_name_audit.py --class`, walking _ZTV-4 -> _ZTI -> _ZTS in the
cartridge:

  dActor_c   ROM 8dActor_c    AGREES
  Camera     ROM 9dCamera_c   DISAGREES -- #2070's replacement
  Amp        ROM 7daBrq_c     DISAGREES -- what #2070 replaced

Both sides of that swap are in the 259-of-541 coined set and both are
scheduled for rename, so #2070 bought nothing. dActor_c and dScMgBase_c
agree with the cartridge and nothing above them can re-key their names.

marker_evidence.py keeps its concrete struct sketch and loses only the
per-symbol path. Rewriting a specific docstring into abstract prose costs
explanatory value for nothing; the path was the only part that could die.
A per-symbol file dies twice over -- on rename, and on TU promotion folding
it into src/actors/<Class>.cpp.

test_a_real_tree_header_still_parses asserted only rc == 0, which a header
the parser SKIPPED satisfies just as well:

  include/dActor_c.h  rc=0  33 commented fields, 0 mismatched
  include/fBase_c.h   rc=0  skipped -- polymorphic, implicit vptr not modelled

The second is the exact "reported a pass and checked nothing" shape this
file exists to catch, and the old assertion passed on it. Now the test reads
the gate's own output and requires a positive checked-field count, so a
future substitution into a skipped header fails loudly instead of quietly
asserting nothing.

check_dead_references clean, check_python_names PASS, 20/20 tests pass.

* Name two more doomed prose paths by symbol instead

Both are pre-existing on main and both resolve today, so no gate is red --
but they are the per-symbol shape that dies twice over, on rename AND on TU
promotion, and one of them is live ammunition right now:

    src/_ZN8PoleLiftD1Ev.cpp   src_tu/actors/PoleLift.cpp already exists
    src/_ZN5Stage11RenderModelEv.cpp

A PoleLift promotion deletes the first one out from under this docstring and
takes main red on dead references, which is exactly how main broke earlier
today at 6d8f8e5 (fixed in #2073).

Named by mangled symbol instead. check_dead_references reads only a/b-shaped
path tokens, so `_ZN8PoleLiftD1Ev` cannot dangle, and the symbol survives both
rename and promotion. The concrete evidence in both comments -- the local
ModelComponents stand-in, and the 0x80/0x158/0x50 padding numbers -- is
unchanged; only the citation spelling moved.
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