mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-27 05:56:00 -04:00
97cd2739b52358fccf8a2dafdc0b52a550e88282
486 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
97cd2739b5 |
fix(phase-29): the gate manufactured 3 false CC1-FAIL verdicts — carve-refusal, tree hygiene, R32 (§97)
A 15-draft harvest_verify batch reported CC1-FAIL=4 and `final SHA None`. Three of the four were the HARNESS, not the compiler. Checked the tree FIRST (the MISMATCH is a tree alarm, not a result), reverted to the committed baseline rather than reasoning about a half-applied state, rebuilt -> d19c9580 BYTE-IDENTICAL. No banked result was ever at risk: the byte-gate cannot manufacture a match, but it CAN manufacture a verdict — and verdicts are what the backlog and roadmap are built from. ORDERING PROVED THE CASCADE (R14): items 1-11 are real (9 PLUMBING, 2 DIFF), all before item 12 — jtbl_carve REFUSING func_8013B83C (§59(3) non-contiguous same-subseg table). Items 13-16 are four CC1-FAILs on the SAME ov_SC01_077_o0.o = one refused carve counted four times. THREE DEFECTS FIXED: 1. `_ok` was computed and IGNORED — a refused carve was spliced and built anyway into a guaranteed Error 33, filed as CC1-FAIL. Now a named CARVE-REFUSED class, skipped (one build cheaper). 2. attempt() never restored on failure, so the tree was dirty BETWEEN drafts — and _jtbl_snapshot() snapshots the tree AS IT FINDS IT, so a later carve captured an earlier FAILED draft's splice and its undo faithfully RE-APPLIED it, after the final _write(baseline). That is the entire `final SHA None` mechanism. Invariant restored: the tree is at baseline except while a draft is under test (atomic AND bisect branches). 3. The recovery's own `make extract` rc was unchecked (_sh does not raise — §93's sibling). Now loud. Plus an R32 assertion on the cleanup: at 0 verified a non-empty git status is residue, not a result; it names the files and the recovery command. It fired correctly on its first real run. MEASURED RECOVERY (same drafts, clean tree): func_8013B83C -> CARVE-REFUSED; func_801789AC -> PLUMBING (actionable); func_8017C974 -> DIFF (corroborates its agent's global_alloc spill diagnosis); func_80140958 -> CC1-FAIL (genuinely its own). final SHA None -> d19c9580; tracked diff empty. BLAST RADIUS OF §96, HONESTLY: the reconcile_tu span fix unblocked func_80176218 (banked, swept 133/137) and no other draft in the batch. 7 of the 9 PLUMBING are `conflicting types for <the function itself>` = the DEF-side self-decl axis conform_decls owns — the next lever, now a measured target list rather than a guess. cookbook §97. |
||
|
|
ea1d6587d6 |
feat(phase-29): func_80176218 family swept 133/137 (R22 140/140)
+134 functions banked total for this exemplar (1 + 133 members). Measured from the committed progress.fleet.md, not projected: fn-count 317,762 -> 317,896; instr-weighted 82.9 -> 83.2% (+43,818 ins); distinct-code 71.5 -> 72.3% (+126 unique fns — these members are genuine byte- VARIANTS that each count distinctly, not free dedup). VERIFY: R22 clean-fleet (make clean && extract-all && check-all) -> 140 passed, 0 failed of 140. make report fail-closed green: dedup-check 1886 validated / 0 failed, C1 coverage 239604/239604, 0 NON_MATCHING in any default build (G4). THE 4 FAILURES ARE CARRIED, NOT CONCLUDED. All four are ov_SC07_006/007/010/011 and all four differ from the other 133 in exactly one way: their sibling TU is _jr_8016AE5C.c, not _jr_801734BC.c — carved under func_8016AE5C, which was banked and swept in SESSION-21. That is the SAME four overlays and the SAME carve the SESSION-21 checkpoint flagged as "worth checking first" for func_8016B6BC's 0/137, which turned out to be a transitive type-carry (§94) rather than a wall. Each sibling reverted its byte-neutral self-decl edit cleanly, so no dead diff is left behind. Per §59 a sweep failure is a per-sibling INTEGRATION signal, not a codegen verdict — read one sibling's real gate result (COMPILE-fail vs byte-DIFF) before concluding. |
||
|
|
8c36ede849 |
feat(phase-29): func_80176218 banked (45,126 templ ins) + reconcile_tu span/R32 fix
THE DRAFT was failing in a CHAIN, one "next conflict" per gate cycle. Applied §95's own diagnostic law instead — splice once, dump EVERY cc1 error — and the whole set named the cause immediately: three errors on TWO axes (one data decl, two callee decls), not three problems. THE DATA ERROR WAS reconcile_tu AGAIN, ONE SHAPE DOWN (§96). split_statements returns comment- STRIPPED text WITH SPANS; the rewrite re-found each planned statement by comparing that text to a raw LINE, so `extern u8 D_80078E78; /* cur base ($s5) */` never matched. The decl was left unconformed WHILE THE USE-CAST PASS STILL FIRED -> a draft whose uses are cast for the TU's storage against the draft's own declaration -> cc1 reports `conflicting types` AT THE VERY DECL THE TOOL JUST CLAIMED TO FIX, exit 0, "reconciled: 3 symbols". FIX: rewrite by SPAN (the primitive existed — its docstring says spans are preserved *because drafts get rewritten*). Plus the R32 assertion the old code was missing: it had a dropped_check counter incremented in two places and NEVER COMPARED — "a loud failure nobody counts is exactly as invisible as a silent one" in miniature. Now declarators-in vs -out AND a per-symbol check that each planned tu.declaration() actually landed, both as `!!` notes so --strict exits non-zero. MEASURED: 3 -> 4 data symbols reconciled on the same draft; trailing comments preserved (H5). THE TWO CALLEE CONFLICTS were the other axis (reconcile_tu skips kind=='func' by construction): cast_call_sites (§20) conformed func_80177AD4 (TU `void (int, unsigned int)`) and func_80178298 (TU `(u32*, u8*, short, short)`) and cast each call site to the draft's intended widths. GATE: verified 1 / failed 0, d19c9580 BYTE-IDENTICAL. Write set is one overlay-local TU = T1 per the §63/§85 blast-radius taxonomy, so the per-binary gate is sufficient; the ×137 sweep is the T2 case and takes a full R22. |
||
|
|
db620d4b8d |
fix(phase-29): reconcile_tu dropped the sibling declarators of a multi-symbol extern line
THE DEFECT (on the banking path — gate_stage runs reconcile_tu): its rewrite replaced the draft's declaration LINE with the TU's declaration of the ONE conflicting symbol. A statement can declare several: 'extern u16 D_80078EB2, D_8011F82A, D_8011F82C, D_80078EB4, D_8011F8C4;' where only EB4 conflicts became 'extern s16 D_80078EB4;' — four symbols silently gone. WHY IT HID: the draft does not fail at the declaration. It fails later with 'D_8011F82A undeclared' at a USE, several conflicts down a peeling chain, nowhere near the cause. I peeled four separate 'next conflicts' out of func_80176218 before dumping ALL cc1 errors in ONE build and seeing three undeclared symbols that the tool itself had removed. FIX: group the plan by STATEMENT rather than by symbol; re-emit EVERY declarator (TU's version for the conflicting ones, the draft's own for the rest); note multi-declarator statements; and when a statement cannot be re-parsed, say so loudly instead of emitting only the planned symbols. VERIFIED: all 5 declarators survive, and the same draft now reconciles 3 symbols instead of 2 — the dropped ones had been hiding a further conflict. cookbook §95. The law (R32 again): a transform that REPLACES a syntactic unit must account for everything that unit contained — the STATEMENT, not the line, is the unit of a C declaration. Diagnostic: when a draft fails in a chain, stop peeling one error per gate cycle; splice once and dump every cc1 error, because the shape of the whole set names the cause. |
||
|
|
1670fe293c |
feat(phase-29): func_8016B6BC 0/137 -> 137/137 — it was a TYPE-CARRY failure, not a wall
The family that failed its sweep twice (once in the 274-member batch, once after the §91 guard) and looked like the §86 bimodal 'some families just don't template' case. It was not. DIAGNOSIS (§59 + §93): spliced ONE sibling and read cc1 directly. It reported `c`, `v`, `off` undeclared — ordinary locals that ARE declared in the remapped body. cc1 says 'undeclared' because it aborted the declaration block at an unknown TYPE and every later declaration fell out with it. Read the FIRST error, not the loudest: a visibly-declared variable reported undeclared means suspect its type. THE LIFT MUST BE TRANSITIVE. Lifting the type the body names directly (M8_8016B6BC) changed nothing — still 0/137. The real set was four, found by following each definition's own references: M8_8016B6BC -> Prim_8016B6BC -> Vtx_8016B6BC (named only inside Prim's body) -> DVec_8016B6BC. lift_types.py --apply, byte-gated ALONE first (neutral, d19c9580 unchanged), then swept. RESULT 0/137 -> 137/137, zero failures. R22 clean-fleet 140/140. cookbook §94. Cost of not diagnosing: this family sat recorded as 'doesn't template' across two sessions. Pointed at one sibling's real stderr it took under an hour and was worth 137 members. |
||
|
|
553949d157 |
docs(phase-29): SESSION-21 final checkpoint + cookbook §92/§93 (the doc gap Drew caught)
CHECKPOINT HYGIENE: between T11 and T12, wave 2 + a bank + a new tool guard were recorded ONLY in commit messages — CURRENT_PHASE.md and the cookbook were stale for that stretch. The quiet periods were background sweeps/R22 (~2h each) during which the tree cannot be touched, but that does not excuse leaving the durable record behind: a stale checkpoint is worse than an absent one. Closed. cookbook §92 — conforming a DECLARATION: pointer changes are caller-neutral, scalar-WIDTH changes are NOT. Byte-proven both ways (func_80179B74: 1,600 sites / 523 files / 3 forms, banked, R22 140/140; func_80175DA8: PLUMBING before the conform, DIFF after — the conform did not fix the draft, it changed the callers). Plus the arity case that broke 138/140, and the counting lesson: func_8015B950 looked like ~926 call-site casts and needed ONE — its only 0-arg call sits in an engine_core.h DEFINE macro the preprocessor expands 926 times. Count SITES, not expansions. cookbook §93 — `set -o pipefail` attributes a pipeline failure to the LAST stage, not the failing one: cc1 exit 33 reads as an assembler error because `as` ends the recipe. The 2-minute fix is to run the stages by hand printing each rc, then re-run the failing one with stderr visible. Turned an opaque Error 33 into a one-line fix twice today. Corollary (§88e, earned): hand a stuck function over as an UNDIAGNOSED observation, never as a named cause — flagged that way, the agent found the true cause (cc1 `conflicting types for 'Ent'`) immediately. func_8014D820 family swept 137/137. func_8016B6BC 0/137 reproducibly — recorded as a DIAGNOSIS task per §59 (a sweep 0/N is a per-sibling integration signal, not a codegen verdict), never as a wall. Checkpoint fn-count corrected 89.88 -> 89.80 against the measured report; stray a.out removed (R12). |
||
|
|
7d9dd6deca |
feat(phase-29): func_8014D820 banked (41,952 ins) + conform_decls scalar-narrowing guard
WAVE 2 (9 never-drafted exemplars, ultracode): 9/9 returned, 5 MATCH / 4 near, 2.25M tokens. BANKED: func_8014D820 (304 ins ×138) — and its agent ROOT-CAUSED the failure I left undiagnosed. It was never an assembler problem: cc1 exit 33, `conflicting types for 'Ent'` vs engine_types.h:434, surfaced by the recipe's `set -o pipefail` and MISATTRIBUTED to `as` because `as` is the last stage in the pipe (Makefile:560). Fixed by moving V4/Desc/Ent to BLOCK scope — byte-neutral and collision-proof across all 138 member TUs. Vindicates flagging it to the agent as UNVERIFIED rather than passing my own guess forward as fact (§88e). R22 clean-fleet 140/140. NEW GUARD — SCALAR NARROWING IS NOT CALLER-NEUTRAL (byte-proven, and it cost 3 gate cycles): conform_decls treated all decl type changes alike. A POINTER change is caller-neutral (func_80179B74 conformed 1,600 sites s16*/short* -> u16* and stayed byte-identical fleet-wide). A SCALAR WIDTH change is NOT: narrowing `s32 a0` -> `u16 param_1` changes argument promotion at every call site. MEASURED on func_80175DA8: decls reverted -> gate says PLUMBING; conform applied -> gate says DIFF. The conform did not fix the draft, it changed the CALLERS. Now warned explicitly (not refused — the draft's sig is still byte-truth for the callee and the gate arbitrates), with the instruction that a DIFF after this conform means examine the callers (§17a-1 pair), not the body. Verified the guard discriminates: fires on func_80175DA8 (s32->u16), silent on func_80179B74. STILL OPEN from wave 2: func_80176218 + func_80175AB8 (DATA-symbol conflicts, D_80078EB4 / D_8011F7BC -> reconcile_decls) · func_80175DA8 + func_80135EB0 (need the §17a-1 caller pair, not a bare conform) · 4 near-misses with precise residuals recorded (func_80176734 129 length-drift, func_80140958 49 inverted-hoist, func_80177B5C 19 sched tie, func_8017C974 83 -> permuter). |
||
|
|
acc8d762a0 |
feat(phase-29): func_80179B74 family swept 137/137 (R22 140/140)
134/134 BANKED on the remainder after 3/3 on the probe — the FOURTH full-family sweep this session, all four unblocked by the --like role guard, three of them 100%. R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed. |
||
|
|
6b9e2b7f33 |
feat(phase-29): func_8016AE5C family swept 136/137 (R22 140/140)
133/134 BANKED on the remainder after 3/3 on the probe. ONE sibling refused (ov_SC03_108, gate-fail) and is left as a stub rather than forced — a 136/137 recorded honestly beats a 137/137 that needed a shortcut. Third full-family sweep this session, all three unblocked by the --like role guard. R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed. |
||
|
|
d4c4a4d563 |
feat(phase-29): func_8015B950 family swept 137/137 (R22 140/140)
134/134 BANKED on the remainder after 3/3 on the probe — the second clean full-family sweep this session, both unblocked by the --like role guard. func_8015B950 is stubbed in NO overlay. R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed. At 271 ins x 137 members this is the session's largest single family by instruction weight. |
||
|
|
f459f53083 |
feat(phase-29): func_8015B950 banked — ONE cast unlocked the 925-site axis that broke 138 binaries
The same axis that broke 138 of 140 binaries an hour ago now lands clean, because conform_decls' NEW arity guard located the actual obstruction instead of leaving me to absorb it by hand. THE OBSTRUCTION WAS ONE LINE. Conforming `extern s32 func_8015B950(void)` -> `(s32 arg0)` turns every 0-arg CALL SITE into `too few arguments`. My hand attempt assumed those were spread across the 926 TUs and would need 926 casts (the func_8012AAAC precedent, where it really was 137 separate sites). They are not: there is exactly ONE call, in `src/shared/engine_core.h`'s `DEFINE_func_8015BEE4()` macro body — expanded into all 926 TUs by the preprocessor. func_8015BEE4 is a THUNK: `return func_8015B950();` with $a0 passing straight through from its own caller. So the 0-arg call shape is byte-CORRECT and must be preserved, not fixed — `return ((s32 (*)(void))func_8015B950)();` keeps it exactly (§17a-1; gcc folds the cast of a known symbol to a direct jal, and the s32 return is unchanged so the thunk's value still flows). Sequence: 1 cast -> conform_decls --apply (925 sites, R32 completion assertion: 0 remaining) -> gate BANKED byte-identical -> R22 clean-fleet extract-all 139/139, check-all 140 passed / 0 failed. The draft's 2 callee-decl conflicts (func_801725A4, func_80147078) dissolved with the axis. Worth 37,398 templatable ins; the ×137 family sweep is next. |
||
|
|
ab3ac83a41 |
feat(phase-29): func_8012AAAC family swept 137/137 — the --like guard unblocked the whole class
- 134/134 BANKED on the remainder (after 3/3 on the probe) => the family is 137/137, ZERO failures. func_8012AAAC is now stubbed in NO overlay. R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed. - FLEET 81.9 -> 82.0% instr · 89.60 -> 89.64% fn-count · distinct-code 69.3 -> 69.5%. - THE METRIC POINT, reproduced twice in one session and in BOTH directions: this jtbl family is byte-VARIANT (each overlay's table holds its own addresses), so every member is a genuinely new unique function and distinct-code MOVED. The h_seq PURE families swept earlier added 274 members and moved distinct-code by +0.0, because those members were already counted via their shared exemplar. SESSION-20's routing rule, now byte-demonstrated: target byte-VARIANT families to move RE-completeness; high-reach h_exact families move only the display number. - cookbook §91 — "a structure-TRANSFER is only valid where the structure corresponds": the --like role trap, plus the three-hypothesis trail (two wrong, and instructive: the sibling call-site casts were a real defect that fixed nothing, and my own carve-alone test was a false lead that departed from the tool's real sequence). The law: any "same family => same structure" transfer must state which structural fact it assumes and CHECK it on both sides — and a tool that drops an error class it cannot act on should still SURFACE it, because a bare `gate-fail` repeated 137 times cost far more than printing one line would have. |
||
|
|
2cc49d0310 |
feat(phase-29): SESSION-21 — func_8012AAAC banked via the §81 carve chain (R22 140/140)
The first jtbl-routed bank of the session, and it validates the whole chain end-to-end:
1. jtbl_carve SPLIT-TABLE repair (this session): jtbl_801D7FB0 28 -> 50 words (112 -> 200 B),
authorized by func_8012AAAC's own `sltiu 0x32`.
2. NEW FIX — SINGLE-TABLE PREDECESSOR: adding a second table to a subseg whose existing carve was
single-table lost the FIRST table's start entirely (new_offs has only the new one;
overlay_jtbl_addrs cannot see the old one because its owner is banked and extract PRUNED the
stub .s; and single-table carves persist no tables= to rebase). The span then failed its own
validator with "first must equal the span start" — the invariant naming the missing entry.
A single-table carve spans exactly its one table, so ITS SPAN START *IS* THAT TABLE'S START:
inference, not persistence, so it also works for spans carved before tables= existed. This is
the RECOVERABLE half of the documented func_8013F350 lesson (that one was a pre-§8e merged
DOUBLE — two tables, no record, genuinely unrecoverable).
Result: ov_SC01_077_a JTBL_PADS := 0,0 tables=+0x0,+0x14. Carve alone byte-gated BYTE-IDENTICAL
BEFORE the bank was attempted (§81 step 2).
3. ARITY axis, all-or-nothing: 1,244 decl sites / 1,240 files `(void)` -> `()` + an R32 completion
assertion (old-form remaining: 0).
4. ONE call-site cast: the definition lands at line 811 and a 0-arg call sits at 822, so gcc sees
the prototype and rejects it — `((void (*)(void))func_8012AAAC)()` (§17a-1; gcc folds the cast
of a known symbol to a direct jal). Only 1 of the 1,386 fleet-wide 0-arg call sites needed it:
the others see only the `extern ()` decl, which permits a 0-arg call.
DIAGNOSIS NOTE: the failure read CC1-FAIL with only a warning visible under make. Running the
pipeline stage-by-stage (cpp | cc1 | maspsx | jtbl_rodata_pads | as) put it on cc1 rc=33, and cc1's
own stderr named it exactly: "too few arguments to function func_8012AAAC" at line 994. Isolating
the stage was what turned an opaque Error 33 into a one-line fix.
R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed.
family_sweep correctly REFUSED this exemplar (§53: a jr-family must route through
jtbl_family_bank.py; "a 0% from this path would be a TOOL artifact, not a wall") — the ×137 member
sweep is the next step and needs a clean tree, which this commit provides.
|
||
|
|
5be4c21480 |
feat(phase-29): SESSION-21 — the ×138 member sweep: 274 members from 3 exemplar cracks (R22 140/140)
- family_sweep --hseq over the 3 newly-banked exemplars: BANKED 274 member-matches / 137 failed across 137 overlays, for ~0 agent tokens. Session total: 3 exemplars + 274 members = 277 fns. - THE STALE-MAP STEP, hit and handled: the first sweep returned "0 matched-exemplar families" because .run/family_hseq.json still listed the fresh cracks as draft-ov077. Regenerated (matched-sib families 60 -> 63) and the sweep found them — the documented bank-x1 -> regen -> sweep path (memory crack-wave-sweep-map-regen). - §86 REPRODUCED CLEANLY: 2 of 3 families templated ~137/137; the third failed ~137/137. Not a rate — a BIMODALITY. One probe per family, then sweep or skip; never a blended pool average. - R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed (second clean-tree verification this session). dedup 1886/0, C1 coverage 239,604/239,604, 0 NON_MATCHING (G4). - FLEET 81.7 -> 81.9% instr · 89.52 -> 89.60% fn-count · distinct-code 69.3% UNCHANGED — correct and expected: these are h_seq PURE propagation-class families, and SESSION-20's routing rule says propagation moves only the DISPLAY metric (members were already counted once via their exemplar). To move RE-completeness, target byte-VARIANT families. Stated plainly so the next session picks targets by the metric it means to move. - drive-by: family_sweep --help crashed (argparse %-expands help text; a literal "0%" needed "0%%"). |
||
|
|
2ce6c5fade |
feat(phase-29): SESSION-21 — 3 family exemplars banked + the §85 return-axis widen (R22 140/140)
BANKED (whole-binary byte-gate, the sole arbiter): func_8014D2A0 (80 ins ×138) · func_80158638
(87 ×138) · func_8016B6BC (94 ×138). Stubs in ov_SC01_077: 150 -> 147, 0 new stubs.
R22 CLEAN-FLEET: extract-all 139/139, check-all 140 passed / 0 failed. dedup 1886/0,
0 NON_MATCHING (G4). Fleet 81.7% instr / 69.3% distinct-code / 89.52% fn-count.
- WAVE STOPPED at Drew's request with 15/24 agents returned, ALL 15 status=match. Only the
completed drafts were gated; in-flight ones are still being written (§90d).
- PRE-GATE, both oracles, all 15: match_one MATCH + reloc_verify ALL RESOLVED. Routed 7 plain /
8 to the §81 jtbl carve chain.
- THE BLOCKER, MEASURED: 7 of 7 plain drafts failed PLUMBING, 0 DIFF, 0 compiler walls — the same
shape as SESSION-20's T0.2. §58b applies: the draft sig is byte-TRUTH (it MATCHed), the header
decl is the stale stub-era guess, so conform the DECLS.
- §85 RETURN-AXIS WIDEN, all-or-nothing: 3,471 decl sites / 1,736 files, precondition verified
(ZERO callers consume the return => byte-neutral by construction) + an R32 completion assertion
(old-form decls remaining: 0). func_8014D820's s32 return is load-bearing — forcing `void` costs
2 instructions (302 vs 304), so the decls had to move, not the draft.
TWO HONESTY ITEMS:
1. I REPORTED "0 of 7 banked"; the true number was already 2. My diagnostic pass printed only
lines starting with "- func_" (the failures) and hid its own successes while I read it for
error text. A script that prints only failures cannot tell you it succeeded — the R32
silent-skip shape aimed at my own instrumentation. Ground truth is the stub count (§55b(3)).
2. A REAL FINDING fell out of that mistake: same drafts, same tree, minutes apart — gate_stage's
full ladder banked 0/7 while bare harvest_verify banked 2/7. The LADDER REGRESSED two drafts
the bare gate accepts (§19's "sig_unify regresses already-canonical drafts", one level up, and
the exact mirror of SESSION-20's missing-ladder false 33%). Neither "always ladder" nor "never
ladder" is right — run both, let the byte-gate arbitrate. One build per draft.
OPEN: func_8014D820 still a stub — after the widen its error moved from `conflicting types` to an
assembler-stage failure, not finished diagnosing. Recorded as open, NOT as a wall.
|
||
|
|
0be781efdf |
docs(phase-29): cookbook §90 — five tool-integrity laws from SESSION-21 (R16/R30)
Each law is one this session paid for, and each fix CHANGED the answer its tool gave:
§90a a comparison tool must share its reference oracle's index space exactly (objdump -dr vs -drz
elided 6 nops -> 104 vs 110 ins -> phantom mismatches; and the .s word field is little-endian
hex TEXT, not the instruction integer). Five false alarms preceded the first true one.
§90b 'byte-neutral' is not 'wanted' — undo on the SUCCESS path (a 0-bank run left 123 files of
dead diff because the backstop only fired on a NON-neutral edit). §61 applied forward.
§90c a library-callable function must FAIL CLOSED on unconfigured module state — an empty result
is indistinguishable from a true negative (R32's silent skip in a different hat).
§90d do not measure a live wave's drafts — §87 staleness in real time (same function, two verdicts
two minutes apart; its agent rewrote the file 12s earlier).
§90e an agent's CONCLUSION and its EVIDENCE fail independently: re-derive the premise, design the
fix from what you can prove. The agent's jtbl bug was real and confirmed 3 ways; its 'zero
xrefs' premise was false and its proposed remedy would have deleted a referenced symbol.
The fix instead gates on the function's own sltiu bound — the program declaring its own table
length. Negative control (228 combinations, exactly 1 change) is half the deliverable.
|
||
|
|
2b38c68333 |
feat(phase-29): SESSION-21 T1-T3 — the frontier measured, the family-exemplar wave, 3 tool fixes
- T1 FRONTIER MEASURED (zero-token, R35: family map regenerated on fresh sigs first — it was stale by ~657 banked members): 36,020 stubs / 2,345,599 weighted ins remain, and only 9.0% are h_exact-FREE. PROPAGATION IS TAPPED (238 distinct classes / 3,245 instances); 22,498 distinct classes / 1,680,097 distinct ins is what is actually left. The mass is FLAT across all 139 binaries (~300-550 sub-500 stubs each) -> "pick the best overlay" is not a strategy. .run/s21_frontier.py + .run/s21_frontier.json - T2 THE AXIS IS THE FAMILY, NOT THE LOCATION: 1,342 substantial h_seq families / 1,298,135 templatable ins = 55% of ALL remaining weighted instructions. Routed by blocker: jr/§81 181 fams (33.6%) · DRAFT-with-cached-Ghidra-C 91 (28.6%) · DRAFT-modal 1,023 (27.5%) · zero-crack 45 (6.5%) · permanent walls 2 (3.9%). Live+cached+non-wall in ov_SC01_077 = 54 families / 589,502 ins, value steeply concentrated (top 24 = 96%). .run/s21_targets.py + .run/s21_targets.json + .run/s21_draft_pool.json - T3 WAVE 1 LAUNCHED: tools/workflows/family_core_wave.js (NEW) — 24 xHigh drafters, one per family exemplar, stake 575,488 templatable ins (24% of remaining). Supersedes worker_wave.js for family work: carries each target's family STAKE, encodes the four §58/§87 integration rules at source (splat D_<UPPERHEX> not Ghidra DAT_; never invent a symbol; canonical callee sigs; leave decl plumbing to the ladder), and requires symcheck.py on any claimed MATCH. - T3b LADDER HYGIENE, both SESSION-20 carry items fixed — one defect, two masks: a byte-NEUTRAL transform was left in the tree when it banked nothing. family_sweep's --normalize-self-decls backstop only fired on MISMATCH (left 123 files of dead diff on a 0/123 run); gate_stage's ARITY undo narrowed to src/shared/ and left ~40 TUs. Both now restore the full snapshot when NOTHING banked (no banks to preserve => the splice hazard cannot apply). §61 on the success path. - T3c BACKLOG addr DEFECT fixed (R32/R33): new addr_of() derives the address from `name`, assert_addr_coverage() fails loud on an unkeyable row, append_record fills both directions. Found a latent bug doing it: load_best() keyed on `addr or name`, splitting one function into two "best" records. Keyable rows 128/1,701 (7.5%) -> 1,701/1,701 (100%). |
||
|
|
5c422e8426 |
feat(phase-29): tools/sweep_parallel.py + §89 — the parallel gate farm, reachable from the family path (step 2)
bulk_harvest's Phase B has been a ProcessPoolExecutor over DISTINCT binaries (per-binary flock, per-worker result files, compute_fleet=False) since Phase 23 — but welded to Phase A's LLM drafting. Family sweeps stage drafts differently (family_sweep --stage-only), so the farm was UNREACHABLE from that path, and SESSION-20 gated 389 + 268 + 104 members SERIALLY for no architectural reason (~8-16x throughput loss on a 32-thread box). This is a thin adapter: same gate_stage.run_gate, same per-binary lock, NO new gate logic. Also fixes the phantom-dir bug at source: a bare .run/sweep/*/ glob matches gate_stage's own intermediate ladder dirs (-cn/-cast/-rc/-s2in/-uni) and calls them as binaries — 24 phantom PARTIAL 0/1 lines that inflated one run's notbanked from 0 to 56. Requires config/splat.<bin>.yaml to exist (R33/R36: derive the binary set, never glob it). Smoke-tested: the phantom is skipped and named, real binaries kept. §89 records both throughput rules the project already had and was not following. |
||
|
|
6ce2e8963f |
chore(phase-29): preserve the behemoth close-out artifacts (R20)
39 files from the three behemoth agents: the matched drafts (s21_func_80183814_b2.c, s21_func_8017D2DC_b1.c, s21_func_8017DC1C_b1.c), their reports with do-not-re-buy tables AND BASES (§80), and the reusable harnesses — including s21_g21_reloc_verify.py, which resolves every relocation (incl. the implicit MIPS-REL addend objdump -r does not print) against the target and is the missing rung between match_one and the binary (§88f). ~735k agent tokens of work; .run/giants is the curated allowlist. |
||
|
|
890dd08e6f | docs(phase-29): §88 — the behemoth close-out laws (cross_jump/call, slti literal-position + its equality false-positive, banking order, the reloc gate) | ||
|
|
d2a79deff2 |
feat(phase-29): ALL THREE BEHEMOTHS BANKED — func_80183814 (5,122), func_8017DC1C (1,518), func_8017D2DC (1,586)
Zero functions >1000 ins remain unmatched anywhere in the fleet. func_80183814 (5,122 ins — the LARGEST function in the game) — round 2 closed it: length 5127->5122 exact, structural residual 36->0, register-sensitive 1201->0, frame -256 -> -0xF8 exact, saves 10 -> .mask 0x807f0000 exact. Verified independently (R14): match_one MATCH (5122 ins). ROUND 1's DIAGNOSIS WAS WRONG and the agent refuted it properly: the +5 length was a SYMPTOM, not the lever, and the §83d max_reg/cse.c:8340 story does not hold — a 15-line reproducer reproduced the case-0/3 CSE exactly (so it cannot be max_reg-gated), max_qty only gates extension ACROSS blocks, and the target leaves $s7/$fp unused (no pressure story). Confirmed from a second direction: C01 has the identical two groups over the identical symbols with ZERO residual, because a `break` puts a CODE_LABEL between them. The two biggest levers were pure DECLARATION SCOPE (§45/§76), not pins. func_8017DC1C (1,518) — MATCH first round, pin-free, zero __asm__ dials. NOT a jr fn (0 mid-fn jr). func_8017D2DC (1,586) — MATCH first round (banked in the previous commit). BANKING ORDER MATTERS — a new failure mode found and worked around: banking func_8017DC1C BEFORE the carve chain broke the build. Its draft establishes the canon for 39 previously-undeclared externs; jr_isolate_all's re-partition (overlay_src_split) then DROPPED ALL 39 across the new split boundary (`D_801C1EB0 undeclared`), leaving them in NEITHER file. The §77 preamble-drop class, in a third tool. FIX = ordering, not patching: run the §81 carve chain FIRST on a clean tree (gated BYTE-IDENTICAL), then bank. Reverted, re-sequenced, both banked clean. R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4). Fleet: instr 81.6 -> 81.7% · distinct-code 69.1 -> 69.3% · fn-count 89.52%. |
||
|
|
09b1993059 |
feat(phase-29): T0.7 sweep (104 members) + BEHEMOTH func_8017D2DC banked (1,586 ins)
T0.7 — the §86 one-member probe applied to the remaining FREE families: 9 LIVE / 6 DEAD / 5 unstaged. The three highest-value families by raw size (18,084 / 11,234 / 10,880 ins) all probed DEAD — the probe skipped them instead of burning ~400 gate cycles rediscovering it. Swept the 9 live: 104 banked, 8 of 9 families fully cleared (func_8017BEF8 has 8 stragglers). BEHEMOTH 2 of 3: func_8017D2DC (1,586 ins, ov_SC01_001) MATCHED and BANKED — closed in ONE agent round, pin-free. Verified independently (R14): match_one MATCH (1586 ins). §81 carve chain: the agent predicted step 1 unnecessary; jtbl_carve REFUSED (the subseg already hosts a .rodata carve and the new table's start != span start). The refusal was RIGHT and is the instruction to run step 1 — jr_isolate_all --only (2 fns/1 object) -> BYTE-IDENTICAL, then jtbl_carve -> BYTE-IDENTICAL, then the ladder banked it. R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4). Fleet: instr 81.5 -> 81.6% · distinct-code 69.0 -> 69.1% · fn-count 89.49 -> 89.52%. |
||
|
|
1eb36504f6 |
docs(phase-29): §87 — match_one never LINKS, so the 315 'integration' entries are not bankable
T0.6 measured: the autopsy's integration bucket (315 match_one MATCHes, 'blocked only on plumbing')
banked 0/27 through the full gate_stage ladder. Two causes, neither plumbing:
(1) UNDEFINED DATA SYMBOLS — the gate fails at LINK on symbols defined in NO overlay's symbol file.
match_one compiles one TU and never links, so an extern resolving nowhere is structurally
invisible to it. (Refuted the obvious alternative: the drafts WERE authored for the right binary.)
(2) STALE DRAFTS — 'redefinition of struct S80172C50': the struct was since lifted into
engine_types.h, so the draft's own copy collides. A stored draft is scored against TODAY's tree.
=> FOUR match_one blindness classes now catalogued: §81 jump tables, §84 masked %lo, §87 link, §87
staleness. A match_one MATCH is 'this TU compiles to the right bytes with relocations masked' —
nothing about linking, nothing about the current tree. A stored MATCH is a CLAIM WITH A TIMESTAMP.
Consequence: with §83's 44%-misfiled finding, docs/backlog.md's headline count is NOT a work queue.
Re-gate a sample before planning against any stored-draft pool. Cheap discriminator added (grep each
D_ symbol against the binary's symbol files; any UNRESOLVABLE will fail at link regardless of ladder).
MY RECOMMENDATION WAS WRONG: I ranked this pool first on 'highest certainty of any pool we have'.
The certainty was an artifact of a tool that cannot see link errors. 0 banked, 0 tokens, tree clean.
|
||
|
|
c2566010f2 |
feat(phase-29): --allow-pins sweep — 268 banked; pin templatability is PER-FAMILY (cookbook §86)
The §42e pin guard refuses any family whose exemplar carries `register __asm__` pins: 680 of the top
8 FREE families' 1,083 members (63%) were skipped BEFORE any gate ran. Re-run with --allow-pins,
letting the byte-gate arbitrate (G3/P9): 268 banked, and ZERO cc1 crashes across hundreds of pinned
compiles — confirming the SIGABRT the guard was written against was Phase 27's extract_unit
macro-drop, NOT a compiler limit. The guard is protecting against a bug that no longer exists.
THE LAW (§86): templatability is a PER-FAMILY property, not a per-member rate.
func_801749C8 137/137 = 100% func_80133AB0 4/136
func_8014C6F4 137/137 = 100% func_8014CF04 0/137
func_80143D28 0/136
Two families at 100%, three at ~1%. MY REPORTED "37%" WAS AN ARTEFACT: a 19-member sample that
straddled families reported their AVERAGE and hid the bimodality. Sample PER-FAMILY, never per-pool.
=> PROCEDURE, now the default: probe ONE member per pinned family; bank -> sweep the family; fail ->
skip entirely. The blanket sweep spent ~412 futile gate cycles (60% of the run) on three families
that were never going to bank; the 1-member probe reduces that to 5 probes + 2 sweeps.
Left explicitly UNDIAGNOSED (do not guess): why two families template and three do not. Likely axis
is caller-saved pins spanning a `jal` (§74's corrupting form) vs pins fixing only a local allocno.
Diagnose BEFORE extending --allow-pins fleet-wide — the byte-gate makes a wrong guess free, but a
wrong PROCEDURE costs a sweep.
R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 81.3 -> 81.5% · distinct-code 69.0% · fn-count 89.41 -> 89.49%.
|
||
|
|
52e6522f1b |
feat(phase-29): T0.5 — FREE-subset sweep, 3 families fully banked (389 members, +37,713 ins)
Re-derived the T0.1 decomposition post-harvest (it was stale by 395 banked members): zero-crack pool 76 fams / 347,892 ins -> 73 fams / 290,850 ins (the harvest came out of it) FREE (sweepable, non-jr, non-O0) -> 58 fams / 167,368 ins Swept the top FREE families through the gate_stage ladder (sample 8/8 first, then the rest): 389 banked; func_801463A0 / func_8017B490 / func_80156670 now stubbed in ZERO overlays. R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4). Fleet: instr 81.0 -> 81.3% (10,645,711 -> 10,683,424) · distinct-code 68.8 -> 69.0% · fn-count 89.30 -> 89.41%. THE BLOCKER HAS MOVED — it is now OUR OWN PIN GUARD, not gcc and not declarations. Of the 1,083 candidate members in the top 8 FREE families, 680 (63%) were refused by the §42e pinned-exemplar guard BEFORE any gate ran; only 403 reached staging. Two pieces of evidence say the guard may now be over-conservative: SESSION-19 banked func_8017A4AC x134 WITH pins once the byte-gate arbitrated, and Phase 27 dissolved the cc1 SIGABRT that motivated it (it was the extract_unit macro-drop, not a compiler limit). Next probe: --allow-pins on a sample of 8, byte-gated. MY OWN SCRIPT BUG, fixed + negative-controlled: the sweep loop globbed `.run/sweep/*/`, which also matches gate_stage's INTERMEDIATE ladder dirs (-cn, -cn-cast, -cn-cast-rc, -s2in, -s2in-uni). Those were called as if they were binaries -> 24 phantom "PARTIAL 0/1" lines inflating notbanked to 56 when the true failure count was ZERO (stub counts 0/0/0 are the ground truth). Fixed by requiring config/splat.<ov>.yaml to exist; negative control confirms phantoms are skipped and real binaries kept. |
||
|
|
015ebff536 |
feat(phase-29): §84 family fully harvested — 123/123 members, 0 failed (+29,280 ins, +27,840 distinct)
The derived-offset recompute swept the whole func_8013D53C family: 119 banked / 0 failed on top of the 4 earlier; func_8013D53C is now stubbed in ZERO overlays. R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4). RECIPE (and it is NOT the return-axis recipe — sampling caught this): §84 derived-offset -> per-member literal recompute AND the gate_stage ladder. With the recompute alone the sample was 0/8; through the ladder it was 3/3, then 119/119. Had I reused the return-axis recipe (plain harvest_verify, which banked 272/272 there) I would have swept 123 members to zero banks and mis-concluded the fix was wrong. Probe-before-scale. METRIC FINDING worth carrying: this harvest moved instr +29,280 AND distinct-code +27,840, while the return-axis harvest moved instr +26,928 and distinct-code +0. §84-class members are byte-VARIANTS so each is a new unique function; propagation-class members were already counted once via their shared exemplar. => §84-class work moves the RE-COMPLETENESS number; propagation moves only the DISPLAY one. Session fleet: 80.6 -> 81.0% instr · 68.2 -> 68.8% distinct-code · 89.18 -> 89.30% fn-count. |
||
|
|
9d9cd58028 |
feat(phase-29): T0.4 harvest — 272 return-axis members banked (+26,928 ins) + the §84 recompute in family_remap
THE §85 WIDEN PAID OFF AS PREDICTED. It is a ONE-TIME fleet edit, so once committed the
`conflicting types` blocker was gone for EVERY member of both families at once:
- sample 8 first (probe-before-scale): 8/8 banked with PLAIN harvest_verify, no ladder needed
- full sweep: 264 banked / 0 failed across 132 overlays; 10 skipped as not-stub
- total 272 members ~= 27k ins, ZERO agent tokens
R22 clean-fleet 140/140 BYTE-IDENTICAL; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 80.6 -> 80.8% (10,589,503 -> 10,616,431, +26,928) · fn-count 89.19 -> 89.26%.
distinct-code UNCHANGED at 68.3% — propagation moves the DISPLAY metric, not the RE-completeness
one (the SESSION-19 split, reconfirmed).
§84 RECOMPUTE now implemented in tools/family_remap.py (fix_derived_offsets), wired into all three
apply_remap call sites as a PRE-pass on the exemplar body (the literal is ambiguous as a substitution
token, so it cannot be a table entry):
correct_literal = mapped(aliased_sym) - mapped(base_sym)
Verified by negative control: the hand-solved case recomputes 0x20 -> 0x18 exactly, and a site whose
target endpoint is NOT a mapped symbol is left byte-for-byte alone AND REPORTED in info
["derived_offsets"] (R32 — a silent skip is a defect, and a silent skip is how this bug survived).
|
||
|
|
772b5c4e02 |
feat(phase-29): the RETURN-axis fleet widen — 2 more families unlocked (cookbook §85); 140/140
Continues the "see why and try again" chain. Diagnosed all 4 T0.2 failures to 4 DISTINCT causes: func_8013D53C 240x123 §84 derived-offset remap bug -> BANKED (previous commit) func_8012CC88 105x137 §73/§30#2 RETURN-axis conflict -> BANKED here func_8014D12C 93x137 §73/§30#2 RETURN-axis conflict -> BANKED here func_80144090 154x136 LENGTH-DRIFT (+13 B, ~3 ins long) -> genuine codegen, real work THE FAILURE THAT TAUGHT THE FIX: widening only src/shared/engine_core.h banked the member in the TARGET overlay and BROKE ov_SC01_077 (R22 139/140) — the source overlay carries its OWN local `extern void func_X(...)` decls, so a shared-header-only widen puts them in direct conflict. The per-binary gate passed while breaking a binary it never built (§63/§61: a T2 write set is only provable by R22). A half-done axis is a guaranteed break, not a smaller win. THE FIX: do the WHOLE axis — 3,668 `extern void` decl sites across 2,688 files widened to `s32`, 0 remaining (R32 completion assertion). Precondition verified first: 0 callers consume the return value, so the widen is byte-neutral by construction. R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4). MY OWN ERROR, recorded (§85 trap): I first spot-checked ov_SC01_077 with `make build | grep | head; echo rc=$?` and read rc=0 as success — that is the exit status of `head`, not make, and the output had no BYTE-IDENTICAL line. I reported a false BYTE-IDENTICAL in the interim. Assert on the SUCCESS STRING, never on $? after a pipe. Fleet: instr 80.6% (10,589,503) · distinct-code 68.3% (3,846,656) · fn-count 89.19%. |
||
|
|
b6bb04ecff |
feat(phase-29): CRACK THE PLUMBING FAILURE — the derived-offset remap bug (cookbook §84); func_8013D53C banked
Drew: "if it fails, see why and try again with new knowledge." It failed twice, then banked.
ROOT CAUSE, byte-proven: a family_remap member reached match_one MATCH (240 ins) and failed the
whole-binary gate by ONE BYTE. The exemplar carries a deliberate matching idiom — reach a symbol via
a DIFFERENT symbol plus a literal offset, so gcc cannot CSE the two %hi/%lo pairs:
(*(S9*)&D_801DAA78) = *(S9*)(&D_801DA998 + 0x20); /* same addr as &D_801DA9B8 */
family_remap substitutes the symbol NAMES correctly and leaves the literal 0x20 — but 0x20 is not a
constant of the algorithm, it is the DISTANCE BETWEEN TWO PER-OVERLAY SYMBOLS:
exemplar 0x801DA998 + 0x20 = 0x801DA9B8 OK
member 0x801A5778 + 0x20 = 0x801A5798 WRONG (real symbol 0x801A5790)
member 0x801A5778 + 0x18 = 0x801A5790 correct
match_one MASKS HI16/LO16 so it is STRUCTURALLY BLIND to this — the §81 blindness in its DATA form.
TWO FIXES WERE EACH INDIVIDUALLY INSUFFICIENT: the byte fix alone re-failed as PLUMBING; the ladder
alone re-failed as DIFF. Together -> BANKED, R22 clean-fleet 140/140.
TWO LADDER CORRECTIONS (my own T0.2 error): bare harvest_verify is the LAST RUNG, not the ladder —
gate_stage runs canon_resident_calls -> cast_call_sites -> reconcile_tu -> ARITY -> sig_unify ->
harvest_verify, so T0.2's "8/8 PLUMBING" measured the UN-RECOVERED rate. And reconcile_decls.py is
RETIRED (R33, superseded by reconcile_tu): asking "what does the FLEET call this symbol?" is wrong by
construction in a loosely-typed engine (548 of its answers conflicted, rewriting 60 of 196 drafts) —
so Drew's suggested tool would have made it worse.
SCOPE, MEASURED (not over-generalised, §80): the idiom appears at only 5 sites corpus-wide — BUT one
gates a 123-member family (133 staged drafts all carry the un-recomputed +0x20 with different
per-overlay bases), so the mechanical fix is worth ~240 ins x 123 ~= 29,520 ins. It does NOT explain
the pool generally: func_80144090 / func_8012CC88 / func_8014D12C have ZERO derived-offset sites and
fail for a different, still-undiagnosed cause.
THE FIX IS MECHANICAL: correct_literal = mapped(aliased_sym) - mapped(base_sym). The remap already
holds both mappings, and the exemplar's own comment names the aliased symbol.
Also observed: the ARITY pre-pass left 40 TUs of caller-decl edits after a 0-bank run (same hygiene
bug as --normalize-self-decls, twice in one session) — reverted, both binaries byte-identical.
|
||
|
|
adafeb13d6 |
feat(phase-29): T0.3b autopsy — 44% of the "near-miss backlog" are not near-misses; 315 are plumbing-blocked MATCHes
Recomputed every backlog residual from the bytes (1,699 rows, -j 12, zero agent tokens) through the validated match_one path, deriving asm-subdir + -O0 from corpus.py. R34 cross-check PASSED (closeness agreed with masked_diff.structured_diff on all 1,610 built rows, 0 classifier errors); 89 nobuild rows REPORTED not dropped (R32). BUCKETS: redraft 707 | structural 528 | integration 315 | permuter 57 | unknown 3. 1. HONESTY CORRECTION: 707 of 1,610 (44%) are class SIZE-MISMATCH — the stored best-draft is a PARTIAL, an incomplete attempt logged with a closeness score (the func_80183814 666-of-5,122 shape). docs/backlog.md has been overstating readiness by ~44%. These route to a FRESH CRACK, not to a wall and not to the permuter. 2. ACTIONABLE: 315 entries are match_one MATCH *right now*, blocked only on the reconcile ladder — recomputing beat trusting the stored label because the tree moved since they were logged. ~108,959 gain-ins; top func_80174CB0 (16,482), func_801463A0 (13,534). §52b still applies: ~half of close=0 drafts fail the whole-binary gate, so these are CANDIDATES not banks. 3. The permuter bucket is 57/1,610 = 3.5% (Task-13B measured 7.7% and called targeting the problem). Extending the mutation set is CONFIRMED not the big lever — small, real, now bounded. 4. R34 again: 3 of 4 comparable labels DISAGREE with measurement — func_80140D68 / func_8012A328 / func_801549F8 recorded "schedule" but measure ADDRESSING -> cse. The grinder was aimed wrong. CONVERGENCE: T0.2 (8/8 failures PLUMBING, 0 walls) and T0.3b (315 integration) independently point at the SAME lever — the declaration/integration reconcile ladder, worth the 224,410-ins FREE pool AND ~108,959 backlog gain-ins. Two keys eliminated today; untried: canon_sig_reconcile v3.2 and reconcile_decls.py (the DATA-symbol analog — one T0.2 failure text was a DATA symbol). |
||
|
|
d3e6d6a702 |
feat(phase-29): T0.2 gate probe — the FREE pool is PLUMBING-blocked, not wall-blocked (4 banked)
MEASURED, not projected (R14): 12 gate attempts across ov_SC01_000 + ov_SC01_001, one draft per build for clean attribution. - 4 BANKED (func_8017B490 x2, func_801463A0 x2); 8 failed; **0 DIFF — zero compiler walls** - all 8 failures are the §75a/def-side declaration class: `conflicting types for 'D_800A651C'` (DATA sym) and `conflicting types for 'func_8013D53C'` (the member's OWN def-side decl) - => raw conversion 33%, but the ceiling is NOT 33%: the blocker is declaration plumbing, which this project has named tools for. Plumbing recovery has out-earned drafting in every phase that measured both (P19 fix_arity_callers, P28 dedup_extend 6,174 members / 95.6% from one new mode) TWO CORRECTIONS TO MY OWN T0.1 POOL MATH, both downward: - 2 of the 8 top "FREE" families were refused outright by the §42e pinned-exemplar guard (the 270 skips) => "FREE" does NOT imply sweepable; pins are a third blocker the decomposition missed. Recoverable (--allow-pins; SESSION-19 banked pinned families x134), but I mis-labelled them - n_templatable counts the matched exemplar, so every T0.1 family figure is ~1 member (~0.7%) high NEGATIVE RESULT (§80, scoped to this base): --fix-def-sig REGRESSES this class — 0 banked and 2 PLUMBING became CC1-FAIL despite targeting the same error text. Do not re-buy without re-testing. NAMED NEXT LEVER: family_sweep --normalize-self-decls, whose help text cites fixing "the conflicting types for func_X that blocked 133/137 of func_801670E4" — exactly this failure. Gate-phase transform, so it cannot run under --stage-only, and --limit caps FAMILIES not MEMBERS => needs a full ~123-member family run. Highest-value outstanding probe, zero agent tokens. R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health/dedup 1886/0; 0 NON_MATCHING (G4). Fleet: instr 80.6% (10,589,065) · distinct-code 68.3% (3,846,416) · fn-count 89.19%. |
||
|
|
1fe4850136 |
feat(phase-29): T1.1 func_80183814 round 1 — 99.3% structural, named lever; cookbook §83
- VERIFIED INDEPENDENTLY (R14): match_one reproduces DIFF 5127 vs 5122, LENGTH-DRIFT/+5. Agent did not over-claim; tree untouched. Difflib-aligned truth: 36/5122 structural (99.3%), 17/21 cases EXACT, args+locals BYTE-EXACT at 216B - §83a: on a LENGTH-DRIFT class match_one's mismatch count is NOT a progress signal — 4,622 and 36 describe the same draft (index-wise comparison smears every index after the delta) - §83b THE LEVER: the handoff's '35x repeated template' (which I passed on flagged UNVERIFIED) is TRUE and was the whole game — 2,625 of 5,122 ins (51%) from ONE parameterised 72-ins body. Three sub-levers: pointer walk (no strength-reduction under -G0), rand()%(u32) for divu, cast barrier vs combine - §83c TRAP: the inherited 'dead local' pad[32] is gcc's OWN SPILL AREA — removing it made the locals area byte-exact. §83e: two 'pure allocation' residuals were a copy-pointer walk -> zero (§80 again) - §83d THE STALL, cited: cse.c:8340 sizes the quantity table by WHOLE-FUNCTION pseudo count, so no per-case edit can move a function-global CSE fork. Next move = close the +5 (buys length parity AND perturbs max_reg), then re-run the do-not-re-buy table on the new base - no pins in the deliverable (diagnostic-only, table row 15) — agent self-reported unprompted - DECISION: round 2 QUEUED, not spent now — T0.2 (224,410-ins pool) outranks a ~0.04pp lever |
||
|
|
57ee715f3c |
feat(phase-29): T0.1 frontier survey re-run (138 ovs) — the family lever is ALIVE; a 224,410-ins zero-crack FREE pool
- verified the tool BEFORE trusting its scan (R35): load() correctly globs all 138 overlays, but the generated header hardcoded '134' -> fixed to derive from the same glob (a doc misreporting its own scope is the P28 img_path shape, one severity down) - stale(07-23,134ov) -> fresh(07-26,138ov): fleet 88.5/79.0/68.4 -> 89.4/80.9/69.0%; families 2721 -> 2688; substantial 558 -> 544; with-matched-sibling 74 -> 76. Structure STABLE => the P25 family reframe is NOT an artifact and P26's ~0% stays unsupported post-fix - FINDING: 3,419 instances banked but only 85 distinct CLASSES fell -> recent yield was propagation, not new classes (SESSION-19's split, now fleet-wide) - THE POOL: 76 zero-crack families (exemplar already matched) = 347,892 ins = 19.4% of remaining distinct code, decomposed by real blocker: FREE(PURE/non-jr/non-O0) 61 fams/224,410 ins = 12.5% of remaining; jr 13/57,311 (§81 chain); -O0 2/66,171 (known deferred build-infra, Arm A proved 9/9 bank) - STILL A PREDICTION (R14/G3): T0.2 re-targeted from this data to measure the GATE conversion rate on 8 members sampled across the FREE subset before any arithmetic scales |
||
|
|
661f5aa751 |
feat(phase-29): bank func_8017C730 x ov_SC03_013 (+1,061 ins) via the §81 carve chain
The SESSION-19 handoff's item 1, closed as specified — no drafting, no agent. - §77 MINIMAL CLOSURE (519 lines, not the 2,993-line whole-file carry): 18 gte_* macros + 5 externs + the bandsetup static-inline helper -> match_one MATCH (1061 ins) - §81 chain, each step byte-gated before the next: jr_isolate_all --only (2 fns/1 object) -> BYTE-IDENTICAL; jtbl_carve --func (single-table, 44-piece interleave) -> BYTE-IDENTICAL; harvest_verify --chunk 1 -> verified 1 / failed 0, 7042bc71 BYTE-IDENTICAL - R22 clean-fleet 140/140 from a genuinely clean tree; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4). FLEET distinct-code 3,845,161 -> 3,846,222 = 68.3% (+1,061, all distinct — a behemoth-class bank, not a propagation); instr-weighted 80.6% - No §75a class spoke: the exemplar's ApplyMatrixSV(void*,void*,void*) canon fix was already carried, so the declarations were clean and it banked first try - cookbook §77: the ladder CLOSED with all four rungs measured (-56 -> -34 -> MATCH-but-uncommittable -> MATCH+BANKED), plus a NEW subsection — the CANDIDATE gate and the REAL gate need DIFFERENT preambles (match_one compiles standalone, so a shared-type body's CC1-FAIL is a report about the PROBE, not the draft; the types header goes in a throwaway probe copy, never in the banked draft) - FINDING, flagged not acted on (P5d): that shortcut already leaked an ABSOLUTE include path into 21 git-tracked files / 23 lines. All 21 verified semantically no-op (guarded engine_types.h via engine_core.h at line 2) => removal is byte-neutral, but cpp must still find the literal path, so those TUs cannot preprocess on any clone not at /home/musashi/bfm-decomp. Invisible to every byte-gate (R34's null-oracle shape, aimed at portability). Proposed as the next task. |
||
|
|
2199c71192 |
docs(phase-29): §77 — add the 5th measured variant (static helper) + the minimal-closure corollary
Drew asked whether the cookbook was actually being updated per behemoth. It was (13 commits, each paired with its bank), but the check found a REAL GAP: the last probe's two lessons went into CURRENT_PHASE.md and a commit message and were never folded into §77 itself. So the cookbook PREDICTED the static-helper variant (its closing line named it) without recording that the prediction had since been CONFIRMED, and lacked the corollary entirely. - VARIANT 5: a `static inline` helper, dropped by family_remap -> LENGTH-DRIFT/-56 with NO compile error at all. The nastiest variant precisely because it produces no diagnostic: the draft compiles clean and is simply ~56 instructions short, which reads as a codegen residual rather than a missing construct. Rule added: a NEGATIVE length drift with no compile error on a mechanically-remapped sibling means look for an uncarried static/inline helper BEFORE touching a lever. - COROLLARY (measured, and it cost a bank): carry the MINIMAL TRANSITIVE CLOSURE of what the body references, not the whole file. Carrying the exemplar's entire 2,993-line region file produced a clean standalone match_one MATCH and then failed the whole-binary gate on PLUMBING -- over-carrying trades a match_one failure for an in-TU collision. Measured ladder: -56 (nothing) -> -34 (helper + externs) -> MATCH-but-uncommittable (whole file); the minimal set is the only bankable point. - Also recorded: the walk-back-to-previous-brace heuristic breaks on an ISOLATED REGION FILE (_jr_<addr>.c from jr_isolate_all), where the construct above the function IS the needed helper -- it returns a 1-line preamble. A preamble-carry tool needs a reference-closure rule, not a positional one. |
||
|
|
109ce6a2c3 |
feat(phase-29): BEHEMOTH #6 func_8017C730 BANKED (1,061 ins) + §82 two source-shape oracles
- CRACKED at xHigh and VERIFIED INDEPENDENTLY: match_one MATCH (1061 ins); agent re-matched 3x from clean runs (100% register-masked AND register-kept, all 10 regions, frame 0x270 exact). §81 carve chain clean first try: jr_isolate_all --only -> byte-identical cacaf7c2 -> jtbl_carve (43-piece set) -> byte-identical -> bank -> R22 clean-fleet 140/140, tools-health OK. instr 80.6%; distinct-code 3,844,100 -> 3,845,161. - WHAT IT IS: the matched base func_8017CA80 + camera height-band cull + distance-driven CLUT fade. func_8004974C (TransposeMatrix) sits in a 36-ins prologue deriving a Y band; the part-level `lim >= g.otz` cull is GONE; flat arms gain an `sz < lim` near-plane cull. The base+one-extra-callee fingerprint predicted this exactly. - §82 ORACLE 1 -- A DUPLICATED `addiu $aN,$sp,K` ACROSS A `jal` MEANS THE BLOCK WAS INLINED. `&X` on any non-first local always creates a pseudo and CSE always merges two of them (expr.c:6260 ADDR_EXPR -> force_operand(..., NULL); exception: virtual-stack-vars offset 0). So the same stack address re-materialised at two sites separated by a jal means CSE was PREVENTED from merging => not the same function body. 17 non-inline spellings failed; a `static inline` helper reproduced the prologue BYTE-FOR-BYTE first try. Reusable probe: scan the ~1,200 built objects for that signature in NON-INCLUDE_ASM functions. - §82 ORACLE 2 -- SCALAR vs AGGREGATE DECIDES *WHEN* A STACK SLOT IS ALLOCATED: lazily at first `&` for a scalar, AT DECLARATION for an aggregate. Six GTE result words had to be six separate longs, not a struct, or they don't land after the inlined helper's temps and the frame isn't 0x270. Second-order: it also flips MEM_IN_STRUCT_P (§30's /s) -- with one word a fixed-address scalar, ((PolyF3*)pkt)->rgbc stops aliasing it, so a store needed respelling to keep the target's nop. A scalar-vs-struct choice is simultaneously a frame-layout AND an aliasing decision. - BANKING FOOTNOTE (§75a class A): first bank rejected `conflicting types for ApplyMatrixSV` -- draft (MATRIX2*, SVECTOR2*, SVECTOR2*) vs the TU/fleet canon (void*, void*, void*), 2,286 of 2,835 sites. Conforming the decl is byte-neutral and banked first try. On a jr function expect BOTH gates to speak: the carve chain answers the jump table, §75a answers the declarations. - Also reproduced: §78 (reuse a busy variable), §80(i) (a lever went -8 -> exactly neutral as the base moved), §72 (a register pin made it worse). - AGENT'S OWN CAVEAT, recorded not hidden: one zero-byte __asm__ keeps a vestigial `mnc = hmid` alive that flow.c would delete (costing 10 ins + the 0x130 spill slot). Emits nothing, compile is 1061 exact, but it is a documented stand-in -- 12 natural spellings measured, all DCE'd. |
||
|
|
faf4547345 |
feat(phase-29): func_8017C954 BANKED — jr carve chain cleared; a shared type was PRESENT but INVISIBLE
- BANKED (1,194 ins, ×1 distinct-code). Chain cleared, each step byte-gated before the next was
built on it: one-line fix to jr_isolate_all._engine_types() -> jr_isolate_all --only
func_8017C954 (2 fns / 1 object, NOT the bare 47-fn / 21-object resegment) -> BYTE-IDENTICAL
b7b0d4ae -> jtbl_carve --func func_8017C954 (44-piece carve set + interleave order) ->
BYTE-IDENTICAL -> harvest_verify VERIFIED BYTE-IDENTICAL -> R22 clean-fleet 140/140,
tools-health OK. instr 80.5 -> 80.6%; distinct-code 3,842,906 -> 3,844,100.
- THE DEFECT (tools/jr_isolate_all.py): _engine_types() harvested shared type names with four
patterns -- `typedef ... X;`, `} X;`, forward-decl `struct X;`, fn-ptr typedef -- and a TAGGED
DEFINITION WITH A BODY matches NONE of them. So `struct PW8017E6D8 { int w; }
__attribute__((packed));` at engine_types.h:658 was present in the shared header yet invisible
to the carried-type check, and `extern struct PW8017E6D8 D_801E1EC4;` could not be placed.
MEASURED BLAST RADIUS: 77 such tags in engine_types.h were invisible. One added pattern fixes
all 77.
- WHY THIS COST 20 MINUTES INSTEAD OF A MYSTERY BYTE-DIFF THREE PHASES LATER: the Phase-26 audit
had already turned this predicate's SILENT DROP into a LOUD REFUSAL. The original bug dropped
4,040 col-0 decls, 683 of them function PROTOTYPES -- and a dropped prototype is a SILENT
BYTE-CHANGER (C89 implicit `int f()`; return type drives delay-slot fill in this codebase). The
refusal named the exact symbols and the exact remedy. A loud "I cannot place this" is worth far
more than a green build -- the audit paying for itself, live.
- §81: the 3-step jr-carve chain + why match_one CANNOT see the problem (it masks jal/HI16/LO16,
so a jump-table function reports MATCH while the whole-binary gate reports DIFF, correctly).
Detect with `grep -cE 'jr \$(v0|v1|a0|t[0-9])'` on the target .s + a jtbl_ in asm/<ov>/data/.
ALWAYS use --only: bare would have resegmented 47 jr-functions across 21 objects.
|
||
|
|
8b828f1ea6 |
feat(phase-29): BEHEMOTH func_8017BF14 CLOSED — 45 -> 0 (4,763 ins, the largest match yet)
- 45 -> 37 -> 33 -> 21 -> 11 -> 3 -> 2 -> 0, reproduced 3x from independent work dirs. Verified independently before believing it (R14): match_one MATCH (4763 ins), then harvest_verify --binary ov_SC03_116 BYTE-IDENTICAL, then R22 clean-fleet 140 passed, 0 failed of 140. distinct-code 3,838,143 -> 3,842,906 = 68.1% -> 68.2%. instr 80.5%. Agent was interrupted by a weekly API limit and RESUMED FROM ITS TRANSCRIPT -- its round-2 harness survived, nothing was re-derived. - §80 THE PROCESS CORRECTION, worth more than the match: A DO-NOT-RE-BUY ENTRY IS SCOPED TO ITS BASE, NOT TO THE FUNCTION. Three of round 1's ~40 measured negatives INVERTED on round 2's base -- the same edit (qsingle23) measured 1,040 mismatched on the 45-base and 11 on the 21-base. Re-testing the round-1 negative list cost ~20s and produced THREE of the seven winning levers. Such a table records (edit, base) -> result, NOT edit -> useless; after any lever that moves the base materially, RE-RUN THE NEGATIVE LIST. This retroactively qualifies every do-not-re-buy table in the cookbook (§45, §60b, §75a, §76, §78, §79). Concrete: round 1 measured "removing the va->$t2 pin costs 4% elsewhere" => keep the pin; on a base with c0..c3 at function scope, removing those pins is worth 21->13. Same experiment, opposite conclusion. - MY FLAGGED "#1 MOVE" LOST, and the failure is the finding. I briefed variable REUSE (§45-A / RC-14) as the top lever because it took func_8017F510 from 97->10. Swept in full here: EVERY merge lost, 43-3294 across 8 merges. Reason: the TRI and QUAD grants did not differ by RANK but by IDENTITY -- two independent allocno sets, and re-ranking inside one set cannot fix a two-set problem. Diagnose ranking-vs-identity before reaching for a merge. The actual fix (c0..c3 at FUNCTION scope, 33->21) was read off the two matched relatives (b5:310, b4:338) and confirmed against the target -- the 4th time today that reading a matched relative beat the clever lever. - PIN'S HIDDEN COST, cited: combine_regs' hard-register branch (local-alloc.c:1795, reached from :1295 with already_dead==0) records the pinned reg in qty_phys_sugg UNCONDITIONALLY -- no death guard. A pin invites local-alloc to tie producer chains into it. New cure R7: a zero-byte __asm__ ref keeping the pinned value live past the temp so find_free_reg can't honour the suggestion -- closed the last 2 ins (c1->$a0 is uniquely load-bearing; every alternative pin lost 64 ins). - §78's attribution primitive RUN and REPRODUCED: under -fno-schedule-insns, -fno-schedule-insns2 and both, order unchanged => the rgb transposition was never a sched.c decision. - Cold-start economics complete: round 1 = decode + exact length + exact frame + 99.06%; round 2 = the last 45, and cheaper. Budget TWO passes at this size. 5th source copy-paste artefact found. |
||
|
|
f5f8dec5ee |
docs(phase-29): the cold-start experiment — func_8017BF14 to 45/4763; §79; full R22 discharged
- COLD-START RESULT (verified independently): 4763/4763 ins, 45 mismatched = 99.06% byte / 99.94% structural, exact frame, exact opcode histogram. NOT a match; nothing banked (45 != 0, the byte-gate is the sole arbiter). The residual is 3 register-grant ties, 0 structural divergence. Named next move: variable REUSE across c0..c3/a0v..a3v, the one §76 lever class the pass never reached. - MY BRIEF'S PREMISE WAS WRONG BY CONSTRUCTION -> §79. I chose this target partly because §71's callee-set fingerprint returned 0.00 against every matched giant = "a genuine cold start". But the function makes ZERO jal calls, so its callee fingerprint is EMPTY and §71 CANNOT FIRE: 0.00 meant "cannot answer", not "no relative". Grepping the target's DATA symbol D_800A5E60 found the matched func_8017BEBC at once -- func_8017BF14 is the 4-light-box member of the same renderer family whose 3-box sibling func_8017D960 was matched hours earlier. RULE: when §71 returns an empty/zero-overlap callee set, fall back to DATA-symbol fingerprinting; an empty fingerprint must never become a cold-start brief. - NEW LEVER (§79): THE FRAME LAYOUT IS A DECLARATION-ORDER ORACLE. gcc-2.7.2 assigns stack slots to spilled pseudos in pseudo-number order, and pseudo numbers follow first use ~ declaration order -- so the target's frame map reads back its source's declaration order. Moving ONE line took 73% -> 84% structural and brought all 127 slots into exact correspondence. - §76 CONFIRMED AT SCALE: the entire -62 length residual was ONE allocno-class decision (c0..c3 declared inside the cull blocks -> 1-death local allocnos -> global.c:668-671 removes those regs from the global pool -> r1lo spills), 52% -> 93%. An __asm__ ref-dial reached the same spill and scored WORSE -- declaration scope beat the ref dial again. - PIN NUANCE: pins are safe on a 0-jal function (§74's hazard cannot arise), 4 pins took 94% -> 99%; but §72 held -- pins 5 and 6 made it worse. - EFFORT ANSWER, HONEST: xHigh from a genuine cold start on a 4,763-ins giant bought the decode, the exact length, the exact frame and 99.06%, and did NOT close. Budget a SECOND pass at this size: the first buys structure, the last ~1% is register grants. - FULL R22 DISCHARGED: make clean + extract-all + check-all -> 140 passed, 0 failed of 140 (run after the agent finished, per the deferral recorded in the pool commit). tools-health OK. |
||
|
|
a1f1a948af |
feat(phase-29): h_norm-remappable pool — +4,919 ins banked, no cracking, no agent
- BANKED (each whole-binary byte-gated; make check-all -> 140 passed, 0 failed of 140): func_80130D48 ×4 (1,064) · func_8018F3E4 (478) · func_8018B3D0 (478) · 13 × 223-ins siblings of func_8017E6D8 (2,899). distinct-code 3,833,224 -> 3,838,143 = 68.0% -> 68.1%. - TWO OF MY OWN COUNTS COLLAPSED UNDER SCRUTINY BEFORE I ACTED ON EITHER (R14/R35): "func_8017CA80's family = 102 unmatched" was really 13 -- my count tallied family members whose NAME appears as a stub anywhere in the fleet, not instances actually unmatched (a semantics error, not arithmetic). "56,267 ins remappable" was really 8,114 -- 86% was the known -O0 / deferred set (the func_80144B9C whale, the func_8013C414 cluster). I nearly recommended a target on the first number. - THE §77 CARRY GAP IS THE DOMINANT COST OF MECHANICAL REMAP: 23 of 27 first-pass CC1-FAILs. NEW .run/giants/s19_remap_tu.py sources the preamble from the exemplar's OVERLAY TU (the block between the previous top-level `}` and the def), applies family_remap's own substitution map, and adds the two includes match_one never adds -> 21 drafts went 0 MATCH -> 14 MATCH. The 13 223-ins siblings share ONE exemplar, so a single preamble fix cleared all 13. - USEFUL ASYMMETRY: func_8018F3E4/func_8018B3D0 FAILED match_one but BANKED in the whole-binary gate -- the real TU supplies decls the standalone compile lacks. A match_one CC1 FAIL is not a reason to skip the real gate on a remapped sibling. - RESIDUAL 3,195 ins, causes NAMED not guessed: func_8017D5C0 (952) matches standalone, gate reports `conflicting types for memcpy` = the §58 red-herring (a warning from an unrelated TU position; SESSION-14 hit the same label and the true cause needed a hand-splice + real cc1 stderr). func_80166994 ×3 + func_8016A290 ×4 still CC1-FAIL after the TU carry. - FULL R22 DEFERRED DELIBERATELY: make clean wipes asm/, which the concurrently-running BF14 agent reads on every probe. This batch changed only src/*.c (no config), so check-all is sound; the clean R22 must still run once the agent finishes. |
||
|
|
f9a2de3edd |
feat(phase-29): BEHEMOTH #2 func_8017D960 CRACKED (1806 -> 0) + its 5-member family = 16,690 ins
- CRACKED pin-free at xHigh (Opus 5 agent), then ALL FOUR family siblings banked via §40 remap, each MATCHING FIRST TRY: ov_SC03_090 (the crack) · ov_SC03_089 · ov_SC03_104 · func_8017E778 @ ov_SC03_091 · func_8017CD9C @ ov_SC03_102 (the last two cross-address). Verified independently before believing the report (R14): match_one MATCH (3338 ins), then harvest_verify BYTE-IDENTICAL on all five binaries, then R22 clean-fleet 140/140. - METRICS: distinct-code 3,816,534 -> 3,833,224 (+16,690) = 67.7% -> 68.0%, the first percentage-point movement in that metric all session. instr-weighted 80.3% -> 80.5%. Session distinct-code total +19,712 ins, ALL from the three behemoths; propagation gave +0. - MY BRIEF WAS WRONG IN AN INSTRUCTIVE WAY -> §78. I said a negative length drift means "missing instructions". The 4 absent instructions were 4 emit tails × 1 nop -- delay slots the target could NOT FILL because the register it wanted was still live. otp at function scope has 4 deaths -> fails local-alloc.c:472 -> global allocno in $a2 -> via global.c:668-671 pushes tp off $a1 -> the 0xFFFFFF mask is free early -> maspsx hoists it into the slot. Declaring otp PER EMIT ARM fixed the whole drift in one edit (3334->3338, 1806->333). SECOND TIME IN ONE SESSION a "structural"-looking residual was an allocno-class choice (the first: F510's "scheduling" transposition, §76). A nop present in the target but absent from the draft is usually a register-liveness fact, not missing code. - TWO MORE REUSABLE FINDINGS (§78): gcc-2.7.2 fold NEVER leaves a literal first in an `|` chain (7 parenthesisations, all reassociate) -- so `or acc, var, K` first in the target means K was a VARIABLE in the source, an asm->source read that retires a whole sweep family. And "make it a variable" has TWO separable effects (fold-opacity vs a new allocno): a fresh short-lived local fixes structure and wrecks allocation (690 mismatched, damage ~300 ins away); reuse a busy one. - ECONOMICS: 9 levers, each necessary by drop-one ablation, and 5 of the 9 were read straight off the MATCHED relatives func_8017F510 (cracked earlier today) and func_8017CA80. Crack the smaller family member first -- it is a lever library for the larger one. - NEW TOOL .run/giants/s19_remap_family.py: family_remap + the §77 preamble carry in one step (reproduces the exemplar's FULL file-scope preamble with the tool's own substitution map applied). Took the 4 siblings from "4 rounds of CC1 FAIL each" to MATCH first try, ×4. |
||
|
|
130b9407b1 |
feat(phase-29): func_8017F5B4 (1,511 ins) banked MECHANICALLY off behemoth #3 — ~0 agent tokens
- func_8017F5B4 @ ov_SC02_031 shares behemoth #3's h_norm AND h_seq (96fe0455c344 / 9a6bd2b91fd4) with a different h_exact = the same instruction stream differing only in masked reloc fields. The §40 family_remap case exactly, so NO agent was spent: family_remap --addr 0x8017F510 --from ov_SC03_006 --to ov_SC02_031 --to-addr 0x8017F5B4 substituted 52 per-overlay symbols correctly on the FIRST invocation. - match_one -> MATCH (1511 ins); harvest_verify --binary ov_SC02_031 -> BYTE-IDENTICAL; R22 clean-fleet 140 passed, 0 failed of 140. - DISTINCT-CODE 3,815,023 -> 3,816,534 (+1,511). With behemoth #3 that is +3,022 distinct-code instructions from the two behemoths, versus +0 from every propagation win this session. - ALL the work was PREAMBLE, none of it the body -> cookbook §77. Four CC1 FAIL rounds, each naming one construct the extractor drops: (1) multi-line `typedef struct {...} PolyGT4;` -- family_remap's backward walk accepts a line only if it STARTS with extern/typedef/comment, and a multi-line typedef ENDS with `} PolyGT4;`, so the walk halts there AND LOSES EVERYTHING ABOVE IT; (2) hence the file-scope extern block above the #define BOXTEST/ATTEN block; (3) the exemplar's own #include lines (PolyFT3/PolyFT4 live in engine_types.h). - THIRD CONFIRMATION TODAY OF ONE DEFECT CLASS, NOW ACROSS TWO TOOLS. §75b found dedup_propagate dropping a file-scope #define and PREDICTED the generalisation; family_remap then dropped a typedef, an extern block, and the includes. RULE (§77): after any mechanical template/propagate step, diff the exemplar's full file-scope preamble against what the tool emitted. A CC1 FAIL on a remapped sibling is a PREAMBLE report until proven otherwise -- it says nothing about whether the remap was right. - Artifact preserved: .run/giants/s19_func_8017F5B4_remap.c |
||
|
|
3ffff74f5b |
feat(phase-29): BEHEMOTH #3 func_8017F510 CRACKED — 97 -> MATCH (1,511 ins), pin-free
- BANKED into ov_SC03_006 through the whole-binary byte-gate (G3/P9); R22 clean-fleet 140 passed, 0 failed of 140. Verified independently before believing the agent's report (R14): match_one -> MATCH (1511 ins), then harvest_verify -> BYTE-IDENTICAL. - DISTINCT-CODE 3,813,512 -> 3,815,023 = +1,511, EXACTLY the function's instruction count and the ONLY distinct-code movement of the entire session. Reach is ×1 by sig, no propagation -- which is precisely why it moves the metric propagation cannot touch. instr 80.3%, fn 89.18%. - EFFORT EXPERIMENT (Drew): behemoths #1-#3 were worked at High; this is the first at xHigh (Opus 5 agent). It closed a residual the lower tier had fully localized but could not move, and that 3,663 permuter candidates at base 97 had failed to improve by even 1. - MECHANISM -> cookbook §76: the allocno CLASS (local vs global) is the dominant regalloc lever and C reaches it ONLY through declaration scope and variable reuse -- unreachable by statement order, expression shape, pins, or random search, which is exactly why the permuter was spent. (1) `otp` per emit ARM: 4 deaths -> four 1-death local pseudos (local-alloc.c:472); its second-order effect via global.c:668-671 (local placements re-marked as HARD regs for global-alloc) had made the target's otp=$a0 STRUCTURALLY IMPOSSIBLE, visible as hard-reg 4 in the `;; N conflicts:` tail of the .greg dump. (2) `cb` reused as the unlit rgbc temp: refs 27->39 lifts its global.c:594 allocno_compare priority past `tp`, flipping the 3-colouring -> 97 -> 10. (3) one shared `rgbw` temp -> 10 -> 2. (4) mny-before-my + one zero-byte __asm__ at the head of the tri cull block -> MATCH. - THREE CORRECTIONS TO MY OWN BRIEF, all byte-evidenced: residual B was never a scheduling residual (it fell out free with lever 2 -- a register grant seen as a schedule diff); residual A is RTL EXPANSION order, proven with -fno-schedule-insns AND -fno-schedule-insns2 (source order survives both -- that attribution primitive is the reusable bit); residual C had no single c3 seed (c3 has no lever of its own, it moves only when cb out-ranks tp). - FIXED a latent SHARED-HEADER defect, pre-existing and unrelated to the draft: src/shared/engine_types.h closed its include guard at line 1174 of 1259, leaving 11 typedefs / 85 lines OUTSIDE the guard since the crack-wave lift. A TU including it twice re-declares them and gcc-2.7.2 rejects a repeated typedef even when identical -> `conflicting types for Blk16_956C`. Guard moved to EOF; byte-neutral. - ARTIFACTS TRACKED (R20): .run/giants/s19_func_8017F510_b4.c (130-line dossier) + s19_f510_report.md, whose ~50-row do-not-re-buy table is arguably worth more than the match, + the s19_* analysis tooling. - STRETCH, MEASURED: func_8017F5B4 (1,511 ins, ov_SC02_031) has a DIFFERENT h_exact -- not a dedup sibling, a family_remap TEMPLATE candidate off the b4 source. |
||
|
|
6e9cbda926 |
feat(phase-29): func_80174CB0 ×3 -> ×135 (§75c pair); the census predicted the residual exactly
- dedup_extend banked 132 / 179 planned across 135 binaries: func_80174CB0 VERIFIED in 132, FAILED in exactly 3. 123 ins × 132 = 16,236 ins. - THE PREDICTION HELD TO THE OVERLAY. The blocker breakdown across the original 134-binary sweep was 131 class-B (func_8012F14C arity split) / 3 class-A (func_80012ABC, census 73 s32 vs 7 s16). Fixing class B alone banked 132 and left 3 -- precisely the class-A set. A diagnosis that predicts WHICH members will still fail, and is right, is much stronger evidence than one that explains failures after the fact; same shape as §75b predicting that the 3 stuck members would be exactly the 3 files carrying the __volatile__ spelling of SHB. - FLEET: instr-weighted 80.2% -> 80.3% (10,539,723 -> 10,555,959); fn-count 89.14% -> 89.18%; distinct-code 67.7% UNCHANGED (propagation moves coverage, not distinct-RE -- fresh cracks are the only lever there). dedup 1886 validated / 0 failed, C1 coverage 239,604/239,604. 0 NON_MATCHING (G4). - R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140. - cookbook §75c committed with this batch. The 3 residual overlays need the 7 `s16` func_80012ABC decls normalized -- worth 3 overlays only, so do it only if trivially cheap. |
||
|
|
3bbfe21596 |
feat(phase-29): func_80165CA0 ×3 -> ×135 via ENGINE_SHB; +22 fns ×1; §75b (the carried-#define gap)
- dedup_extend banked 157 / 478 planned across 135 binaries: func_80165CA0 (99 ins) ×135 (~+0.10pp) + 22 other functions ×1 picked up in the 3 overlays the first sweep excluded. - FLEET: instr-weighted 80.1% -> 80.2% (10,525,534 -> 10,539,723, +14,189 ins); fn-count 89.09% -> 89.14%; distinct-code 67.7% (unchanged — propagation moves coverage, not distinct-RE). dedup 1886 validated / 0 failed, C1 coverage 239,472/239,472. 0 NON_MATCHING (G4). - R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140. - §75b — extraction lifts `extern`s but NOT file-scope `#define`s, so a body matched with a macro in its preamble compiles only where that overlay's define is in scope ABOVE the splice point. Signature is a LINK error (`undefined reference`), never `conflicting types`: an unexpanded SHB(x) parses as a call to an undeclared function. The diagnosis PREDICTED the membership — the 3 stuck members are exactly the 3 files carrying the __volatile__ spelling of SHB, i.e. the function's own preamble still sitting above its own instantiation. - R14/R35 IN ACTION: the full-sweep census REVERSED the ranking I had just committed. I put the class-A normalization first at "~+0.13pp if it reaches ×138"; measured across all 134 it is worth 3 overlays (func_80012ABC 3, func_8012F14C 131). The cheap win was the one I ranked third. §75a's "collect across the whole sweep before scoping" earned itself immediately. - NEXT (specified, not guessed): func_80174CB0 is class B on func_8012F14C (1944 `(s32)` vs 968 `(s32,s32,s32)`). The macro carries the 3-param prototype; the failing TU declares the 1-param one FIRST (ov_SC01_001: TU@328 vs instantiation@2616) -> two prototypes, different arity -> reject. Per cdecl.compatible's MEASURED rule a K&R `extern void func_8012F14C();` is accepted BOTH ways round here (prototype-first + `()`-second always; `()`-first + prototype-second when no param default-promotes, and s32 does not) -> it should satisfy both populations in either order. One-line probe on the carried decl, byte-gate the 3 members, then extend. |
||
|
|
39127535da |
feat(phase-29): func_8014F3E8 ×4 -> ×138 via dedup_extend; §75a enumerates the exclusion classes
- THE NORMALIZATION PAID: one `dedup_extend --binaries <the 134 excluded>` banked 134/400
planned -- func_8014F3E8 VERIFIED in ALL 134 -> ×138 total (+4,288 ins), no drafting at all.
A 4-overlay island became full fleet reach because the carried extern finally agreed.
- FLEET: instr-weighted 80.0% -> 80.1% (10,509,526 -> 10,525,534 = +16,008 ins, exactly the
projected 84×138 + 32×138); fn-count 89.02% -> 89.09%; distinct-code 67.7% (unchanged, as
expected -- propagation moves coverage, not distinct-RE). dedup 1884 -> 1886 validated / 0
failed, C1 coverage 239,315/239,315. 0 NON_MATCHING (G4).
- R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140.
- §75a — "PROPAGATION-CAPPED" IS AT LEAST THREE CLASSES, and the classifier names which:
A minority spelling `conflicting types` + a lopsided census (1710 vs 4) -> normalize, cheap
B genuine arity split same message, TWO real populations (func_8012F14C: 1944 `(s32)` vs
968 `(s32,s32,s32)`) -> the §29 loose-typing wall; a K&R `()` MAY satisfy
both but is order-dependent -> PROBE, do not normalize on a guess
C missing extern `undefined reference to 'SHB'` -- a LINK error, unrelated to types
The discriminator is one grep (census the symbol cc1 named) and it decides the remedy.
- R14 self-correction recorded: I predicted func_80174CB0 was "the identical class". It is class
A in KIND but on DIFFERENT symbols, and different ones per overlay (func_80012ABC at
ov_SC01_000 where the minority is on the TARGET side; func_8012F14C at ov_SC01_001 = class B).
One member's error names one blocker, not the blocker set -- collect the classifier's line
across the whole sweep before scoping a fix.
- func_80174CB0 (×3) and func_80165CA0 stay capped, each now with a named cause and a named next
probe -- not a wall verdict.
|
||
|
|
2fcb8de6bf |
fix(phase-29): normalize func_8014F468 to the fleet-canonical s32 (unblocks the ×138 reach) + §75
- THE PROPAGATION CAP WAS A MINORITY-SPELLING SOURCE OVERLAY, byte-censused:
extern s32 func_8014F468(void); 1710 | s32 func_8014F468(void) 134 <- fleet canon
extern void func_8014F468(void); 20 | void func_8014F468(void) 4 <- the outlier
and ALL 4 `void` definitions are ov_SC07_{006,007,010,011} — the overlay the F3E8 body was
banked from. dedup_propagate carries the source overlay's file-scope externs into the shared
macro VERBATIM, so the macro inherited `extern void` and the 134 overlays that define the
symbol `s32` rejected it. Propagation landed on exactly that 4-overlay island.
- The exclusion message ("byte-diverge / irreconcilable") is provably the wrong cause: members
are selected BY h_exact, so all 138 are byte-identical by construction. It is a COMPILE
conflict, never a byte one (same defect family as §68's mislabel, same tool).
- NORMALIZED the 24 minority occurrences to s32 (4 definitions + 19 overlay externs + the 1
line in the freshly-authored macro). func_8014F468 is a pure inline-asm $sp-switch trampoline
— no C-level value flow — and 134 overlays already PROVED s32 is byte-correct for the
identical function. Fleet is now uniform: 1730 extern s32 + 138 s32 defs, 0 `void`.
- BYTE-GATED the complete blast radius (the 4 instantiators of DEFINE_func_8014F3E8):
ov_SC07_006 7ca772be · 007 b3b95547 · 010 d7b5875d · 011 9885af74 — all BYTE-IDENTICAL.
- cookbook §75: census the carried extern before believing an exclusion message; prefer a
majority-spelling source overlay; always pass --recover; after normalizing use dedup_extend
(the body is already a macro) not dedup_propagate --addr.
|
||
|
|
6f9860c46a |
docs(phase-29): §74 — pin-safety audit; the 5-pin behemoth draft is SAFE (open action #3)
- AUDITED .run/giants/s18_func_8017D960_b2.c (pins $25 $17 $19 $20 $21) WITHOUT recompiling: the SESSION-18 match_one object survives and cmp proves its t.c is this draft. - VERDICT SAFE. The corrupting form of the §72 hazard is a CALLER-SAVED pin ($25=$t9) whose live range spans a jal — gcc-2.7.2 does not save/restore an explicit-register variable across a call. Byte-checked: exactly 3 jal, all at 0x2c-0x50; first pin write at 0x58 => NO call after the pins are established. Corroborated by a token census of the C (every call-shaped token after line 270 is a file-local macro: gte_*, BOXTEST, ATTEN, CLAMP80). - The observed excess writes (2/3/3/5/5 vs 2 assignments each + 1 epilogue lw) are the BENIGN §72 mode: gcc using the pinned reg as scratch before the pinned value lands (lui/lw/addiu on $20, with addu t9,s4,zero routing r1's value out through it). Nothing live was clobbered. - cookbook §74: the reusable audit (objdump the surviving object; compare jal addresses against the first pin write; expect writes == assignments + 1 epilogue restore) + the standing rule — prefer a callee-saved register for any pin outliving a call; a caller-saved pin across a jal is a real wall verdict, not a drafting slip. |
||
|
|
1c0d29d91d |
feat(phase-29): §30#2 widen batch — func_8014F3E8 + func_8014D4C0 banked; §73 (the two axes)
- FLEET WIDEN (T2, one edit): extern void -> extern s32 for func_8014F3E8 + func_8014D4C0 across src/** (16 decls in engine_core.h + 5,079 in 3,459 overlay .c; 0 `extern void` left, 0 pre-existing `extern s32`). Scope re-verified against the tree first (R14/R35): the SESSION-18 counts reproduce exactly and no decl exists outside the `extern void <name>` shape in any .c/.h under src/. - BYTE-NEUTRALITY OF THE WIDEN ISOLATED FIRST: ov_SC07_006 7ca772be + ov_SC01_000 9052dc0e BYTE-IDENTICAL before splicing any draft (ov_SC01_000 chosen because it instantiates the two return-CASTING macros — the only sites a decl's return type could touch codegen). - BANKED into ov_SC07_006 (both ×1, both reach ×138 by sig: single h_exact across 138/138): func_8014F3E8 (32 ins) on gate 1; func_8014D4C0 (84 ins) on gate 2. - FINDING -> cookbook §73: the widen fixed only HALF the conflict. A def-side self-decl conflict has TWO independent axes — RETURN (fleet macro-widen, T2, R22-mandatory) and PARAMS (canonical param types + casts at each USE, T0, no fleet edit). func_8014D4C0 failed the first gate on the PARAM axis (canon `void*` vs draft `u16*`); the §17a-1 move applied to the def's own signature banked it with nothing outside the draft touched. Diagnose the axis before reaching for the expensive fix. - R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140. make report: dedup 1884 validated / 0 failed, C1 coverage 239039/239039, 0 NON_MATCHING (G4). Fleet 80.0% instr / 67.7% distinct / 89.02% fn-count (the ×138 propagation is the value). |
||
|
|
dfa366c7c6 |
docs(phase-29): cookbook §72 — behemoth #3 to 1511/1511; a register pin is a PREFERENCE, not a reservation
func_8017F510 (1,511 ins): EXACT length, frame 0x258 exact, byte-exact prologue AND epilogue,
identical sp-slot set, 99.5% register-masked structural / 93.3% byte-aligned, SYMS-OK, 97 divergent.
Not a match (G3). §71's callee-set lever delivered ~90% of the C and a first compile at 1528/1511.
- CORRECTNESS FINDING (qualifies §17): a local `register s32 x __asm__("$30")` pin produced a
seductive 1511 ins / 98.9% and was a MISCOMPILE -- gcc-2.7.2 ALSO allocated $s8 to an unrelated
live value. A pin is a HINT to the allocator, not a reservation. Never ship one without inspecting
the pinned register's defs. Banked work is safe by construction (the byte-gate rejects a
miscompile); the exposure is UN-GATED drafts. ACTION: behemoth-2's draft carries FIVE pins
($25 $17 $19 $20 $21) and must be re-checked before anyone builds on it.
- THE HONEST FIX was source-level: the +17 drift was live-range stretching from REUSING w/wz for the
vertex-word reads (spilling amb, 7 lw+nop pairs). Dedicated temps -> 1528->1511, 88%->99.6%, no pin.
- GIV RECORD ORDER (§70 family): part->prim must be read BEFORE part->nprim -- loop.c:combine_givs
walks bl->giv in REVERSE record order, so the last-recorded giv becomes the combined base.
- RESIDUAL 97 traced to ONE seed: c3 is $a2 in the target, $a3 in the draft; tp takes the other of
the pair and renames the whole 4-tail block. Fix c3 -> $a2 and ~93 should fall together.
- SPENT, byte-recorded: decl-order permutations, block-scoping, splitting/inlining tp, reusing f0,
vertex axis orders, and decomp-permuter (4,724 candidates, base 97, ZERO improvement -- a §3 hard
tail outside the C-randomisation space).
- b3_align.py / b3_pos.py supersede the b2_* aligners.
|