tools: fix test_tubuild expectations that demanded #2066's defect back - #2075
Merged
Conversation
Two assertions in tools/test_tubuild.py went stale at #2066 (467bde0), which moved ~PoleLift() into the class body. One of them was not merely stale -- it asserted the anomaly #2066 fixed: assert "1 ordinal pair(s) NOT in ROM order: [(0, 1)]" in out An out-of-line destructor makes mwccarm emit D2/D0/D1 with D0 before D1, opposite the ROM; the pilot report called that non-fixable. Defining the destructor inline emits exactly the ROM's two variants in ROM order. So the only way to make this assertion pass by "fixing the code" would be to revert #2066. Measured across 467bde0^ -> 467bde0, swapping the shadow source and the class header together (the pre-#2066 source does not compile against the post-#2066 header, which is why this surfaced as a failing assert rather than a quietly wrong number): before 37 sections, 8 .text, D2 present, "1 ordinal pair(s) NOT in ROM order: [(0, 1)]", 12 unlicensed after 35 sections, 7 .text, no D2, "ALL MATCH, ROM order", 11 unlicensed Section arithmetic: each vague-linkage symbol that stops being emitted costs two sections, itself plus its own .rela. That is 43->37 at #1555 (3 symbols) and 37->35 here (1). Rather than bump the numbers, the stale expectations become regression guards stated as absences, so reintroducing an out-of-line definition fails loudly here: assert "NOT in ROM order" not in out assert "_ZN8PoleLiftD2Ev" not in out assert "UNLICENSED function symbols" not in out The last is an absence because tubuild prints no function block at all when the count is zero -- asserting "(0)" would never match. Negative control: reverting both files to 467bde0^ fails the new assertion at tools/test_tubuild.py:166. The guards have teeth. No path naming PoleLift appears in the new prose. PoleLift is a coined name the cartridge contradicts (ROM RTTI: 18daObjKm2_Ami_Bou_c) and the rename is a prerequisite for promoting this very TU, so such a path is a dead reference with a scheduled fuse -- see #2074. 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 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.
One of these tests asserted the defect #2066 fixed
tools/test_tubuild.pyhas two failing assertions (52 passed / 2 failedonmainat6c7d35b0c). Task #79 asked whether that is (a) stale expected strings or (b) a realPoleLiftregression from the #2066 inline-destructor flip, and said to read the actual output before assuming (a).Measured, and it is (a) — but with a sting. One of the two is not merely stale. It asserts the anomaly #2066 removed:
An out-of-line destructor makes mwccarm emit
D2/D0/D1with D0 ahead of D1, opposite the cartridge. #2066 (467bde020) moved the destructor into the class body, and the compiler then emits exactly the ROM's two variants in the ROM's order. So this test now demands the defect back: the only way to make it pass by "fixing the code" would be to revert #2066. That is worth more than the numbers below.Measured, not inferred
I reverted both #2066 files together — the shadow source alone will not compile against the post-#2066 header (
object 'PoleLift::~PoleLift()' redefined), which is precisely why this surfaced as a failing assert rather than a quietly wrong number — and rantubuild.py compileon each side:.text467bde020^_ZN8PoleLiftD2Evpresent1 ordinal pair(s) NOT in ROM order: [(0, 1)]467bde020ALL MATCH, ROM orderSection arithmetic: each vague-linkage symbol that stops being emitted costs two sections — the section itself plus its own
.rela. That is 43 → 37 at #1555 (three symbols: Platform's vtable and its two out-of-line destructors, anchored by giving Platform a key function) and 37 → 35 here (one). The docstring now carries all three rows so the next drift is diagnosable instead of mysterious.Stale expectations become regression guards
Bumping
37to35would fix the red and lose the information. Each stale expectation is instead restated as an absence, so reintroducing an out-of-line definition fails loudly right here:The last one is an absence rather than
"(0)"becausetubuild.py compileprints no function block at all when the count is zero. Asserting a count of zero would never have matched.Promotion is still correctly refused, but for a narrower reason than before: what remains unlicensed is
_ZTI8PoleLift/_ZTS8PoleLift, for which nocompiler_only_outputdisposition is admissible while the class carries a coined name the cartridge contradicts.Negative control
Same discipline as #2074 — a guard nobody has watched fail is a guess. Reverting both files to
467bde020^fails the new assertion:The guards have teeth. (A third assertion at line 112 also fails in that mixed state; that is an artifact of old source against today's manifest and I am not claiming it as evidence.)
No path names PoleLift
The new prose names the class and the mangled symbols, never a file path.
PoleLiftis a coined name the cartridge contradicts —— and the rename is a prerequisite for promoting this very TU, so
include/PoleLift.handsrc_tu/actors/PoleLift.cppare dead references with a scheduled fuse. That is the defect class #2074 landed to remove, and I caught two of them in my own first draft here. The docstring says why, so the next reader does not restore the paths as a helpful clarification.Gates
Base is
6c7d35b0c= currentorigin/main, andgit merge-base --is-ancestor origin/main HEADsucceeds, so the merge tree is the branch tree — these are merge-tree measurements, not proxies:Single file, tools-only, no
src/, noconfig/, no generated state.check_dead_referencesstill reports1 baselined reference(s) now resolve— that is the pre-existing stalesrc/game/actorsbaseline entry, not a failure and not from this branch; it is filed separately and deliberately kept out of this PR.Deliberately split out
tools/test_tubuild.pyhas 10 sites ofif not _toolchain(): return— a silent vacuous PASS, the same false-green shape the worktree skill warns about..github/workflows/tool-tests.ymlalready documents it (test_tubuild 28 real pass / 15 vacuous / 2 fail, "returnguards become skips"). Converting them to real skips needs a decision about taking apytestimport dependency in this file, which is a different question from this one, so it is not bundled here.