mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-29 23:24:32 -04:00
fix(phase-30 S48): §166 — the destination-TU oracle, and stop printing a guess as a finding
gate_stage labelled every "standalone MATCH / whole-binary DIFF" with "(declaration/TU plumbing)". The tool never checked for a declaration conflict — that was a GUESS printed as a diagnosis, and func_8017F2D4 carried it through SEVEN attempts across five waves while every agent hunted codegen. The body was byte-correct from the first attempt; the notes had simply named the wrong destination TU (a file holding only a caller + prototype), and splicing there is a no-op that leaves the INCLUDE_ASM bytes in place. - gate_stage now says only what is true (the two oracles disagree) and hands over the check that resolves it, instead of naming a cause it did not measure. - §166a banks the oracle: asm/<ov>/nonmatchings/<TU_stem>/<fn>.s => the INCLUDE_ASM is in src/<ov>/<TU_stem>.c. The third path component IS the TU stem, derived from the split config, and it beats any prose citation — a grep for the function name also hits callers and prototypes in OTHER TUs and reads exactly like a destination hit. - Plus the two probe gotchas that cost wave-5/6 agents real time: the wrong --aspsx-version fakes ~32 ori-vs-addiu mismatches, and a collateral-drift check must filter to sized symbols (nm -S) or the zero-size .NON_MATCHING aliases all report false drift. cookbook_index.py: 506 sections.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
|
||||
>
|
||||
> `docs/matching-cookbook.md` is ~716 KB / 505 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
|
||||
> `docs/matching-cookbook.md` is ~716 KB / 506 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
|
||||
|
||||
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
|
||||
|
||||
@@ -393,7 +393,7 @@
|
||||
- **§163z** — THE UNVETTED REMAINDER (do not cite as law; each needs a dedupe pass) <sub>L11825</sub>
|
||||
- **§3-The** — ADDRESS-CLASS TABLE: which load/store pairs even REACH the `/s` clause (P30 S48 wave 4, `func_80185B44`, ov_SC03_014) <sub>L14339</sub>
|
||||
|
||||
### integration / TU plumbing (38)
|
||||
### integration / TU plumbing (39)
|
||||
|
||||
- **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) <sub>L437</sub>
|
||||
- **§8d** — Templating a body INTO a TU must not CHANGE its declaration environment — demote the carried data externs (Phase 26 session 8, byte-proven on `func_8015AE2C` ×133) <sub>L483</sub>
|
||||
@@ -433,8 +433,9 @@
|
||||
- **§3-The** — same swallow, twice more, in the integration spine <sub>L9706</sub>
|
||||
- **§3-A.** — Payload word0 is a global MODULE ID; code starts after the header <sub>L10524</sub>
|
||||
- **§162** — THE LICM PAIR: what makes an address a movable AT ALL, and why the preheader order is the body order (P30 S47, `ov_MAIN_012`) <sub>L11140</sub>
|
||||
- **§166** — THE DESTINATION-TU ORACLE (P30 S48): the seven-attempt bug that was never codegen <sub>L14899</sub>
|
||||
|
||||
### build graph, splat & the harness (107)
|
||||
### build graph, splat & the harness (108)
|
||||
|
||||
- **§4** — Flag/toolchain gotchas <sub>L190</sub>
|
||||
- **Build** — mechanism — per-file opt override (splat resegmentation) <sub>L288</sub>
|
||||
@@ -543,6 +544,7 @@
|
||||
- **§162** — S48 WAVE-1 HARVEST (P30, 2026-08-11): the reach-ordered sibling campaign's first 12 targets <sub>L11011</sub>
|
||||
- **§163** — S48 WAVES 2-3 HARVEST (P30, 2026-08-11/12): the five that were byte-probed and are actionable <sub>L11757</sub>
|
||||
- **§165** — S48 WAVE-4 HARVEST (P30, 2026-08-12): banked the same day the wave landed <sub>L13686</sub>
|
||||
- **§166** — THE DESTINATION-TU ORACLE (P30 S48): the seven-attempt bug that was never codegen <sub>L14899</sub>
|
||||
|
||||
### process, measurement & doctrine (71)
|
||||
|
||||
@@ -1295,3 +1297,4 @@
|
||||
- **§16Z** — SHARPENS *(sharpens §37 "the /s-DEP LATTICE", §136-13, §136-14, §16Xy, §162q, `gcc-2.7.2-map/sched.md` §64)* <sub>L14337</sub>
|
||||
- **§3-The** — ADDRESS-CLASS TABLE: which load/store pairs even REACH the `/s` clause (P30 S48 wave 4, `func_80185B44`, ov_SC03_014) <sub>L14339</sub>
|
||||
- **§165z** — REFUTED THIS WAVE: do NOT re-derive <sub>L14855</sub>
|
||||
- **§166** — THE DESTINATION-TU ORACLE (P30 S48): the seven-attempt bug that was never codegen <sub>L14899</sub>
|
||||
|
||||
@@ -14893,3 +14893,46 @@ Target shape — a subtract whose three registers are all specific:
|
||||
*Why:* Both halves fail. (1) NECESSITY, byte-refuted: replacing `if (t == 3) { goto sel_C94; }` with the duplicated body `if (t == 3) { sel = (u32)&D_801C3C94; goto set_sel; }` → MATCH 279. The 2-instruction `lui/addiu` + `j` tail clears §50-B's floor and jump.c merges it for you — this is precisely §164-69's 'a tail the compiler WILL merge must be duplic
|
||||
* **`func_8017F2D4`** — `s32 lt = mode < 0xA;` must be an explicit local because gcc-2.7.2 has no gcse and the single `slti` must precede the branch both arms need it after.
|
||||
*Why:* Byte-refuted by me: deleting the local and inlining the compare at both use sites — `if ((mode < 0xA) || (D_8011515A == 0x100))` and `if (!(mode < 0xA))` — gives MATCH 279. The C form is byte-INERT here, so it is not a lever and must not be taught as one. The mechanism phrasing is also imprecise: §164-52 byte-establishes that cse spans basic blocks
|
||||
|
||||
---
|
||||
|
||||
## §166 — THE DESTINATION-TU ORACLE (P30 S48): the seven-attempt bug that was never codegen
|
||||
|
||||
**§166a — THE SPLAT ASM SUBDIR *NAMES* THE DESTINATION TU. A PROSE CITATION THAT DISAGREES WITH IT IS
|
||||
WRONG.** *(NEW. Nothing in §52b/§161c/§163a/§165-01 — the whole decl-conflict family — covers "you
|
||||
are editing the wrong file". They all assume the TU is known.)*
|
||||
|
||||
asm/<overlay>/nonmatchings/<TU_stem>/<fn>.s ⇒ the INCLUDE_ASM is in src/<overlay>/<TU_stem>.c
|
||||
|
||||
The third path component **is** the TU stem, derived from the split config. It is authoritative.
|
||||
|
||||
**WHY THIS COSTS WAVES.** A `grep` for the function name also hits **callers** and **prototypes** in
|
||||
OTHER TUs of the same overlay, and those hits read exactly like a destination hit. `func_8017F2D4`
|
||||
was cited in five waves of notes as living in `ov_SC01_005_jr_8017C340.c` — that file holds only
|
||||
`ret = func_8017F2D4(c, ret);` and a prototype. The real `INCLUDE_ASM` is in
|
||||
`ov_SC01_005_jr_8017ED5C.c:3115`. Splicing into the wrong file is a **no-op**: the binary keeps its
|
||||
`INCLUDE_ASM` bytes, the SHA differs, and the run is recorded as a gate refusal.
|
||||
|
||||
**THE COMPOUNDING FAILURE — a guess printed as a finding.** `gate_stage` labelled every such refusal
|
||||
`match_one MATCH but gate rejected (declaration/TU plumbing)`. That string is not a measurement; the
|
||||
tool never checked for a declaration conflict. Seven attempts across five waves hunted codegen and
|
||||
decl conflicts on a body that was **byte-correct from the first attempt**. Fixed: the message now
|
||||
states only what is true (the two oracles disagree) and hands over this check first.
|
||||
|
||||
**THE RULE.** For ANY "standalone MATCH / whole-binary DIFF" entry: **re-derive the TU path from the
|
||||
asm subdir before hunting anything.** Then prove it in situ — splice into a private copy of the real
|
||||
TU (one directory deep, with a `shared` symlink so `../shared/engine_core.h` resolves), run the
|
||||
pinned triple end-to-end, and masked-diff your function out of the WHOLE-TU object.
|
||||
|
||||
**TWO PROBE GOTCHAS** (both paid for in wave-5/6 agent time):
|
||||
* the wrong `--aspsx-version` yields ~32 spurious mismatches **all** of the `ori`-vs-`addiu` li-form
|
||||
shape — that uniformity is the fingerprint of a version mismatch, never a codegen residual. Use
|
||||
`--aspsx-version=2.56 --expand-div`.
|
||||
* a collateral-drift check must filter to symbols with a **real size** (`nm -S`): the
|
||||
`*.NON_MATCHING` aliases are zero-size markers, so a masked diff falls back to the whole `.text`
|
||||
and reports every one of them as drift purely because your function's bytes changed.
|
||||
|
||||
*Byte evidence:* `func_8017F2D4` (ov_SC01_005 + ov_SC01_006, 279 ins). In-situ splice into BOTH real
|
||||
TUs: 279/279, 0 masked diffs, cpp/cc1 clean; collateral check 71/71 other sized symbols identical.
|
||||
The same agent corrected the family reach to **×2** (only two `.s` exist, byte-identical modulo the
|
||||
overlay name) against a map that claimed ×5.
|
||||
|
||||
+13
-2
@@ -450,8 +450,19 @@ def _run_gate_locked(drafts, binary, src, asm, out, good_sha, propagate, source_
|
||||
sm = re.search(r"//\s*@stuck:\s*(.+)", body)
|
||||
rclass = cm.group(1).strip() if cm else None # the worker's self-reported residual class
|
||||
note = sm.group(1).strip() if sm else None
|
||||
if kind == "match": # match_one says MATCH but the whole-binary gate rejected -> plumbing/TU conflict
|
||||
status, where = "near", note or "match_one MATCH but gate rejected (declaration/TU plumbing)"
|
||||
if kind == "match": # match_one says MATCH but the whole-binary gate rejected
|
||||
# ⚠ DO NOT NAME A CAUSE HERE. This used to read "(declaration/TU plumbing)" — a GUESS
|
||||
# printed as a finding. `func_8017F2D4` carried that label through SEVEN attempts across
|
||||
# five waves while every agent hunted codegen; the body was byte-correct the whole time
|
||||
# and the real fault was that the notes named the WRONG DESTINATION TU (a file holding
|
||||
# only a caller + prototype). No declaration conflict ever existed. A diagnosis the tool
|
||||
# did not measure must not be stated as one — say what is TRUE (the two oracles disagree)
|
||||
# and hand over the check that resolves it (P30 S48).
|
||||
status, where = "near", note or (
|
||||
"match_one MATCH but the whole-binary gate rejected — CAUSE NOT DETERMINED. "
|
||||
"FIRST re-derive the destination TU from the asm subdir: "
|
||||
"asm/<ov>/nonmatchings/<TU_stem>/<fn>.s => src/<ov>/<TU_stem>.c (the third path "
|
||||
"component IS the TU). Only then look for a decl conflict or a codegen residual.")
|
||||
near += 1 # …and COUNT it. It was logged as `near` and counted as NOTHING, so a
|
||||
# run of 63 such drafts printed "banked 0, near 0, failed 0" — three
|
||||
# zeros that do not sum to 63, and nobody ever added them up (R32).
|
||||
|
||||
Reference in New Issue
Block a user