Skip to content

Re-bank the two daObjAbuku_c paths #1996 absorbed, and check the ratchet on main - #2011

Merged
andrewboudreau merged 1 commit into
mainfrom
fix/rebank-abuku
Aug 30, 2026
Merged

Re-bank the two daObjAbuku_c paths #1996 absorbed, and check the ratchet on main#2011
andrewboudreau merged 1 commit into
mainfrom
fix/rebank-abuku

Conversation

@andrewboudreau

Copy link
Copy Markdown
Collaborator

Main has been out of sync on the CONVERTED ratchet since #1996 merged. Every PR touching src/** inherits the red. #1978 is currently failing for this and it has nothing to do with ov002.

What happened

config/converted-baseline.json banks src/_ZN12daObjAbuku_cD0Ev.cpp and src/_ZN12daObjAbuku_cD1Ev.cpp. #1996 deleted both when it promoted the ov002/daObjAbuku_c translation unit.

No one's checks were wrong — they never overlapped. #1996's green ran against a base predating #2007, and #2007's re-bank (1957 → 2567) is what first banked those two files. By the time #1996 merged, the paths it deletes were sitting in a baseline its CI had never read. The ratchet workflow only ran on: pull_request, so main itself was never checked, and the breakage surfaced on the next unrelated PR instead.

The fix

The removal is legitimate, so it is banked with a reason rather than reverted. tiers_ratchet.py diagnosed it itself:

MOVED -- absorbed into src/actors/daObjAbuku_c.cpp by TU promotion
(ov002/daObjAbuku_c), which fails: No raw offset arithmetic
(*(u32*)(c + 0x74)); No unk_<off> fields; Calls things by real names,
not mangled _Z

A reconstructed TU must spell vague-linkage symbols directly (_ZN7fBase_cnwEj, _ZN8dActor_cC2Ev, _ZN8dActor_cD2Ev) or its range will not link, so no_mangled_refs structurally cannot pass for an absorbing file. Byte-match outranks readability. Both removals are logged to config/converted-backslide-exceptions.jsonl with that reason. No source file changed and no byte moved. Baseline 2567 → 2565.

The push: [main] trigger

The workflow's design note asserted that staleness here "only ever runs one way" — permissive, never falsely red, so no PR ever needs to re-bank in order to pass. That is true for conversions, which only add.

TU promotion is the exception: it removes banked paths. The note now says so, and cites this incident, so the next person reading it does not re-derive it from a red build.

The trigger gates nothing — there is no branch protection and a red main is advisory. What it buys is attribution: the merge that desynchronises the baseline goes red itself, instead of ambushing whoever opens the next PR.

This matters more as the queue drains. Every remaining TU-promotion PR (#1993 with 26 TUs, #1995, #2000, #2002, #2005) will hit the same removal, and each one should bank its own reason rather than leaving it for the next branch to discover.

Verification

tiers_ratchet --check        PASS   baseline 2565   current 2565
pytest tools/test_tiers.py   29 passed
check_dead_references        no new dead references
port_refcheck                405 checked, all resolve
check_src_tu_compiles        88/88

🤖 Generated with Claude Code

https://claude.ai/code/session_01WdCK1xgrJdiJzPCh3bAJfQ

…het on main

Main has been out of sync since #1996 merged. `config/converted-baseline.json`
banked `src/_ZN12daObjAbuku_cD0Ev.cpp` and `src/_ZN12daObjAbuku_cD1Ev.cpp`,
which that PR deleted when it promoted the ov002/daObjAbuku_c translation unit.

Nobody's checks were wrong; they just never overlapped. #1996's green ran
against a base predating #2007's re-bank, which is what first banked those two
files. By the time #1996 merged, the paths it deletes were in the baseline it
never re-read. The next unrelated PR to touch src/** -- #1978, which has
nothing to do with ov002 -- is the one that went red.

The removal is legitimate and is banked with a reason, not reverted:

  MOVED -- absorbed into src/actors/daObjAbuku_c.cpp by TU promotion
  (ov002/daObjAbuku_c), which fails: No raw offset arithmetic; No unk_<off>
  fields; Calls things by real names, not mangled _Z

A reconstructed TU must spell vague-linkage symbols directly
(_ZN7fBase_cnwEj, _ZN8dActor_cC2Ev, _ZN8dActor_cD2Ev) or its range will not
link, so `no_mangled_refs` structurally cannot pass for an absorbing file.
Byte-match outranks readability. No source changed and no byte moved.

Also adds a `push: [main]` trigger. The workflow's design note claimed
staleness "only ever runs one way" -- permissive, never falsely red. TU
promotion is the exception, because it REMOVES banked paths, and the note now
says so. The trigger gates nothing (no branch protection; a red main is
advisory) but it attributes the breakage to the merge that caused it instead
of to whoever opens the next PR.

  tiers_ratchet --check        PASS  baseline 2565  current 2565
  pytest tools/test_tiers.py   29 passed
  check_dead_references        no new dead references

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

tangos-validator Bot commented Aug 30, 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,042 / 11,347 (97.31%, +0)
Byte-verified code bytes 2,049,508 / 2,211,124 (92.69%, +0)
Claimed, not byte-verified 174 functions, 55,796 bytes (+0)
Perfect source moves 0 R100
Enrolled ranges (delinks complete) 11,058 functions, 2,052,772 bytes (92.84%, +0) -- differs from byte-verified by +16
Contributor credit 0 added, 0 changed, 0 lost
Relocation check 0 checked; no affected slots
Module fidelity 106/106 exact; 100.000000% compared bytes
Code linked from verified source 11,087 functions, 2,066,772 bytes (93.47%)
Module bytes from source 2,066,772 / 3,049,600 (67.8%); 811,492 (26.6%) are data no delink entry reaches
ROM data reproduced from source 447 symbol(s) exact, 242 partial, 15 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 174 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,216 this project calls matched.

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 added a commit that referenced this pull request Aug 30, 2026
Two files conflicted, both machine-generated.

config/converted-baseline.json -- resolved to origin/main's file VERBATIM.
Not by regeneration, not by key union, not --ours/--theirs. `--check` only
asserts current >= banked, so a PR that banks a smaller set passes green and
silently lowers the floor. This branch's own TU promotion legitimately turns
four banked per-symbol paths into one absorbing file, so ANY regeneration
here writes 2562 -- below main's 2567 and below the 2565 that PR #2011 will
leave. Leaving the file identical to main keeps the floor, drops the file
from this PR's diff, and costs nothing: `--check` resolves all four dBase_c
paths through config/tu_manifest.d/arm9/ActorDerived.json as

  MOVED -- absorbed into src/actors/ActorDerived.cpp by TU promotion
  (arm9/ActorDerived); that file passes all five, so nothing readable was lost

which classify_missing() counts as a move, not a backslide. Verified against
a simulated post-#2011 baseline: "CONVERTED ratchet PASS  baseline 2565
current 2562  (+1 gained, not yet banked)  (4 moved into a promoted TU)".

notes/cpp-tu-current-state.md -- regenerated over the merged tree with
`python tools/cpp_tu_state.py --write-note`.

attribution.json auto-merged as a clean key union: 845 override keys at the
merge base, +5 ours, +7 theirs, 857 after, nothing dropped.
config/match_attempts.jsonl and config/match_provenance.jsonl are untouched
by this branch, so their union merge driver had no edited row to mangle;
both now equal origin/main byte for byte.

The consolidation this PR exists for is intact. config/arm9/delinks.txt still
collapses five entries into one `complete` src/actors/ActorDerived.cpp over
.text 0x02013e80-0x02013f28, and 0x24 + 0x38 + 0x0c + 0x0c + 0x34 = 0xa8
closes exactly.
@andrewboudreau
andrewboudreau merged commit bfd908b into main Aug 30, 2026
4 checks passed
@andrewboudreau
andrewboudreau deleted the fix/rebank-abuku branch August 30, 2026 15:04
andrewboudreau added a commit that referenced this pull request Aug 30, 2026
Re-merges main now that #2011 has re-banked the two daObjAbuku_c paths
that #1996 absorbed, which was main's own ratchet desync and not this
PR's doing.

- config/converted-baseline.json: REGENERATED from main's 2565 with
  tools/tiers_ratchet.py --update -- never resolved by side or key union.
  New count 2559 = 2565 minus the six per-symbol files this PR's
  ov070/daKpFr_c promotion absorbs. All six are classified
  "MOVED -- absorbed into src/actors/daKpFr_c.cpp by TU promotion
  (ov070/daKpFr_c)" by the tool's own classify_missing(), and that file
  exists and is tracked in this tree. Zero genuine removals.

- config/converted-backslide-exceptions.jsonl: the union driver produced
  duplicate daObjAbuku_c rows (this branch's earlier pair plus #2011's).
  #2011's authoritative rows are kept and the redundant pair dropped, so
  each path is one row. The six daKpFr_c rows this branch already logged
  are unchanged; no new rows were needed.

- notes/cpp-tu-current-state.md: regenerated with tools/cpp_tu_state.py
  --write-note; --check-note is clean.

No source file, delinks entry, or byte changed in this merge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WdCK1xgrJdiJzPCh3bAJfQ
andrewboudreau added a commit that referenced this pull request Aug 30, 2026
Drops this branch's two redundant daObjAbuku_c backslide rows in favour of
#2011's authoritative pair (the union merge driver had produced one of each),
and re-regenerates config/converted-baseline.json from the parent branch's
2559 with tools/tiers_ratchet.py --update.

Count 2552 = 2559 minus the seven per-symbol files this PR's ov070/daKrpa_c
promotion absorbs. All seven are classified "MOVED -- absorbed into
src/actors/daKrpa_c.cpp by TU promotion (ov070/daKrpa_c)" by the tool's own
classify_missing(); that file exists and is git-tracked here. Zero genuine
removals, and all seven already had rows from this branch's earlier run, so
no duplicate rows were added.

notes/cpp-tu-current-state.md regenerated; --check-note clean.
No source file, delinks entry, or byte changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WdCK1xgrJdiJzPCh3bAJfQ
Alberto12345678999 pushed a commit to Alberto12345678999/sm64ds-decomp that referenced this pull request Aug 30, 2026
Both were introduced by me and both actively mislead. An agent working tangosdev#1993
read the second one, believed the gate was unwired, and spent a cycle on a
theory that could not be true.

1. "NOT WIRED INTO ANYTHING YET -- deliberately." False since tangosdev#2011, which
   added .github/workflows/converted-ratchet.yml (pull_request + push: main).
   Replaced with what the workflow actually does, pointing at its `on:` block
   as the authoritative path list rather than duplicating it here -- the
   duplicate is what would go stale next.

2. "staleness only ever runs one way." False for two shapes, both of which
   cost real time this week:

   - TU promotion removes banked paths. classify_missing() resolves them
     through the TU manifest and reports MOVED; when the absorbing file is
     itself CONVERTED the removal is absorbed_clean and needs no --reason.
     The banked COUNT drops and that is CORRECT. Stated explicitly, because
     I circulated the opposite rule ("the floor is 2565, never go below it")
     to three agents and two of them had to come back with the source to
     correct me. This is a SET ratchet; there is no floor number to defend.

   - A plain file rename has no detection at all: it reports GONE and demands
     a --reason, which writes a permanent fake backslide row. The workaround
     (apply renames to the parent's banked set first, then regenerate) is
     recorded until the detection lands.

Also records that a CI red here is usually a base desync, not a regression --
the tangosdev#1996 shape, where a PR cut before a re-bank inherits the red and the next
unrelated src/** PR is the one that turns red for it. Fix is to merge main in,
never to lower the pin.

Docstring only. No behaviour change; --check still PASS 2565/2565.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WdCK1xgrJdiJzPCh3bAJfQ
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