mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-29 15:18:24 -04:00
88aaa7d59f99b9bcbbbaddf305c646b668965709
563 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bbd51be24a |
docs(phase-30): SS126a — a bare except around a coverage oracle re-creates the silent skip
I under-counted this cluster 8x (reported 275 stubs/18 overlays; truth 2,184/138). The scan ran during a background rebuild AND wrapped corpus.stubs() in `except: continue`, so every R32 coverage refusal became a silent skip and the total was taken over the few overlays that happened to be re-extracted already. Two of our own rules broken at once: a measurement taken during a rebuild is not a measurement (caught EARLIER the same session, by the same assertion I then suppressed), and R32 lives in the CALLER — an oracle only asserts coverage if the caller lets it raise. It also cost credibility the other way: I used the bad number to declare the T0(f) "2,192 open members" pin STALE. The pin was right. R35 applies to a re-measurement as much as to the original measurement. Checkpoint updated with the corrected population and the completed fleet-wide sweep. |
||
|
|
803d73bb97 |
docs(phase-30): SESSION-28 checkpoint — T2 proven + tooled; fleet 92.71/88.3/78.7, R22 140/140
Records the T2 result as the phase's biggest unblock: the carve-within-a-carve is byte-neutral (Arm-A does NOT bite), the real constraint is that an address range is not an optimization region (SS126), and tools/o0_subsplit.py implements the correct bound. Measured, not assumed, what it unblocks: 275 open stub instances across 18 overlays in the 0x8013B568..0x8013C98C cluster, homed in an -O2 jr split — plus a note that the T0(f) "2,192 open members" pin is STALE and must be re-derived before costing (R37). Also flags my own under-count: the "15 contiguous -O0 fns" came from an asm scan that cannot see matched functions. |
||
|
|
d2b48b7680 |
feat(phase-30): tools/o0_subsplit.py — the T2 carve-within-a-carve driver; +3 banked in ov_SC03_015
Promotes the proven probe (commit:1266) into a real tool, and validates it FIRST-TRY on a
fresh overlay.
tools/o0_subsplit.py <ov> --lo <vram> --hi <vram>:
- derives the range's contents from the SOURCE ANCHORS (overlay_src_split.parse_overlay_c:
`asm` = unmatched stub, `define`/`def`/`nonmatch` = already matched), NEVER from an asm
scan -- a matched fn emits no .s, which is exactly the blindness that made the range look
like a clean contiguous run (SS126 / SS124's shape);
- computes the -O0 bound as (address range MINUS already-matched bodies) and emits ONE
sub-region per maximal run of unmatched anchors (K matched islands => K+1 regions);
- names each `<ov>_o0<letter>` picking free suffixes, so the widened Makefile glob selects
them; refuses loudly if it runs out or if the range spans >1 object or is already -O0;
- honours the one-carve-per-region law (forces a cut at every already-banked jr in the
object) and reuses jr_isolate_all's plan/build_new_config/ascending-unique validation
verbatim, so carve-repoint + source-repartition stay on the proven path;
- warns (does not refuse) when a stub in an -O0 run lacks the frame-pointer prologue --
the byte-gate is the arbiter, not the heuristic.
VALIDATION on ov_SC03_015 (untouched by the manual probe): the tool independently derived the
SAME structure found by hand on ov_SC03_014 -- 2 matched -O2 islands (func_80184440,
func_801848E4), 2 -O0 regions (8 + 7 fns), same 5 cuts. Sub-split -> BYTE-IDENTICAL. Then 3
drafts, each global DERIVED FROM THAT OVERLAY'S OWN ASM (%hi operand) rather than copied:
3/3 match_one --o0 MATCH (22 ins), 3/3 through the whole-binary gate.
BANKED this commit: func_801846E4 / func_8018473C / func_80184794 in ov_SC03_015 (6 across
the two overlays now). The other 24 stubs in the region are undrafted -- the route makes them
DRAFTABLE (they were un-bankable at any effort before); drafting them is crack-wave work.
R22 CLEAN-FLEET: extract-all 139/139 (+main); check-all 140 passed, 0 failed of 140.
cookbook SS126 (the address-range-is-not-an-optimization-region law + the probe ladder).
|
||
|
|
8d4f2a38cb |
fix(phase-30): RETRACT 2 of 3 jr wall verdicts — SS125 rewritten; my measurement was the defect
Max-effort re-measurement of the three jr refusals I ledgered earlier this session.
Two of the three verdicts were FALSE. Every number below is SHA vs config/check.<ov>.sha
from a clean tree, with the restore re-verified.
func_8018057C / ov_SC01_009 : jr_isolate_all is BYTE-NEUTRAL
-> "JR-ISOLATE-BREAKS-BYTES" RETRACTED; original failure not reproducible.
func_80191C50 / ov_SC06_018 : isolate NEUTRAL -> carve DIVERGED
(got 1b1667ea, want cbbc4f44) -> the ONE real instrument failure. CONFIRMED.
func_8017BEBC / ov_SC04_004 : carve is BYTE-NEUTRAL (body-free)
-> failure is the TEMPLATED BODY, the OPPOSITE of what SS125 first claimed.
Re-probed once more from a verified-clean tree: still gate-fail. Reclassified
BODY-TEMPLATE-GATE-FAIL.
So the tidy "two apparent walls are ONE tooling problem" conclusion was wrong: they
are two different problems, and the third target has no demonstrated problem at all.
ROOT CAUSE, and it is mine not the tools': a grep-of-the-build-log gate inside a driver
that did not revert on abort. config/overlays.mk is SHARED, so target 1's half-applied
isolate was still in the tree while target 3 was measured. Separately reproduced the
SS42b stale-object trap head-on: `git checkout -- config/` WITHOUT a re-extract turned a
byte-identical overlay into [FAIL] got 8f28aa77 / want 38a3d919 (Phase-20's R22
corollary, live).
SS125 rewritten. The METHOD (split the carve from the body, one build) is kept and is
what refuted this section's own first conclusion; what is added is the instrument rules
that make its answer trustworthy: compare the SHA against config/check, never grep the
log; re-extract after every config change AND every revert; a driver that aborts a
target must revert it before the next; verify the BASELINE against canonical too.
Meta-lesson recorded: SS53 says a 0% from the wrong TOOL manufactures a doctrine — this
is the same failure one level up, a verdict from the wrong MEASUREMENT, and my own
diagnostic script is an instrument subject to R35 like any other.
Ledger corrected in place (3 entries, superseding the earlier misattributions), so the
scheduled repair is the right one. No source/config change; no bank affected; the fleet
is untouched at 140/140 (last full R22 this session, HEAD commit:1263).
|
||
|
|
c95b61063f |
docs(phase-30): SS125 split the CARVE from the BODY; 3 jr residues ledgered by STAGE
The session's most useful finding is an instrument ticket, not a match. SS125 (new): before ledgering any jr residue, run jtbl_carve with NO body spliced and rebuild. Byte-identical => the carve is neutral and the failure is the template; NOT identical => the failure is the carve and the body was never fairly tested. One build, and it collapses ambiguity that SS53 warns has twice steered strategy. MEASURED: group B func_8017BEBC had gate-failed 3 probes in a row (default AND --raw, cross-address ov_SC02_015 AND same-address ov_SC04_004). Carve-only on ov_SC04_004 broke the bytes with nothing spliced — so all 3 probes were testing a body that never got a fair run. The SAME stage had already refused behemoth func_80191C50/ov_SC06_018. Two "unrelated walls" = ONE tooling problem. func_8018057C/ov_SC01_009 fails at a DIFFERENT stage (jr_isolate_all, step 1) and is deliberately NOT grouped with them. Both tools reported SUCCESS on every failing target; only the whole-binary gate refused (G3/P9). A tool's exit code is not the oracle. Ledger: the three logged by STAGE (JTBL-CARVE-BREAKS-BYTES / JR-ISOLATE-BREAKS- BYTES), not by function, so a carve fix auto-reopens every target it should. None is diagnosed, so none is called a compiler wall — that guess has been wrong four times running on this project (R35). CURRENT_PHASE: SESSION-28 checkpoint refreshed; the carve diagnosis is now resume item 1 (it gates 13 members + a 710-ins behemoth and every future jr family). |
||
|
|
a293eeeb6a |
docs(phase-30): SESSION-28 checkpoint + cookbook §124/§124a (the asm-label alias blind spot)
- §124: a "not matched" verdict can mean the definition is there under a DIFFERENT C NAME (the §37/§73 asm-label alias). The whole "no matched unit" skip class was one exemplar x 137 members. Includes the two traps in the fix (re-derive the pattern PER FILE; CARRY the alias declaration or the sibling emits the wrong symbol and still links) and the law: when corpus.stubs and a source scanner disagree, the SCANNER is wrong. - §124a: `0 matched-exemplar families` from family_sweep may be the --band FILTER (defaults to `substantial`), not a wall — same shape as §53 / §116. - cookbook-index regenerated (tools/cookbook_index.py, R33). - CURRENT_PHASE: SESSION-28 checkpoint. Fleet 92.70 fn-count / 88.3 instr / 78.7 distinct, R22 140/140. Records the 4th -O0 region VERIFIED + SIZED (30 instances / 1,504 ins, ov_SC03_014+015 only) and correctly BLOCKED on the T2 re-carve, and two R14 corrections to my own SESSION-27 checkpoint (the 137 were skips not failures; the cause was not "banked in the wrong binary"). |
||
|
|
0130fb340a |
feat(phase-30): wave-4 resumed 10/10 MATCH banked + h_exact leg (14 propagated); R22 140/140
The 12 agents killed by the usage-limit pause were resumed and ALL returned MATCH (2 had already banked from their partial drafts, so 10 ran). h_exact propagation leg completed over all 112 banked exemplars: 14 propagated, 42 benign skips (h_seq tier, correctly routed away per §123), 0 failures — the 0x801466F0 'halt' was a third benign-refusal phrase, not a partial write. fn-count 92.61 -> 92.67% | instr 88.2 -> 88.3% | distinct 70,581 -> 70,590 unique fns. |
||
|
|
d79d8f2356 |
feat(phase-30): cookbook-index — 9 curated symptom lines from wave-4 agent feedback (10/10 MATCH, 9/10 index hits)
Every line is a symptom an agent HIT and had to re-derive from gcc internals because title-keyword search structurally cannot surface it: - SIZE-MISMATCH/short + frame-pointer prologue => the target is -O0, pass --o0 (the flag was documented nowhere an agent would look; a 4th -O0 region also exists beyond the 3 known ones) - rotated instruction window => sched1 order; brute-force all N! statement orders (24 runs, 2 min) - if/else result in $v1 vs target's $v0, and load-hoisted-above-store => §76 variable reuse (§76's title reads behemoth-only, so nobody finds it for a 48-ins function) - ori 0xffd8 vs addiu -0x28 => negative const in an UNSIGNED narrow local; signed keeps the lhu - LENGTH-DRIFT -1 as a missing jal-delay copy => narrow ANSI prototyped param (not just K&R §43) - lwl/lwr+swl/swr is a delay-slot SPONGE (the inverse of the §5a fence case) - a vanished param copy => cse.c make_regs_eqv live-range rule - a ghidra_c seed may be a DIFFERENT function (overlays share VAs) |
||
|
|
29cd4d4c39 |
feat(phase-30): T3 wave-4 — 60/68 drafts banked across 14 binaries (parallel gate); R22 140/140
Wave 4 launched 70 agents / 14 binaries; 58 returned before the pause (all match_one MATCH) and their drafts + 10 partials gated to 60 banks. fn-count 92.59 -> 92.61%, distinct 70,506 -> 70,581. R22 clean-fleet 140 passed / 0 failed under the campaign lock. Propagation deliberately deferred (--no-propagate) — it runs per-function, routed by tier (§123). |
||
|
|
471314da54 |
feat(phase-30): T3 waves 2+3 + 4 behemoths — 52 cores banked, 911 members propagated; R22 140/140
WAVE 3 (48 agents / 8 binaries, dealt across binaries so BANKING fans out): 48/48 match_one MATCH, 48/48 banked through 8 PARALLEL per-binary gates. WAVE 2: 15/19. BEHEMOTHS: 4 non-jr confirmed (func_8017E120 884ins x14, func_8017FA5C 728, func_8017CAD4 755, func_8017E35C 719). Tier-routed propagation (§123): family_sweep --hseq banked 911 members across 137 overlays. fn-count 92.32 -> 92.59% | instr 87.9 -> 88.2% | distinct 78.3 -> 78.7% (70,506 unique fns) R22 clean-fleet 140 passed / 0 failed, under one campaign lock (treelock.sh). CORRECTION (R14): the 'per-binary bank-rate cliff' I reported from the pre-incident gate run (SC03_014 1/6, SC04_018 1/6, SC06_018 2/6) was an ARTIFACT — those gates ran against a tree propagation was concurrently rewriting. Re-gated clean: 6/6 everywhere. A measurement taken during corruption is not a measurement; I should not have theorised a cause before re-running it. |
||
|
|
f3ec6ef588 |
fix(phase-30): treelock.sh — an flock MUTEX for tree-writing campaigns (incident 2: a poll is not a mutex)
I gated 8 binaries in parallel while wave-2's propagation loop was still running, then ran 'make clean' on top. check-all 77/140; the corpus denominator moved, so the apparent 91.4% instr was a half-written tree, not a gain. Reverted to commit:1245 (last R22-verified) — 140/140 restored, all 58 drafts survived because agents only ever write .run/. ROOT CAUSE, and it was structural not unlucky: my guard was while pgrep -f dedup_propagate; do sleep; done A CAMPAIGN is a LOOP of short-lived processes (15 sequential invocations), so it has gaps where no process matches. The poll sampled a gap and started. Presence-of-a-process cannot express 'a campaign owns the tree'. treelock.sh holds one flock for the WHOLE campaign, released by the kernel on exit OR kill, with --status; both drivers refuse to run unlocked. LAW: guard the CAMPAIGN, not the process. Corollary (twice today): a killed process performs no undo — a fleet-tier write needs a lock ABOVE it, not cleanup inside it. |
||
|
|
c14f15a09f |
fix(phase-30): cookbook-index — 226 -> 324 sections (the unnumbered idiom headers) + curated symptom hints from wave-2 agent feedback
WAVE-2 MEASURED THE INDEX: 15/19 index hits and the bank rate went 57% (wave 1, no index) -> 79% (wave 2, index-first) on the same gate. Agents also NAMED its gaps, which is the flywheel working. Two real defects found and fixed: 1. COVERAGE. The parser required a '§' prefix, so 111 h2-h4 headers were invisible — including '### T4 — Branch polarity', the fix match_one names by class (BRANCH-POLARITY) and which two agents re-derived by hand, and the §1/§2 idiom-catalog entries (I1-I4, T1-T4). 2. THE ASSERTION ITSELF. My R32 check compared §-headers-parsed against §-header-CANDIDATES — a tautology over a set I had already narrowed. R32 says the candidate set must OVER-approximate; it now counts EVERY header and accounts for each as indexed-or-explicitly-skipped. The tool written to stop silent skips had the silent-skip defect. 3. Keyword matching over titles cannot surface an idiom whose title omits the symptom, so the index now opens with a hand-curated SYMPTOM -> section list, seeded from what agents actually hit (branch polarity, (void)-canon conflicting types, asm-label alias, one-base-register reuse, folded andi, slti/sltiu, sibling-first, delay-slot theft, void->s32). |
||
|
|
4570a5854b |
feat(phase-30): cookbook-index — a SYMPTOM-keyed index (226 sections, derived + coverage-asserted, in tools-health)
Wave-1 measured the tax: three agents each reported a 'NEW idiom' that was ALREADY documented — the asm-label alias (line ~2516, same 'address-of perturbs regalloc' mechanism) and the void->s32 non-neutrality (§41d, Phase 26; the agents cited the very entry §41d corrects). They consulted the cookbook as instructed and could not FIND them. 716 KB / 226 sections with no index = a discoverability failure, and every wave re-paying for prior waves' findings is the inverse of R16. docs/cookbook-index.md maps SYMPTOM (what you see in the diff) -> sections, 14 buckets, a section listed under every symptom it addresses. Derived by tools/cookbook_index.py (R33 — cannot drift), --check wired into tools-health. R32 on my own tool: the first regex required an em-dash separator and silently dropped 50 sections — including §1 (idiom catalog), §2, §5a (cross-jump, cited by an agent today). An index missing its most-cited entries turns 'I could not find it' into 'it is not there'. Now asserts extracted == candidate '§' headers and hard-exits on a gap. |
||
|
|
5d4167bb3c |
feat(phase-30): T3 wave-1 h_seq sweep — 548 members banked across 4 families; R22 140/140 (fn-count 92.16 -> 92.32%, distinct 78.0 -> 78.3%)
The 4 cores dedup_propagate refused (h_exact tier) templated cleanly via family_sweep --hseq once the family map was regenerated post-bank (a bank invalidates the map: sig-overlays + family_hseq must run BEFORE the sweep — the standing wave-loop order). 548/686 banked, 138 failed (one consistent per-overlay slice, diagnose next). Wave-1 total: 8 cores -> 1,121 instances. instr 87.5 -> 87.9%, distinct 69,828 -> 70,094 unique fns. |
||
|
|
159317d3fe |
feat(phase-30): T3 wave-1 — 8 cores banked + 4 propagated fleet-wide; R22 140/140 (fn-count 92.00 -> 92.16%)
Ultracode wave of 14 agents over fresh reach-138 cores: 14/14 match_one MATCH, 8 accepted by the whole-binary gate (the §52b law reproduced exactly). Propagated per-function (the incident fix): 0x8012E014, 0x80151C54, 0x8012F49C, 0x80151B98 -> +573 instances. R22 clean-fleet 140/140; instr 87.5 -> 87.7%, fn-count 92.00 -> 92.16%, distinct 69,828 -> 69,836. The other 4 banked cores are h_seq (PURE/IMM) families: dedup_propagate is h_exact-only, so its 'reach<2' / 'not self-contained' refusals were statements about the TOOL's tier, not the functions -> cookbook §123 (the §53 carve-law generalized to the propagation-tier axis) + a routing table. They bank via family_sweep --hseq next. |
||
|
|
fa1f6d0bf2 |
docs(phase-30): T1a close-out — +18 banked (+12 unique), R22 140/140, stored-draft question CLOSED (report point #2)
39% prior did not generalize (S16 measured FRESH wave drafts; this is A10's stored-backlog class, 0/958 by plain re-gate) — the driver lifted ~16% over that 0%. Residue routed to T3 redraft lanes. §61 orphan-carve residue reverted; two T3 pre-work gaps recorded (gate_stage commit add-scope for new carve files; no tracked writes during tree-writing campaigns). Ledger pruned: 1,350 -> 1,332. |
||
|
|
fe8095a24d |
feat(phase-30): T2 — rollout_o0.py (generalized o0b driver) + x1 probe verdict: append route REFUTED for the remaining cluster (R14 correction)
o0b-bearing != o0b-adjacent: T85's 0x801457A4 banked by append only because it abuts the o0b object's END; the 0x8013Bxxx-0x8013Cxxx families mis-place by construction (probe 1/1 gate-reject) and per-fn isolation IS the Arm-A re-carve. Frontier report corrected; T2 pivots to the Arm-A +0x20 defect itself (symbol-pin hypothesis first). Driver stands as the post-fix sweep harness. |
||
|
|
19766a6dc3 |
feat(phase-30): T0.5 — prefetch_fleet.py, the fleet Ghidra-C batch orchestrator (+ SETUP row, R21; fuel manifest ride-along)
One representative per remaining h_seq distinct class + all main/resident stubs -> .run/ghidra_c/. Resumable (skips cached); serial on the exclusive project lock; auto-stops a serving MCP (R23); imports missing overlay programs on demand via ghidra_import_raw.sh (blob derived via family_remap.img_path, vram from the splat yaml — R33, never guessed); R32 per-program outcome report, continues past failures. Dry-run: 126 programs / 7,966 uncached representatives. |
||
|
|
93d2851ab2 |
feat(phase-30): T0e2+T0f — autopsy refreshed (108 stranded MATCHes); frontier regenerated; the three populations PINNED (docs/frontier-p30.md)
- Autopsy 1,349 rows: 1,178 near / 63 nobuild / 108 match_one-MATCH (T1 fuel, 3x the S16 sample); 0 classifier errors; second-oracle agree. - THE -O0 PIN: 18 fam / 2,192 open members = 2,131 o0b-route-eligible + 61 SC07-only; 15/18 exemplar-matched. The 'WALLED ~1,287' framing dissolves — T2 generalizes rollout_801457a4_o0.py (proven 130/130); jr+o0 composites (0x8013c414, 0x8013c0f8) probe x1 first. - Zero-crack: 114 fam / 3,166 members / ~204k w-ins (28 substantial). Concentration top-20 24.0% / top-100 44.8%. Worklist fresh: 101 live / 261,789 gain-ins (stale 160/583k gone). - T0 COMPLETE (a-f) — report point #1 = docs/frontier-p30.md |
||
|
|
de7b347f6f |
feat(phase-30): T0c — the family_hseq/progress 'gap' was a cross-date+scope misread; digests now self-stamp (scope+HEAD+oracle)
Same-tree regen: family_hseq(overlays) 27,248 == progress 28,296-1,034(main)-14(resident) EXACT. The 07-29 map was SESSION-25's open snapshot; 29,961-27,248 = 2,713 = the session's banked total. Zero definitional gap — both tools already derive from corpus.stubs (Phase 26-A). family-hseq.md header now stamps 'OVERLAYS only' + generation HEAD + compare-at-same-HEAD. Roadmap D-bucket corrected. Fresh readings: 478 substantial fam / 678,404 templ ins / 28 zero-crack (S25 ate 33). |
||
|
|
b5a28edae8 |
feat(phase-30): T0a — gate_stage stage-0 raw gate + fix_arity_callers per-edit journal undo (§122)
- STAGE 0: gate the RAW drafts before any transform (GATE_NO_STAGE0 escape) — the carried 'ladder destroys good drafts' defect (SESSION-22 reproduction: _o0 pair + func_80138C60, ladder-FAILED/bare-VERIFIED) is impossible by construction; ladder+arity now touch only stage-0 failures. TU-blind-transform root-cause hypothesis recorded in-code, open. - fix_arity_callers --journal/--undo-journal --keep: exact per-edit undo in the WRITER, shared by ladder AND bare workflows (the 17-TU residue class); replaces the two-special-case file snapshot; undo moved after stage 2 (closes the stage-2 arity parity gap); stale-journal guard. Negative-control: apply->undo byte-identical; --keep exact. - Flow test .run/t0a_flowtest/driver.py 7/7 PASS. Cookbook §122. CURRENT_PHASE T0(a) logged. |
||
|
|
8c73950270 |
docs(phase-29): roadmap-to-100 v2 — the owed re-baseline; P30-P33 rechartered on 2026-07-30 measured reality
- §1 contract numbers corrected: 140 onboarded + 39 type-1 pending; metrics contract marked IMPLEMENTED (main in denominators since 07-22); main second-oracle gap named as P31 item - §2 rebuilt: 87.5/78.0/92.00 baseline; buckets W1-W5/M/R/T/B/D with dated sources; the measured lever order (recover -> fix -O0 instrument -> concentration head -> scope -> flag-plants) - §3 rechartered: P30 Recovery & Concentration -> P31 Scope-Complete + Main & Resident -> P32 Behemoths+Walls -> P33 Verify+Flip; honest scale estimates from measured velocity - §4 tooling: member_adapt + family-adapt fine-tune VACATED (dissolved premise); burn-down DERIVED not built (R33); new T0 defect fixes named; diff_regions BUILT - §7 records the v1->v2 supersession (v1 in git history at commit:1210) |
||
|
|
ceae8bb4cd |
feat(phase-29): T97 — func_80151944 138/138; the "three-edit job" was ONE edit
- The last big NAMED blocker, costed across four checkpoints as §112 header + §20 call-site cast + a scripted §99 pass over 2,022 overlay-local decls. Probing first showed two of the three were unnecessary: the conflict is entirely between DEFINE_func_80151924()'s own forward-decl (extern s32 func_80151944(void)) and the byte-true definition (void f(void *a0)), four lines apart in the assembled TU. The 2,022 decls live in OTHER TUs and never entered it. - ONE 4-line edit in engine_core.h: decl -> byte-true, call site -> ((s32 (*)(void))f)() so the caller's codegen is unchanged. rtu_match: conflicting types -> MATCH (15 ins). Sweep 138/138. - Family 0x80131eec fully closed: 149 (T87) + 138 (T97) + 1 immediate-refusal = all 288 members. - SHARED-HEADER RISK VERIFIED, NOT ARGUED: engine_core.h is included by all 138 overlays, so §20 cast-folding is a hypothesis. Per-binary gates 138/138 are necessary but not sufficient; the fleet check is the one that counts. R22 clean-fleet 140/140 + tools-health RC=0 (corpus 0 PHANTOM/0 TRUNCATED, cdecl, audit-binaries, dedup 1886/0, C1 239604/239604). - METRICS: fn-count 91.96 -> 92.00% (+138, exact) · instr 87.4 -> 87.5% (+2,070) · distinct +72. - COSTING LESSON: the estimate came from reading the symptom (2,022 decls of this name exist) instead of probing the failure (which decl actually conflicts). Probe before COSTING, not just before scaling. |
||
|
|
7e32da8f64 |
feat(phase-29): T95/T96 — func_80142B2C 136/136 (§121); all 3 byte-identical stragglers closed
- The draft calls ((void(*)(void))func_80142C84)() but nothing declares that symbol above the splice: it is DEFINED by DEFINE_func_80142C84() in engine_core.h, so gather_externs has no extern line to harvest, and the member TU instantiates the macro BELOW our function. - The wrong guess was the useful step: a no-prototype `extern s32 func_80142C84();` turned `undeclared` into `conflicting types` — a DIFFERENT error, proving the diagnosis right and the type wrong. Synthesised from the macro's own definition head -> MATCH (34 ins) -> 136/136. - NEW macro_def_sig_map() (1,878 signatures): the complement of header_sig_map(), which reads the externs a macro emits FOR ITS CALLEES; this reads the signature a macro DEFINES. Cookbook §121. - ALL THREE byte-identical stragglers carried since SESSION-24 are now closed: func_80146750 137/137 (T84), func_801759D8 137/137 (T93), func_80142B2C 136/136 (T95) = 410 members, and not one was a compiler wall (a signedness-wrong header decl, a type-name collision, a missing extern). - Blast radius 0 (74 further families re-swept). FOUR data points now: only §117 (wrong LOGIC) generalised at 1,209 members; §118/§120/§121 are path-reachability gaps worth ~one family each. - GATES: R22 clean-fleet 140/140; dedup 1886/0; 0 NON_MATCHING (G4). - METRICS: fn-count 91.88 -> 91.96% (+273, exact) · instr 87.3 -> 87.4% (+12,296) · distinct +0 (both byte-identical families — §111 predicted exactly that). |
||
|
|
9a1507462f |
feat(phase-29): T93/T94 — func_801759D8 137/137 via type-uniquify (§120) + two T92 corrections
- CORRECTION 1 (R14/P9): T92's "strip-if-ambient" recipe was WRONG. Stripping the draft's duplicate
typedef breaks the extern that USES it (the TU's own copy sits below the spliced function), so the
"second stacked blocker" T92 recorded (D_800AF634 used prior to declaration) was my own fix
misfiring, not a real blocker. RENAME, don't remove: rtu_match CC1 FAIL -> MATCH (56 ins).
- CORRECTION 2: T91's wiring never RAN. family_sweep has THREE staging sites sharing the identical
two lines (edit-remap / hseq / plain h_norm); I patched by rindex twice, which lands on the PLAIN
site, so --hseq staged the draft unchanged and the lever looked ineffective. Re-anchored on the
hseq site's unique write (func_{to_addr:08X}.c) and the draft came out renamed. T91's revert was
right discipline on a false premise.
- RESULT: _uniquify_draft_types wired into the hseq path (byte-neutral — C type names never reach
codegen). func_801759D8, one of the three long-standing byte-identical stragglers: 0 -> 137/137,
0 failed. Blast radius 0 (74 further families re-swept, none moved) => TARGETED lever, like §118
and unlike §117.
- Cookbook §120, incl. the law: before concluding a lever does not work, prove it RAN — diff the
staged artifact for the change it is supposed to make.
- GATES: R22 clean-fleet 140/140; dedup 1886/0; 0 NON_MATCHING (G4).
- METRICS: fn-count 91.88 -> 91.92% (+137, exact) · instr 87.3 -> 87.4% (+7,672) · distinct +0
(byte-identical family — §111 predicted exactly that).
|
||
|
|
f7c6d2eb2f |
feat(phase-29): T89/T90 — 0x80161c98 138/138 via the flag off-diagonal (§119) + a T84 correction
- CORRECTION (R14/P9): T84's '137 banked = all of 0x80161c98' is WRONG and committed wrong in commit:1193. The 137 were func_80146750 (a byte-identical straggler), banked 1-per-overlay in <ov>_after.c; 0x80161c98's members were still stubs. I assigned a count to the family I had been looking at without deriving it — third instance today of that error class. The --fix-def-sig-is-harmful finding itself stands (it unblocked func_80146750 x137). - THE REAL BLOCKER was a flag OFF-DIAGONAL, not a defect. 0x80161c98's byte truth is (int,u32) -> sltiu; engine_core.h says (s32,s32); and an in-TU decl disagrees with the def. The levers pull opposite ways: --fix-def-sig bends the DEFINITION to the header; --normalize-self-decls bends the DECLARATIONS to the definition. both-on -> slti DIFF (T79). both-off -> correct sltiu but 'conflicting types' (T84/T88). NSD-only -> 138/138 (T89). Three sweeps across three sessions tested only the diagonal of the 2x2. Cookbook §119. - T90 blast radius: 23 more (NSD-only) across the remaining still-zero families — targeted, not general; recorded so it is not over-projected. - GATES: R22 clean-fleet 140/140; dedup 1886/0; 0 NON_MATCHING (G4). - METRICS: fn-count 91.84 -> 91.88% (+161, exact) · distinct-code 69,593 -> 69,744 (+151). |
||
|
|
bf71232d0b |
feat(phase-29): T87/T88 — ordinal immediate resolution (§118): 158 banked
- The T86 asm-ambiguous refusal was CORRECT (a by-value swap would corrupt the non-differing occurrence); the safety TEST was too strict. It compared the C literal's occurrences against EVERY asm use of that value, but gcc synthesises uses no C token names — e.g. D_80187044[*(u16 *)((s32)a0 + 0x2)]() has one C literal 0x2 and TWO asm uses of 2 (the per-member offset + a fixed sll ..,2 for the 4-byte stride). Unsatisfiable by construction. - FIX (_ordinal_edits, §118): pair C occurrences to asm positions IN ORDER, accepting either len(spans)==len(asm_pos) (every use named) or len(spans)==len(diff_pos) (extras are implicit). Rewrite only occurrences whose instruction is in diff_idx. Order is a heuristic, so the whole-binary byte-gate stays the sole arbiter — a wrong pairing is rejected, never banked. - T87: func_801599A4 0 -> 137 drafts, 137 banked; +12 singletons = 149 (family 0x80131eec). - T88 blast radius: only 9 of the other 144 immediate-refusals converted (refusals 67 -> 34). A TARGETED lever, not a second §117 — recorded so it is not over-projected. - GATES: R22 clean-fleet 140/140; dedup 1886/0; 0 NON_MATCHING (G4). - METRICS: fn-count 91.79 -> 91.84% (+158, exact) · distinct-code 69,450 -> 69,593 (+143). |
||
|
|
dcbeebaf49 |
feat(phase-29): T84/T85 — 0x80161c98 137/138 + func_801457A4 133/133 (+270 members)
- T84 (item 1): the top still-zero family's whole diff was ONE instruction — slti (signed) vs the target's sltiu. --fix-def-sig was conforming a byte-correct draft to engine_core.h's signedness-wrong decl (extern void func_80161D20(s32,s32)) while the exemplar's own def is (int, u32). Re-swept the 92 still-zero families WITHOUT the flag: 137 banked (all of 0x80161c98), other 91 unmoved => family-specific, NOT a second §117. Recorded as such. - T85 (item 2): rewrote tools/rollout_801457a4_o0.py as the two-file ATOMIC driver §116 called for (remapped body -> <ov>_o0b.c AND drop the INCLUDE_ASM from <ov>_after.c in one edit; build vs config/check.<ov>.sha; restore BOTH files on mismatch, §61). Validated on 3, then 130/130. No splat change — the Arm-A re-carve wall never touched. - Item 4 PRICED AND DROPPED: STRUCT residue = 34 families / 166 members / 0.02pp. - R14: my new_distinct estimator over-projects ~2x (priced 259, measured 125) — it counts classes unmatched at run time, so concurrent sweeps double-count. Ranks correctly, overstates absolutely. - GATES: R22 clean-fleet 140/140; dedup 1886/0; 0 NON_MATCHING (G4). - METRICS: fn-count 91.72 -> 91.79% (+270, exact) · instr 87.2 -> 87.3% (+16,946) · distinct-code 69,325 -> 69,450 (+125). |
||
|
|
9d0ce20015 |
feat(phase-29): T83 — the §117 blast radius: 821 members, 138 families zero -> complete
- Re-swept the 229 eligible non-jr families (2,575 candidate members) that had never seen a correct target spelling. 821 banked / 1,538 failed; 138 families went zero -> COMPLETE (732 members), 14 partial, 92 still zero. Top: 0x80172780 +135, 0x80128158 +31, 0x80187318 +28, 0x8016f540 +27, 0x8017bef8 +20. - Every one of those 138 families had been swept before and booked as a failure. None was a compiler problem — all were downstream of the one positional-map defect fixed in T82. - GATES: R22 clean-fleet 140/140; dedup 1886/0; 0 NON_MATCHING (G4). - METRICS: fn-count 91.48 -> 91.72% (+821, exact) · instr 86.9 -> 87.2% (+33,670) · distinct-code 69,024 -> 69,325 unique fns (+301). - The 92 still-zero families are the honest residue: swept with every lever this phase built (§114 callee, §115 named-symbol, §117 symbol-kind, def-sig, self-decl normalization), so no known harness defect applies to them. Correct starting population for the next diagnosis round. |
||
|
|
28dc3785f5 |
feat(phase-29): T82 — symbol-KIND fix in symbol_map: func_80174784 2/255 -> 251/251 (§117)
- CAUSE: family_remap.symbol_map zips exemplar/sibling reloc slots positionally and spelled the SIBLING's symbol from the EXEMPLAR's kind. Same-address families always agree, so it was invisible for 20+ phases; cross-address families need not agree — func_80174784's callback slot is the FUNCTION func_801747CC while member func_8017CFD4's same slot is the DATA symbol D_80182688. The map emitted func_80182688, the body materialized a name for an address that is not a function, and the fleet gate refused all 251 members. - FIX: spell the target by what the target address IS in the SIBLING's overlay (func_ iff in that overlay's sig set — the same boundary oracle nins_of trusts, R33; memoized). Phase 26-A had already established this rule and applied it only to the exemplar side. - WHY IT HID: rtu_match/match_one MASK HI16/LO16, so a wrong %hi/%lo symbol still reports a clean MATCH (measured: "MATCH (10 ins)" on a member the fleet gate rejected). masked-MATCH + whole-binary DIFF is the exact signature of a compiler wall. Cookbook §117 carries the law. - Also refuted en route (cheaply): --normalize-self-decls was NOT the cause — re-swept without it, still 0/251. - GATES: R22 clean-fleet 140/140; dedup 1886/0; 0 NON_MATCHING (G4). - METRICS: fn-count 91.41 -> 91.48% (+251, exact) · distinct-code 68,782 -> 69,024 unique fns (+242, projected 246) · instr +2,510. - BLAST RADIUS UNMEASURED: symbol_map serves every family sweep; 229 eligible non-jr families / 2,575 members have never been swept with a correct target spelling, incl. the byte-identical families T76 measured at 0/682 (same failure shape). |
||
|
|
90a644fb80 |
docs(phase-29): T80/T81 — two 0/N diagnoses + the SESSION-25 checkpoint
- T80: the §116 rollout prescription was WRONG and the build refuted it in 56s across 133 overlays. "Byte-neutral by construction" was a claim about the LINKER; splat keys asm/ generation to the SEGMENT, so deleting func_801457A4's INCLUDE_ASM from <ov>_after.c stops func_801457A4.s being emitted and <ov>_o0b.c cannot assemble. Reverted, nothing committed. Cookbook §116 corrected IN PLACE with the refutation + the corollary (build it before you call it neutral). Real route: a two-file atomic driver (body -> _o0b.c AND drop the stub from _after.c in one edit). 129 distinct still on the table, now costed. tools/rollout_801457a4_o0.py kept as the inventory pass ONLY — do not --apply. - T81: 0x80131eec 0/288, and the two halves have DIFFERENT blockers — func_80151944 (138) staged and gate-failed on the T71 decl conflict; func_801599A4 (137) + 13 singletons were REFUSED AT REMAP for unresolved immediates and never reached a compiler. My prediction that the correct-decl half would bank was the T76 error shape (reason from one property, ignore the disqualifying diff_class: IMM) — recorded, not buried. CORRECTION IT BUYS: T71's "the immediate engine is not the bottleneck" holds for T70's families and is FALSE here (150 of 288). T2a immediate resolution is now a named, sized lever. - Refuted from source before spending a probe: the reloc tracker DOES see a function address materialized as an argument (LO_OPS includes addiu), so 0x80174784's 2/255 is not that. - SESSION-25 checkpoint: fleet 86.9% instr / 77.4% distinct / 91.41% fn-count; 641 banked this session; ranked next-list with all six items measured. Nothing running, tree clean. |
||
|
|
774592c452 |
feat(phase-29): T79 — byte-VARIANT re-sweep: 641 banked; T70's "1 of 10" was a pre-lever measurement
- VALIDATED FIRST, then batched: 0x80143d28 (T66's #1, T76's ApplyMatrixSV callee diagnosis) banked 136/136 under the §114 callee axis + §115 named-symbol widening. Batch of 8 followed: 505/1039. Totals: 5 families outright + 1 partial of 9; 641 members ×N. - Attribution DERIVED (R33), not parsed from the sweep log: live stubs recomputed per family from corpus.stubs before/after. Reconciles exactly against the metric (fn-count +641). - §116 (NEW): optimization level is a property of the FILE, not the function. 0x801457a4 swept 0/137 because its exemplar lives in ov_SC01_077_o0b.c (-O0 via WHALE_O0B_OBJS) while all 137 members' stubs live in <ov>_after.c (-O2). The fix moves the STUB line, not the def: <ov>_o0b's .text ends exactly at 0x801457A4, so the relocation is byte-neutral by construction and needs no splat re-carve (which is the Arm-A +0x20 wall). 13th time a family-wide 0/N was the harness. - R14 CORRECTION to the handoff arithmetic: the tier is 123 families / 3,100 distinct on fresh sigs, but 1,287 of that distinct is the -O0 cluster behind the Arm-A splat wall. Honest addressable tier = 113 families / 85,360 ins / 1,813 distinct. Billing the walled 1,287 as sweep yield would have repeated the T76 error. - 0x80131eec (214 distinct, the biggest item left) diagnosed precisely: header macro decl + §20 call-site cast + a scripted §99 pass over 2,022 overlay-local decls; param is void*, so the T75 narrow-param refusal does not apply. - GATES: R22 clean-fleet 140/140 from make clean + extract-all + check-all; tools-health RC=0 (corpus 0 PHANTOM/0 TRUNCATED, cdecl, audit-binaries, dedup 1886/0, C1 239604/239604); report RC=0; 0 NON_MATCHING (G4). - METRICS: instr 86.7 -> 86.9% (+28,205 ins) · distinct-code 76.9 -> 77.4% (68,196 -> 68,782 unique fns) · fn-count 91.23 -> 91.41% (+641). The distinct-code move is the point of this tier. |
||
|
|
611622c9e7 |
feat(phase-29): T78 — PsyQ-symbol widening: func_8012F40C 0/137 -> 137/137 (three places, not one)
I called this "a one-line predicate widening". It was THREE, and fixing the first two changed nothing
— the sweep still reported 0/547 (cookbook §115):
1. canonical_map : re.fullmatch(r'func_[0-9A-Fa-f]{8}') + keyed by parsed ADDRESS
2. DECL_LINE_RE : (func_[0-9A-Fa-f]+) as the name group
3. split_sig_string : \bfunc_[0-9A-Fa-f]+\s*\(
Each is a SILENT SKIP indistinguishable from "no conflict found". With 1+2 done the symbol reached 3
and died there; only tracing transform's internals (`callees cast: 0` while the canonical map plainly
held `s32 RotTransPers(s32, s32, s32*, s32*)`) located it. THE TRAP WORTH REMEMBERING: a partial fix
to a name-form assumption produces the exact symptom of no fix at all, so a correct hypothesis looks
refuted. Curated naming increases as RE quality improves, so any func_-only predicate is
rot-by-design — the same shape as stub_map's (Phase 26-A).
RESULT: func_8012F40C 0/137 -> 137/137. The other three families (801759D8, 80146750, 80142B2C) still
fail on different causes.
GATES: R22 clean-fleet 140 passed, 0 failed of 140; tools-health OK; dedup 1886/0; 0 NON_MATCHING.
METRICS: instr 86.7% (+4,932 ins); fn-count 91.19% -> 91.23% (+137); distinct +0 (byte-identical).
NEXT: the byte-VARIANT tier is worth re-sweeping — T70 banked 1/10 BEFORE the callee axis existed, and
26 families remain unswept by the two levers added since.
|
||
|
|
970559423d |
feat(phase-29): T77 — wire the callee-decl lever into family_sweep; func_80173A60 0/135 -> 135/135
Item 1. The T76 diagnosis was right and the fix was a lever we already owned. cast_call_sites
(§17a-1/§20) handles the callee-conflict class and lived ONLY in gate_stage, which the family sweep
deliberately does not use — the THIRD instance this session of a lever unreachable from the path that
needs it (T56 data-decl unreachable, T57 function-decl off-by-default, now T77 callee).
the 5 byte-identical families : 0/682 -> 135/682
func_80173A60 specifically : 0/135 -> 135/135
Wired after scope_data_fix (orthogonal axes: data vs callee), default ON with --no-cast-callees. Two
details that matter: the canonical map is built from the TARGET sibling's TU via cpp
(canonical_map(ov, src_file=tu) -> cdecl.tu_scope) so it sees MACRO-INJECTED declarations — a
raw-text scan returns nothing for exactly the callees that conflict (§51g LAW 7) — and it is read
AFTER any tu-scope edit is on disk.
THE OTHER FOUR STILL FAIL, different causes. And the next finding is already visible:
func_8012F40C's blocker is RotTransPers, a PsyQ LIBRARY symbol — a callee conflict the cast should
have handled. It did not, because cast_call_sites' canonical map keys on
re.fullmatch(r'func_[0-9A-Fa-f]{8}'), so NAMED PsyQ callees are structurally invisible to it. That is
a one-line predicate widening with ~270 members behind it (RotTransPers + ApplyMatrixSV families).
GATES: R22 clean-fleet 140 passed, 0 failed of 140; tools-health OK; dedup 1886/0; 0 NON_MATCHING.
METRICS: instr 86.6% -> 86.7% (+7,965 ins); fn-count 91.15% -> 91.19% (+135); distinct +0
(byte-identical — §111 predicted it).
cookbook §114 — the three decl axes, and "conflicting types for X: READ X".
|
||
|
|
ed95cad428 |
feat(phase-29): T72 — ARITY probe banks 137/137; most of the class was never an arity problem (§113)
Probe target switched from func_8013BD34 on measured evidence (its def is in ov_SC07_010_o0.c and
_o0 families sweep ~1/137 — a poor test of an unproven technique). func_80144B14: same class, 137
stubs, not -O0, real 34x137 family, tests both axes (void(void) -> int(int)).
THE PROBE FOUND THE PRECONDITION OVER-FIRING. The ARITY blocker exists because the macro's own CALL
SITE passes the header's arity. But DEFINE_func_* does not call func_80144B14 — it takes its ADDRESS:
*(s32 *)((s32)a0 + 0xDC) = (s32)&func_80144B14;
No call site => no arity constraint => the FULL correction is available, not the §99 no-prototype
workaround. Applied `extern int func_80144B14(int param_1);`.
RESULT: header change ALONE -> R22 clean-fleet 140 passed, 0 failed of 140 (byte-neutral); family
sweep -> 137/137, 0 failed.
METRICS: instr 86.6% (+4,658 ins); fn-count 91.12% -> 91.15% (+137); distinct-code +0 (byte-identical
family — §111 predicted it).
THE REFINEMENT (cookbook §113): the precondition must ask what the macro DOES with the symbol — a
call constrains arity, an address-taken or unused decl does not. Blocking on "both names appear"
over-fires, and it had 137 members behind it. The remaining ARITY findings should each be re-checked
for call-vs-address before assuming §99 is needed.
GATES: R22 140/140 twice; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
|
||
|
|
283937ed8e |
feat(phase-29): T70 — byte-variant families sweep 1 of 10 (138 banked, +130 distinct)
Item 5, first batch. Swept 10 byte-VARIANT non-jr non-O0 families (42,235 ins / 1,552 distinct projected): 138 BANKED / 1,346 failed — ONE family of ten (func_801627E8 137/137), plus 152 members skipped as "unresolved immediates (T2a)". THE FINDING: that is a ~10x worse rate than the byte-IDENTICAL families, which banked 137/137 apiece all session. It follows from what §111 established — a byte-variant member differs in more than relocations, so the template must adapt immediates too, and family_remap's T2a engine refuses what it cannot resolve. The distinct-code lever is real but it is NOT the same cheap sweep, and the projected "2,962 distinct across 36 families" should be discounted until the immediate-resolution rate is measured. That measurement is now item 1 of the next list, ahead of sweeping the other 26. §111 PASSED A SECOND PREDICTIVE TEST: projected +129 distinct for func_801627E8; observed +130 (the extra from an unrelated 2-member bank). GATES: R22 clean-fleet 140 passed, 0 failed of 140; tools-health OK; 0 NON_MATCHING (G4). METRICS: instr 86.5% -> 86.6% (+2,618 ins); fn-count 91.08% -> 91.12% (+138); distinct-code 68,066 -> 68,196 = +130 — the first real distinct-code movement of the session. |
||
|
|
a6e5abfd39 |
fix(phase-29): T69 — audit preconditions computed, not discovered; validated against known outcomes
Item 1. audit_header_sigs.py now COMPUTES the safe subset instead of leaving it to a failed gate,
and the two new preconditions took two wrong models to get right (cookbook §112).
PRECONDITION 1 — ARITY: correcting a `(void)` header decl for a 1-param definition breaks the macro's
OWN call site ("too few arguments"). Measured before the batch.
PRECONDITION 2 — VISIBLE COLLISION, and the two wrong models on the way:
(a) "any disagreeing decl in src/ blocks it" — compares type SPELLINGS, so s32-vs-int and
u32-vs-unsigned-int count as disagreements. Fixed by comparing type IDENTITY via
cdecl.compatible. Finding count 61 -> 32 once that noise is gone.
(b) "any INCOMPATIBLE decl in src/ blocks it" — STILL WRONG. It blocked ALL SIX corrections that
had just gated 140/140 and banked 685 members. func_80161774 has 1,063 TUs carrying the old
spelling and correcting it was byte-clean.
The right model: a macro-body decl is only visible where the MACRO IS INSTANTIATED, so a collision
needs a TU that BOTH instantiates the macro AND carries an incompatible decl. Measure the
INTERSECTION, not the population (macro_owners() + per-TU macro-use set).
VALIDATED AGAINST KNOWN OUTCOMES (the control this needed): the six that gated clean -> 0 colliding
TUs each; the one that failed the gate (func_80147364) -> 272. Perfect discrimination.
HONEST RESULT: 32 findings, 13 SAFE — but the safe subset is worth only 15 stubbed binaries. The
high-value targets (func_80147364 at 137, the arity trio at ~410) are all BLOCKED and need
conform_decls or §99 first. The cheap header lever is spent.
No src/ or config/ change: no bank, no metric move.
|
||
|
|
f59ae302b8 |
feat(phase-29): T68 — 6 header corrections sweep 685 members (+33,565 ins); fleet 86.5% instr
The audit was the right precondition: THREE of the six corrected functions were families already queued for the item-3 sweep, and each would have failed 0/137 exactly the way five families did earlier today. SWEEP: 6 corrected functions, all non-jr families with 137 live stubs -> 685 BANKED / 137 failed. Five families landed 137/137; func_80146750 failed on its own residual (undiagnosed). GATES: R22 clean-fleet 140 passed, 0 failed of 140 — after the header batch alone AND after the banks; tools-health OK (corpus 0 PHANTOM + 0 TRUNCATED, cdecl, audit-binaries, dedup 1886/0); 0 NON_MATCHING (G4). METRICS: instr 86.3% -> 86.5% (11338739 -> 11372304 = +33,565 ins); fn-count 90.88% -> 91.08% (321472 -> 322157 = +685); distinct-code 76.9% -> 76.9% (+0). §111 GOT ITS FIRST PREDICTIVE TEST AND PASSED: all six families have a single h_exact class, so the model predicted +0 distinct BEFORE the sweep ran, and +0 is what happened. The metric is modelled, not mysterious. |
||
|
|
a6f6ccf545 |
docs(phase-29): T66 — item 4: the distinct-code anomaly modelled and closed (it was never a bug)
Seven sweeps moved distinct-code by +125/+125/+129 and +0 four times; I had logged it four times as
"unexplained, still not guessed at". Modelled in one pass:
delta_distinct = (distinct h_exact classes in the family) - (classes already matched)
weighted_metrics counts distinct h_exact classes with >=1 matched instance. EXACT on all 7, no
residual: func_80135260 131-6=125; func_80133AB0 131-6=125; func_80156044 130-1=129; the four +0
families have EXACTLY 1 class across all 138 overlays (every member byte-identical), already matched
via the exemplar.
IT IS A REAL SIGNAL, NOT NOISE. A byte-IDENTICAL family is ONE piece of distinct code — the
exemplar's crack already reconstructed it, so the other 137 banks pay fleet/instr in full (each
binary now builds from source instead of pasted asm) but add NO new reverse-engineering. A
byte-VARIANT family is ~130 genuinely different functions and pays both. The two headline metrics
rank the same work differently, and both are now predictable BEFORE spending a sweep.
THE REMAINING FRONTIER, PRICED BOTH WAYS (49 eligible non-jr families):
byte-identical 13 families 80,085 ins 0 distinct
byte-variant 36 families 114,331 ins 2,962 distinct
total 49 194,416 ins (~1.48 pp instr)
MY OWN BUG, CAUGHT BY VERIFYING (R14): my first ranking reported ALL 49 families as byte-identical /
0 distinct yield. Defect in my probe — I wrote int(x,16) on the member address in one comprehension
and forgot it in the next, so every sig lookup missed and every family collapsed to one class. Caught
only by spot-checking two entries against a direct count (func_80143D28 is 130 classes, not 1). Had I
reported it, the conclusion "the entire remaining harvest is worthless for distinct-code" would have
been exactly backwards for 36 of 49 families.
cookbook §111, with §106 applied: the ranking is two lines over the sigs, so it is derivable on
demand and deliberately NOT committed as a table that rots.
No src/ or config/ change: no bank, no metric move.
|
||
|
|
ec34c31b68 |
feat(phase-29): T65 — extract_unit definition-detection fixed; func_80156044 137/137 (+10,138 ins)
Item 3, and it banked the third family. extract_unit located a definition with "the line matches
<type> func_<addr>( and does not end in `;`" — wrong whenever ONE LINE holds both a declaration and a
definition, which the handwritten inline-asm wrappers do:
extern void func_80156044(int, int); int func_80155FF8(int, int) { __asm__ … }
The line does not end in `;`, so func_80156044 — appearing there only in the DECLARATION — was taken
as a definition head. extract_unit lifted the neighbouring WRAPPER instead of the real definition
seven lines below; every sibling already defines that wrapper via its shared DEFINE_ macro, so all
137 failed with `redefinition of func_80155FF8` and it read as a compiler wall.
FIX: ask what follows the PARAMETER LIST, not what ends the line (`_def_head_at`) — `;` is a
declaration, `{` or end-of-line is a definition. Plus the R32 assertion: a unit that defines a
function other than its target cannot template, so refuse LOUDLY (`_foreign_defs`).
TWO TRAPS HIT WHILE WRITING THAT ASSERTION, both caught by regression-checking against families known
to bank: (1) _def_head_at ALONE over-fires — a call whose args wrap has nothing after the `(` on its
line, which "end of line => definition" reads as a definition; it refused THREE families that had
just banked 137/137. (2) The type-prefix test ALONE under-fires — it is what missed the wrapper
originally. The predicate needs both: split the prefix on its last `;`, require the remainder to look
like a return type, then check what follows the parameter list. All five known-banking families
extract byte-identically before and after.
RESULT: func_80156044 0/137 -> 137/137, 0 failed.
GATES: R22 clean-fleet 140 passed, 0 failed of 140; tools-health OK (corpus 0 PHANTOM + 0 TRUNCATED,
cdecl, audit-binaries, dedup 1886/0); 0 NON_MATCHING (G4).
METRICS: instr 86.2% -> 86.3% (11328601 -> 11338739 = +10,138 ins); fn-count 90.84% -> 90.88%
(321335 -> 321472 = +137); distinct-code 76.7% -> 76.9% (67937 -> 68066 = +129).
cookbook §110.
|
||
|
|
60f9ac40f3 |
feat(phase-29): T64 — func_8014D610 swept 137/137 after the header correction (+10,138 ins)
Item 2, and the same story as item 1: the header correction WAS the fix. With engine_core.h declaring the byte truth, the family swept 137/137 with zero failures — no draft change. before (header wrong) 0/137 `conflicting types` / a param-retyped body that could not compile after (header right) 137/137, 0 failed GATES: R22 clean-fleet 140 passed, 0 failed of 140; tools-health OK (corpus 0 PHANTOM + 0 TRUNCATED, cdecl, audit-binaries, dedup 1886/0); 0 NON_MATCHING (G4). METRICS: instr 86.1% -> 86.2% (11318463 -> 11328601 = +10,138 ins); fn-count 90.81% -> 90.84% (321198 -> 321335 = +137); distinct-code 76.7% -> 76.7% (+0 — a SIXTH data point for the anomaly). |
||
|
|
a850255572 |
feat(phase-29): T63 — func_8016163C swept 137/137 after the header correction (+10,686 ins)
Item 1. The header flip (commit:1163's sibling, committed just before) was the whole blocker: with engine_core.h declaring the byte truth, the family swept 137/137 with ZERO failures — no draft change, no new lever. before (header wrong) 0/137 `conflicting types` / a --fix-def-sig-truncated draft after (header right) 137/137, 0 failed GATES: R22 clean-fleet 140 passed, 0 failed of 140; tools-health OK (corpus 0 PHANTOM + 0 TRUNCATED, cdecl, audit-binaries, dedup 1886/0); 0 NON_MATCHING (G4). METRICS: instr 86.0% -> 86.1% (11307777 -> 11318463 = +10,686 ins, exactly 137 x 78); fn-count 90.77% -> 90.81% (321061 -> 321198 = +137); distinct-code 76.7% -> 76.7% (+0). The distinct-code anomaly now has FIVE data points (T52 +125, T57 +125, T56 +0, T58 +0, T63 +0) and still no identified variable. Unchanged as the queued probe. |
||
|
|
50a108b5a8 |
fix(phase-29): T60 — reconcile_def_sig name bug fixed (verdicts moved); 0 banked, three causes separated
Tool fix + a sharper diagnosis. NO BANKS — the three "header-conflict" families share a SYMPTOM, not
a cause.
THE FIX (cookbook §109): reconcile_def_sig now conforms the canonical TYPES and keeps the BODY's
parameter names, parsed with cdecl (base/params/pnames, R33 — not a regex). Two re-render traps
handled: `void*` + `a1` -> `void *a1` (cdecl glues stars to the type), and an EMPTY parameter list is
handed back verbatim because `(void)` and `()` both parse to params==[] and are DIFFERENT
declarations (§99 no-prototype). Unit-tested across 6 shapes incl. both void forms and an arity
mismatch; falls back to the wholesale canonical string for fn-ptr/array params.
THE FIX IS REAL, AND THE PROOF IS THAT THE VERDICTS MOVED:
func_8016163C `param_1 undeclared` -> DIFF (plumbing CLEARED; codegen left)
func_8014D610 `param_1 undeclared` -> `void value not ignored` (the HEADER is wrong)
func_80156044 unchanged -> `conflicting types for func_80155FF8` (WRONG LEVER — callee conflict)
TWO FINDINGS UNDER THAT:
1. The §85 return-axis precondition applies to reconcile_def_sig and NOTHING CHECKS IT. Conforming a
def's return to the canonical `void` is only safe when no caller consumes the return.
func_8014D610's callers do, so engine_core.h's `void` contradicts the byte truth and conforming
yields `void value not ignored`. The HEADER is the wrong artifact; correcting it is fleet-shared
blast radius (§61/§63), not a sweep-time fix.
2. func_80156044 was never the def-signature class — its conflict is on the CALLEE func_80155FF8
(decl 2 lines above the splice). That is cast_call_sites / canon_sig_reconcile territory.
HONEST ACCOUNTING: re-swept all three with the fix -> 0/411, tree clean throughout. The lever is now
correct (it no longer manufactures a false compile failure) but it was ONE of three causes, not the
cause. My T59 write-up grouped them as a single ~30,000-instruction block; that grouping was WRONG,
and what disproved it was re-reading each verdict after the fix rather than re-running the batch and
reporting the total.
No src/ or config/ change: no bank, no metric move.
|
||
|
|
28ef237c35 |
docs(phase-29): T59 — the five T58 zero families diagnosed: four causes, one wall
Deliverable is the diagnosis, not banks. Method: splice ONE member, `make -j1` the single object,
read the NON-warning cc1 lines (-j16 interleaves the real error away; the §58 memcpy / "type
mismatch" warnings dominate any naive tail; §93 pipefail names the wrong stage). Tree clean after
every probe.
CORRECTION TO MY OWN T58 REPORT (R14): I said "7 remaining families all have banked exemplars".
WRONG — there were 5. 0x80175820 (276 members) and 0x8016ec0c (138) have NO matched exemplar
anywhere: INCLUDE_ASM stubs in all 138 overlays. My batch-selection test picked the first TU
CONTAINING THE NAME (a declaration) and, seeing no stub in that file, called it banked. The family
map was right all along (kind='draft-ov077', matched_members=[]) and family_sweep correctly excluded
them ("6 matched-exemplar families" — a line I read past). Use corpus.stubs(ov), never a name-grep.
Their claimed 109,296 bytes were never real fuel.
THE FIVE VERDICTS:
0x8014d610 137 PLUMBING shared-header signature conflict
0x8016163c 137 PLUMBING shared-header signature conflict
0x80156044 137 PLUMBING shared-header signature conflict
0x80143d28 136 PLUMBING conflicting types for ApplyMatrixSV (a PsyQ library symbol)
0x801457a4 137 DIFF compiles clean, bytes differ — the ONLY genuine codegen wall
THE HEADER-CONFLICT CLASS (3 families / 411 members ~ 30,000 ins) + A THIRD OPT-IN LEVER. The
"previous declaration" line was the tell: for func_8014D610 it points at line 1727, which is NOT a
declaration — it is DEFINE_func_8014D438(), a shared-macro instantiation whose expansion
forward-declares the templated fn with the canonical engine_core.h signature. All four conflicting
fns are header-declared; the two non-header families are exactly the two with different verdicts.
--fix-def-sig is the lever (a THIRD opt-in one, after T56's unreachable and T57's off-by-default).
Tested: 0/411, and the verdict did NOT move to DIFF — it moved to a precise new compile error:
canonical : void func_8014D610(s32 a0, void *a1, void *a2)
draft body: ... param_1 ... -> `param_1' undeclared
reconcile_def_sig adopts the canonical signature WHOLESALE (types AND param names) while the body
keeps the exemplar's param_N names. Its docstring calls this a "rare name mismatch"; it is not rare —
an exemplar drafted with the param_N convention hits it every time. Fix: conform TYPES, keep BODY
names (both are in hand at the call site).
THE PATTERN, THREE TIMES IN ONE SESSION: T56 a lever unreachable from the sweep path, T57 a lever off
by default, T59 a lever subtly broken. Every family-wide 0/N so far has been a statement about the
HARNESS, not the code. cookbook §108 records the recipe + the four causes.
No src/ or config/ change: no bank, no metric move.
|
||
|
|
2d7694ba2d |
feat(phase-29): T58 — 8-family batch: 1 of 6 banked (func_8012A1BC 137/137, +10,686 ins)
Ran the batch with the T57 recipe (--band all --normalize-self-decls, live stubs derived from src/ not the stale map). 6 of 8 selected (two still filtered — selection line read this time). 821 candidate members across 6 families BANKED 137 — func_8012A1BC (78 ins) 137/137 failed 684 — the other FIVE families banked 0 each Attribution from git diff (137 x func_8012A1BC), not the per-group log lines whose split-name field my first aggregation mangled. THE SHAPE OF THE REMAINING FRONTIER — the finding. Across T56->T58 the per-family outcome is BINARY and near-total: a family banks ~137/137 or ~0/137, nothing in between. And each 0/N so far has had its OWN distinct cause — DATA decl scope (T56), FUNCTION decl scope (T57), jtbl table-count drift (func_8014032C), plus five more undiagnosed here. The mechanical lever is done pulling by itself: from here each family costs one diagnosis. A batch is now a DIAGNOSIS QUEUE, not a harvest, and the next phase of this work should be planned on that economics. GATES: R22 clean-fleet 140 passed, 0 failed of 140; tools-health OK (corpus 0 PHANTOM + 0 TRUNCATED, cdecl, audit-binaries, dedup 1886/0); 0 NON_MATCHING (G4). METRICS: instr 86.0% (11297091 -> 11307777 = +10,686 ins); fn-count 90.73% -> 90.77% (+137); distinct-code 76.7% -> 76.7% (+0). The distinct-code anomaly now has FOUR data points and still no explanation: T52 +125, T57 +125, T56 +0, T58 +0. All four families are PURE; the exemplar overlay does not separate them either (T56 and T57 both templated from ov_SC01_077 and disagree). Two behaviours, no identified variable. Still not guessed at — it stays the queued probe. |
||
|
|
cbc5665fd8 |
feat(phase-29): T57 — func_80133AB0 132/132 (+18,084 ins); a SECOND opt-in lever found; fleet 86.0% instr
First batch off the 64-family list. Fleet crosses 86.0% instr-weighted.
TWO OF MY OWN ERRORS, both caught by measuring:
1. Three of five targets never ran — --band defaults to `substantial` (nins>=80) and I picked three
at 79/78/78. The tool printed "2 matched-exemplar families" and I nearly read that as "5
attempted, 3 refused". Read the SELECTION line, not the intent.
2. Stale map: .run/family_hseq.json was regenerated in T55, BEFORE T56 banked func_80144090, so it
still listed 134 live stubs for a now-complete family. Membership is stable (h_seq over original
bytes); only the matched/unmatched split rots. Filter live stubs from src/, not from n_matched.
THE FIRST RUN WAS 0/268 — AND IT WAS A SECOND OPT-IN LEVER, NOT A WALL. Diagnosed one sibling past
the -j16 interleave and the §58 warning noise: `conflicting types for func_80133AB0` (spliced def at
2688 vs a decl at 2429) — the FUNCTION decl-conflict class, not the DATA one T56 fixed. That is
exactly what --normalize-self-decls exists for (the sibling's own caller declares the member in a
different C form than the exemplar's, which used a fn-ptr cast) — and it is OPT-IN, so it never ran.
Re-ran the identical two families with it: 0 -> 132 banked.
0x80133ab0 (137 ins, jr_8012ACE0) 132/132 BANKED
0x80143d28 (80 ins, jr_80140608) 0/136 — a different, undiagnosed blocker
THE PATTERN, TWICE IN A ROW: T56 the DATA decl lever was unreachable from the sweep path; T57 the
FUNCTION decl lever is reachable but OFF BY DEFAULT. Both present as a flat 0/N that reads exactly
like a compiler wall. A 0/N from a sweep is a statement about which levers were enabled, not about
the code.
GATES: R22 clean-fleet 140 passed, 0 failed of 140; tools-health OK (corpus 0 PHANTOM + 0 TRUNCATED,
cdecl, audit-binaries, dedup 1886/0); 0 NON_MATCHING (G4).
METRICS: instr 85.8% -> 86.0% (11279007 -> 11297091 = +18,084 ins); fn-count 90.69% -> 90.73% (+132);
distinct-code 76.4% -> 76.7% (67812 -> 67937 = +125).
SHARPENS the T56 anomaly rather than resolving it: 132 banked here moved distinct-code +125, and
T52's 132 also moved it +125 — but T56's 136 moved it +0. Three PURE families, two behave one way
and one the other. Still unexplained, still not guessed at.
|
||
|
|
56e2d808ab |
feat(phase-29): T56 — wire the tu-scope lever into family_sweep; func_80144090 0/136 -> 136/136
T55's two-part next step as one job. +20,944 instructions banked. 1. THE LEVER WAS UNREACHABLE FROM THE PATH MOST FAMILIES USE (cookbook §107) §103 was wired into jtbl_family_bank only (T53), and that tool runs for has_mid_jr families. Everything else sweeps through family_sweep, which gates via PLAIN harvest_verify by design — so the lever existed, was byte-proven, and most families could not reach it. The symptom was indistinguishable from a compiler wall: func_80144090 swept 0/136 with `conflicting types for D_800A651C`. Why it does not violate the plain-harvest_verify rule: that rule exists because gate_stage's transforms PERTURB A CORRECT DRAFT (§19/T3). The tu-scope never touches the draft — it moves a DECLARATION IN THE TARGET TU. The test is not "is it a transform" but "does it change the draft?" Reused the existing undo instead of inventing one: family_sweep already snapshots TUs it edits at staging time (--normalize-self-decls) and reverts on a final MISMATCH (not byte-neutral) AND on a zero-bank group (§61 undo law — no dead diff). The tu-scope shares that dict and inherits both backstops; renamed nsd_snapshots -> tu_snapshots. Default ON with --no-tu-scope to A/B it (the T24 --allow-pins precedent): byte-neutral by construction, a no-op when nothing collides, auto-reverted when it buys nothing. 2. THE DUPLICATE-DECL REFUSAL RELAXED — AND IT DID NOT MATTER scope_tu_externs refused N>1 file-scope decls as "ambiguous"; duplicate-IDENTICAL externs are legal C, so N identical decls are one decl written N times. Now compares whitespace-collapsed forms and refuses only on genuine disagreement. MEASURED, and my hypothesis was WRONG: D_800B9A02 is 3 decls in 2 DIFFERENT forms, so it was correctly refused all along — the family banked 136/136 without it. RESULT: func_80144090 0/136 -> 136/136, 0 failed, with NO change to any draft. GATES: R22 clean-fleet 140 passed, 0 failed of 140. tools-health OK (corpus 0 PHANTOM + 0 TRUNCATED, cdecl, audit-binaries, report/lint/dedup 1886/0). 0 NON_MATCHING (G4). METRICS (reconciled against make report): instr-weighted 85.7% -> 85.8% 11258063 -> 11279007 = +20,944 ins fn-count 90.65% -> 90.69% 320656 -> 320792 = +136 distinct-code 76.4% -> 76.4% +0 (67812 unique, UNCHANGED) FLAGGING the third row rather than explaining it away: 136 banked functions moved distinct-code by ZERO, where T52's 132 moved it by +125, and both families are classed PURE. I do not have a verified cause and will not invent one — either a real property of this family or a gap in the metric. Worth one probe before that number is quoted again. |
||
|
|
bcd44badc9 |
fix(phase-29): T55 — frontier re-mapped; 2 families swept, 0 banked, both blockers diagnosed to the line
Honest result: NO YIELD. What it produced is a re-measured frontier, a real fix to my own T53 work,
and both failures diagnosed rather than left as "0/N".
FRONTIER RE-MAPPED (T52's +132 moved it): family_hseq -> 2,647 target families, 513 substantial,
64 with a banked exemplar AND live stubs. Caveat recorded: the top two by byte-weight (0x8013c414
180KB, 0x8013c0f8 84KB) are -O0, and _o0 families are already measured at ~1/137 — do not be drawn
by their weight.
FAMILY 1 func_8014032C (183 ins x 136 ~ 25,000 ins): sample 0/8, last_err empty. Read one sibling's
real gate result (§53/§59) past the -j16 interleave and the §58 memcpy red herring — TWO causes:
(1) conflicting types for D_80115128 — the T48/T51 class, which tu-scoped should have caught;
(2) jtbl_rodata_pads "more rodata .align than pad specs — table-count drift vs the carve", a
DISTINCT class jtbl_family_bank's own comment documents as NOT isolate-fixable (§91 --like
role trap).
After fixing (1): still 0/8. Cause 2 is the live blocker — carve work, not decl work. NOT ground
further; it is a documented wall.
THE T53 DEFECT, FOUND AND FIXED: contested() scanned only the draft's BLOCK-scope externs, because
T51's motivating family had them hand-written in the body. But gather_externs carries decls in at
FILE scope, and those are exactly the ones scope_data_externs.fix DROPS when the TU already declares
the symbol — its give-up branch, the fatal case the lever exists for. Measured: scope_data_fix
dropped 3 symbols while contested() returned []. So the stage never fired on its own class. Now
scope-independent; regression-checked against T51's case using the pre-T51 TU from git (old ==
new, added []), and it now finds D_80115128 on the T55 target.
FAMILY 2 func_80144090 (154 ins x 136 ~ 21,000 ins), chosen because has_mid_jr=False avoids the
carve: 0/136. Diagnosed: conflicting types for D_800A651C (2210 vs 379) — the SAME class.
family_sweep gates via PLAIN harvest_verify by design, so it never sees the tu-scoped lever, which
lives only in jtbl_family_bank. Probed: the lever would move D_800A651C + D_800AF648 (deletion-only)
and REFUSES D_800B9A02 as "3 file-scope decls above (ambiguous)" — an over-conservative refusal,
since duplicate-IDENTICAL externs are legal C.
THE FINDING: the same decl-scope collision class gates the frontier's mechanical families — it cost
T52's family 133 of 137 siblings, and it blocks both families probed here. The lever exists and is
byte-proven; it is not reachable from the sweep path most families use.
No src/ or config/ change: no bank, no metric move. Tree verified clean after every probe.
|
||
|
|
f72e2344a6 |
fix(phase-29): T54 — correct the ADDRESSING route, and fix the reason changing it was inert
Item 1 off T53's list. Two changes: the route, and the design flaw underneath it.
THE DEFECT UNDER THE DEFECT (cookbook §106). residual_class answers two questions in one pass:
`klass` is a MEASUREMENT (expensive, from comparing instruction streams); `(profile, bucket)` is a
POLICY (a table lookup over it). autopsy persisted BOTH and verdicts() read BOTH back — so editing
_ROUTE changed nothing until someone re-ran the whole collect, and a weeks-old row could silently
out-vote the live table with no oracle to report it. The corpus on disk is dated Jul 21 and does not
even contain the SESSION-23 targets the recommendation cited.
Fixed by re-deriving at read time: residual_class.route_for(klass, detail), called from
autopsy.verdicts(). R33 — persist the measurement, derive the decision. Subtlety: LENGTH-DRIFT's
route is MAGNITUDE-dependent (permuter only when |delta|<=2 AND explains=="tail", §60b), so a naive
re-derivation from klass alone would have silently demoted 9 rows; both inputs are already in
`detail`, so the override reproduces exactly — VERIFIED 1610/1610 against the stored corpus with the
table UNCHANGED, before touching it.
THE ROUTE CHANGE: ADDRESSING ("cse","permuter") -> ("cse","structural"). It contradicted this file's
own bucket definition ("structural — local mutation CANNOT introduce it ... it wants a C-level
idiom"): the §10/§20 hoist-vs-remat shape is a multi-instruction change with a documented recipe
(gcc-2.7.2-map/cse_expr.md §2, byte-proven on func_80149374/func_801493D0). Measured (T31): both
admitted ADDRESSING targets plateaued under a §31-directed permuter, and the class was 32% of the
admission pool. After: pool 56 -> 38, exactly 18 rows changed, ALL ADDRESSING, nothing else moved;
grinder admits 45, structural skips 512 -> 530.
THE BOUND (R14), kept in the _ROUTE comment: I read the T31 record instead of the summary line, and
the summary was looser than the evidence. T31 finding 4 byte-tested the §2 recipe on func_80132F40
across six variants and it never closed (best 40 mismatches). `structural` does NOT promise a free
fix — it means "a search over local mutations is the wrong tool, try the documented idiom", exactly
what WIDTH / BRANCH-POLARITY / IMM-OFFSET already mean. Also corrected: the checkpoint cited
func_80176734 as the flat-for-32-min evidence, but that function is not in the corpus at all.
Tooling-only: no src/ or config/ change, no bank, no metric move.
|
||
|
|
f285de46e8 |
feat(phase-29): T53 — fold the T51 lever into the gate; kill gather_externs' false positive; close a revert gap
Items 1-2 off T52's list, plus a third defect found by T53's own testing. TOOLING ONLY — banks
nothing; metrics unchanged by design (85.7% instr / 76.4% distinct / 90.65% fn-count).
1. THE T51 PRE-PASS IS A jtbl_family_bank STAGE (cookbook §103, AUTOMATED)
Order: raw -> scoped -> tu-scoped -> recovered -> reconciled. After the non-invasive stages (it
edits the TU outside the spliced body); BEFORE the recovery stages deliberately — those bend the
DRAFT and T48 measured both at +3 ins for this class, so they cannot succeed here. The stage
re-runs scope_data_fix against the SCOPED TU rather than reusing the raw body: composition-correct,
since the contested symbols no longer have a file-scope decl to be dropped against.
COUNTERFACTUAL, byte-gated on a reproduced blocker (ov_SC01_000 restored to its pre-T51 TU):
raw -> compile error (conflicting types)
scoped -> compiles, FAILS the byte check (§8d drops the decl -> the u8 CSE costs +3)
tu-scoped -> BANKED
That is the evidence the stage does the work — not T52's sweep, which ran on TUs T51 had already
scoped by hand.
Refactor note: a stage editing outside the spliced body must RE-FIND the splice point (the stub
offset indexes the ORIGINAL TU). Each stage now carries its base; every pre-existing stage passes
`orig`, where the re-search returns the identical span — same operation as before, by construction.
2. gather_externs' COMMENT-SCANNING FALSE POSITIVE — FIXED (cookbook §104)
It scanned RAW text, so a symbol named only in the draft's PROSE counted as referenced: the
func_80135D20 warning that fired on 137/137 and was right 0 times. Fix is a two-text discipline —
MATCH on cdecl._mask'ed text, EMIT by span from the ORIGINAL (a masked decl is all blanks, so
"just mask it" would splice whitespace). Same change closes a second, unobserved defect of the
class: a COMMENTED-OUT extern could be selected as the carried decl and spliced in as live code.
MEASURED as a no-op on output (R14): 20 (exemplar, sibling) draft pairs across 4 families, old vs
new -> 20 identical / 0 differing. Only the false warning changed.
3. UNPLANNED — A REVERT THAT DID NOT SURVIVE AN EXCEPTION (cookbook §105)
A wrong exemplar made remap_hseq raise AFTER the carve rewrote config/ and jr_isolate created a
region file; the exception propagated out of bank(), the revert never ran, and the tree kept a
rewritten carve config plus an UNTRACKED region file (git checkout -- src/ does not remove it).
In a 132-member sweep that residue rides into the next member's build. bank() is now a
revert-guaranteed wrapper around _bank(). Negative-control proven: the crashing invocation now
reports {'exception': 2} and leaves git status -- config/ src/ at 0.
"Revert on failure" != "revert on every exit"; the exits are success, gate-fail, refusal, and the throw.
GATES: R22 clean-fleet 140 passed, 0 failed of 140. tools-health OK (corpus 0 PHANTOM + 0 TRUNCATED,
cdecl, audit-binaries, report/lint/dedup 1886/0). 0 NON_MATCHING (G4).
HONEST COVERAGE GAP: no live end-to-end BANK through the refactored loop — all three big families are
137/137 and the only family with live stubs (0x80191c50) has no banked exemplar, so it refuses. The
counterfactual byte-gated the exact splice on all three candidates and the 2-member run exercised
construction/refusal/revert/tally; the next real family sweep is the true end-to-end validation.
MY ERRORS: invoked the sweep with a wrong exemplar+address for a cross-address family (an unmeasured
guess about a members file I had not read — it is what surfaced defect 3); and deleted last_err's
initializer while refactoring, which would have raised NameError on the first clean gate-fail.
cookbook §103 (AUTOMATED) + §104 + §105; SETUP inventory row updated (R21).
|