mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
feat(phase-29 Task-13B): directed permuter wins first try; 3 latent gate defects fixed at root
First run of the Task-13A-targeted grinder (--once --batch 8 --permute-secs 90):
targeting: ON — 1665 classified; only bucket=permuter is admitted
targeting skipped 1601 non-permuter candidates
{redraft 707, structural 583, integration 305, unclassified 4, unknown 2}
permuter WON func_80181F78 @ ov_SC03_014 (close was 1) [~6 min]
BANKED 2 (both whole-binary byte-gated, R22 clean-fleet 140/140):
- func_80181F78 (8 ins) — classified DELAY-SLOT / schedule
- func_80141B90 (29 ins) — classified IMM-VALUE / cse
Both were classified bucket=permuter by residual_class BEFORE the run: the classifier
predicted a search-closer could reach them, and one did. First end-to-end validation of
the targeting thesis.
THREE latent defects, all pre-existing, all unreachable while the grinder banked nothing
since Phase 21 — the fix made it win and every one fired at once (cookbook §60a):
1. gate_stage commit path crashed on src=None. `src` is DELIBERATELY never defaulted
(Phase 26-A: a default silently PINS the gate to the main .c), but the commit did
`git add src …` unconditionally -> every caller that omits it (grinder, orchestrator,
idiom_hunt) crashes THE MOMENT IT BANKS. Now `git add -u src/`, which also retires the
`src/ov_*/*.c` filename glob that once omitted 4 R22-verified banks from a commit.
2. _xform ladder dirs (-cn/-cast/-rc/-uni) ACCUMULATE across runs: they held 34 stale
drafts, so the gate processed 34 when the grinder submitted 1, and banked one function
it was never asked to try — which would have been committed under a message naming a
different one. Nothing wrong entered the tree (G3/P9 held; the gate banks only
byte-identical output) but report and work had diverged. Now cleared per run.
3. grinder called gate_stage with the default propagate=True = `dedup_propagate
--auto-from`, the §55b fleet-wide path that timed out at 3600s and left 90/140 overlays
broken — and being INSIDE the gate it takes the banks down with it. Now propagate=False;
banks commit cheap, propagation is its own targeted --addr batch (§55b law).
R22: make clean && extract-all && check-all -> 140 passed, 0 failed of 140.
tools-health OK (dedup 1847/0, C1 234343/234343); 0 NON_MATCHING (G4).
This commit is contained in:
+1722
-1724
File diff suppressed because it is too large
Load Diff
@@ -4447,3 +4447,35 @@ process died with a traceback instead of a verdict: **14 of 1,752 drafts lost in
|
||||
— and every parallel wave has paid it invisibly, because a drafter that crashes on its self-check merely
|
||||
looks like a drafter that failed. Now per-PID. Same defect class, one level down, as the Phase-28
|
||||
`match_one --work` shared scratch whose docstring promised the isolation its default contradicted.
|
||||
|
||||
### §60a — What the first DIRECTED grinder run exposed (Phase 29 Task-13B, 2026-07-21)
|
||||
|
||||
Turning the targeting on and running the grinder bounded (`--once --batch 8 --permute-secs 90`) produced a win
|
||||
on the FIRST candidate — `func_80181F78`, close=1, classified `DELAY-SLOT`/schedule, banked in ~6 min — and
|
||||
then immediately surfaced three latent defects that had been unreachable **because the daemon had not banked
|
||||
anything since Phase 21**. All three are the same shape: a step whose REPORT and whose WORK had quietly
|
||||
diverged.
|
||||
|
||||
1. **`gate_stage`'s commit path crashed on `src=None`.** `src` is deliberately never defaulted (the Phase 26-A
|
||||
audit: a default would silently PIN the gate to the main `.c`), but the commit did `git add src …`
|
||||
unconditionally. So every caller that omits `src` — grinder, orchestrator, idiom_hunt — crashes
|
||||
**the moment it banks**. Fix: `git add -u src/` (every modified tracked file under src/), which also
|
||||
retires the `src/ov_*/*.c` filename glob that once omitted 4 R22-verified banks from a commit because a
|
||||
family's members do not all live in the same-named split.
|
||||
2. **The `_xform` ladder dirs accumulate.** `<drafts>-cn/-cast/-rc/-uni` are reused across runs and the
|
||||
transform tools only write the drafts they are handed, so every stale draft from every previous run
|
||||
survives and is re-submitted to the byte-gate. Measured: the grinder submitted **1** draft, the gate
|
||||
processed **34** and banked **2**. Nothing wrong entered the tree (G3/P9: the gate banks only
|
||||
byte-identical output) — but a run banked a function it was never asked to try, and would have committed
|
||||
it under a message naming a different one. Fix: clear the out dir per run. Note the symmetry with R32: a
|
||||
scanner that silently NARROWS its input hides work; a stage that silently WIDENS it fabricates provenance.
|
||||
3. **The grinder fired the fleet-wide propagate from inside the gate.** `gate_stage(propagate=True)` runs
|
||||
`dedup_propagate --auto-from` — the §55b path that timed out at 3600 s and left 90/140 overlays broken,
|
||||
and which, being *inside* the gate, takes the banks down with it when it fails. The unattended caller must
|
||||
never fire it: bank with `propagate=False`, commit the cheap verified banks, then run ONE targeted
|
||||
`dedup_propagate --addr` as its own batch.
|
||||
|
||||
**The transferable point:** a tool that has been failing for a long time accretes latent bugs on its success
|
||||
path, because nothing exercises it. Before trusting an unattended fix-and-run, budget for the first success
|
||||
to fail — and check the tree state, not the exit code (here the durable Task-12 winner save in
|
||||
`.run/permuter-winners/` is what made the crash a non-event).
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
# cross-binary collapsible-byte leverage: docs/duplicates.cross.md.
|
||||
|
||||
# THREE progress metrics (all matter — see the labels):
|
||||
FLEET fn-count byte-ident: 310917 / 353722 = 87.90% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
|
||||
FLEET instr-weighted : 10203439 / 13081451 = 78.0% (shipped .text across resident+138 overlays; the decomp.dev-DISPLAY number)
|
||||
FLEET distinct-code(uniq): 3708744 / 5574674 = 66.5% (64085/87459 unique fns; the DISTINCT-RE number)
|
||||
FLEET fn-count byte-ident: 310919 / 353722 = 87.90% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
|
||||
FLEET instr-weighted : 10203476 / 13081451 = 78.0% (shipped .text across resident+138 overlays; the decomp.dev-DISPLAY number)
|
||||
FLEET distinct-code(uniq): 3708773 / 5574674 = 66.5% (64086/87459 unique fns; the DISTINCT-RE number)
|
||||
MAIN game-code weighted : 436 / 60201 = 0.7% (Phase-27 T10; SEPARATE — LINKED-excluding Ghidra sig dated 2026-06-14, PROVISIONAL until a fresh/complete main sig; NOT folded into the fleet number)
|
||||
|
||||
FLEET REAL substantive : 309062 (of which dedup-shared 234299 via 1847 groups / 234343 instances)
|
||||
FLEET REAL substantive : 309064 (of which dedup-shared 234299 via 1847 groups / 234343 instances)
|
||||
FLEET LINKED PsyQ objs : 959
|
||||
FLEET NON_MATCHING : 7 (0 in any default build — G4)
|
||||
FLEET INCLUDE_ASM stubs : 42798
|
||||
FLEET INCLUDE_ASM stubs : 42796
|
||||
FLEET matchable : 353722
|
||||
|
||||
| binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % |
|
||||
@@ -55,7 +55,7 @@ FLEET matchable : 353722
|
||||
| ov_SC03_011 | 2236 | 1700 | 0 | 2242 | 2527 | 88.7% |
|
||||
| ov_SC03_012 | 2214 | 1700 | 0 | 2215 | 2406 | 92.1% |
|
||||
| ov_SC03_013 | 2233 | 1700 | 0 | 2233 | 2492 | 89.6% |
|
||||
| ov_SC03_014 | 2291 | 1725 | 0 | 2291 | 2685 | 85.3% |
|
||||
| ov_SC03_014 | 2293 | 1725 | 0 | 2293 | 2685 | 85.4% |
|
||||
| ov_SC03_015 | 2292 | 1725 | 0 | 2292 | 2685 | 85.4% |
|
||||
| ov_SC03_023 | 2220 | 1700 | 0 | 2221 | 2435 | 91.2% |
|
||||
| ov_SC03_024 | 2278 | 1705 | 0 | 2285 | 2641 | 86.5% |
|
||||
|
||||
@@ -681,7 +681,31 @@ conditional) · main-EXE/B9 + GLM/B6 + resident's 14 walls (P30) · behemoths B7
|
||||
diagnosing a search that never properly ran (R35). Correct order: **run the directed permuter over the 75 →
|
||||
collect genuine plateaus with real `passes_tried` → only then spend the LLM on what survives.**
|
||||
|
||||
> **🛑 SESSION-5 CHECKPOINT (2026-07-20) — superseded by the Task-13A entry above.** Tree clean (only db.*.gbf R23
|
||||
- **✅ 2026-07-21 — TASK 13B (first run): the directed permuter WINS on its first target; two gate
|
||||
defects fixed at the root.** Ran the newly-targeted grinder bounded (`--once --batch 8 --permute-secs 90
|
||||
--max-closeness 12`). Log: `targeting: ON — 1665 classified; only bucket=permuter is admitted` /
|
||||
`targeting skipped 1601 non-permuter candidates {redraft 707, structural 583, integration 305, unclassified
|
||||
4, unknown 2}` → **`permuter WON func_80181F78 @ ov_SC03_014 (close was 1)`** in ~6 min. **Banked 2**
|
||||
(both byte-gated): `func_80181F78` (8 ins, DELAY-SLOT/schedule) + `func_80141B90` (29 ins, IMM-VALUE/cse).
|
||||
**Both were classified `bucket=permuter` by the Task-13A classifier before the run** — it predicted a
|
||||
search-closer could reach them and one did; the first end-to-end validation of the targeting thesis.
|
||||
**THREE defects found + fixed at the root (all pre-existing, all surfaced by the grinder finally winning):**
|
||||
(1) **`gate_stage` commit path crashed** — `git add src …` with `src` deliberately never defaulted (the
|
||||
Phase 26-A audit), so EVERY caller that omits it (grinder/orchestrator/idiom_hunt) crashes the moment it
|
||||
banks. Unreachable while the grinder banked nothing since Phase 21; the targeting fix made it win and it
|
||||
crashed instantly. Now `git add -u src/` (also kills the §-lesson filename-glob hole that once omitted 4
|
||||
R22-verified banks from a commit). (2) **`_xform` ladder dirs ACCUMULATE across runs** — `-cn/-cast/-rc/-uni`
|
||||
held 34 stale drafts from earlier sessions, so the gate processed 34 when the grinder submitted **1**, and
|
||||
banked one function it was never asked to try (which would then have been committed under a message naming a
|
||||
different one). Now cleared per run. Nothing wrong entered the tree — G3/P9 held throughout, the gate banks
|
||||
only byte-identical output — but the report and the work had diverged (the R32 defect class, inverted:
|
||||
a stage silently WIDENING its input set). (3) **grinder was calling `gate_stage` with the default
|
||||
`propagate=True`** = `dedup_propagate --auto-from`, the fleet-wide path that timed out at 3600s and left
|
||||
90/140 overlays broken (§55b) — unacceptable for the unattended caller; now `propagate=False`, banks
|
||||
committed cheap, propagation left as its own targeted `--addr` batch per the §55b law.
|
||||
**R22 clean-fleet: 140/140 byte-identical.** Cookbook §60 extended; SETUP.md updated.
|
||||
|
||||
> **🛑 SESSION-5 CHECKPOINT (2026-07-20) — superseded by the Task-13A/13B entries above.** Tree clean (only db.*.gbf R23
|
||||
> churn), **140/140 byte-identical** (last R22 clean-fleet at the crack-wave-4 verify + func_8017AE2C ×137;
|
||||
> Task-8/12 tooling changes touch only matching-loop tools, no build/src output). tools-health OK (dedup 1846/0
|
||||
> class). Main HEAD after this = the checkpoint commit. **Fleet 78.0% instr · 66.5% distinct-code · 87.9%
|
||||
|
||||
@@ -1426,7 +1426,25 @@ void func_80141A60(void)
|
||||
}
|
||||
|
||||
|
||||
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_80140608", func_80141B90);
|
||||
|
||||
extern s16 D_800B9A02;
|
||||
extern u8 D_801151C8[];
|
||||
extern s32 D_801151D0;
|
||||
extern u16 D_80115116;
|
||||
extern unsigned short D_80115112;
|
||||
extern u8 D_800B9A15;
|
||||
extern void func_8013FAF8(s16, s16);
|
||||
void func_80141B90(void)
|
||||
{
|
||||
volatile double reserved;
|
||||
D_801151D0 = ((unsigned int *)D_801151C8)[(*(unsigned short *)&D_800B9A02)];
|
||||
((void (*)(s32, s32))func_8013FAF8)(2, 3);
|
||||
if (D_80115116 == 0)
|
||||
{
|
||||
D_800B9A15 = 0;
|
||||
D_80115112 = (long long) (D_80115112 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_func_80141C04() /* dedup: shared engine-core @0x80141C04 (src/shared) */
|
||||
|
||||
|
||||
@@ -3564,7 +3564,29 @@ INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017EB7C", func_80181E8
|
||||
|
||||
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017EB7C", func_80181EEC);
|
||||
|
||||
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017EB7C", func_80181F78);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern void func_8012C218(void *a0);
|
||||
void func_80181F78(void)
|
||||
{
|
||||
int new_var;
|
||||
((s32 (*)(s32)) func_8012C218)(new_var);
|
||||
new_var = 0;
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017EB7C", func_80181F98);
|
||||
|
||||
|
||||
+25
-3
@@ -55,8 +55,19 @@ def _check_sha(binary):
|
||||
|
||||
|
||||
def _xform(tool, ov, indir, suffix, extra=None):
|
||||
"""Run a draft-dir transform; return its out dir, or the in dir if the tool no-ops/fails."""
|
||||
"""Run a draft-dir transform; return its out dir, or the in dir if the tool no-ops/fails.
|
||||
|
||||
The out dir is CLEARED first. It used to be reused across runs, and the transform tools only
|
||||
WRITE the drafts they are given — so every stale draft from every previous run survived in
|
||||
`<drafts>-cn/-cast/-rc/-uni` and was handed to the byte-gate again. Measured 2026-07-21: the
|
||||
grinder submitted ONE permuter winner and the gate processed THIRTY-FOUR drafts and banked TWO
|
||||
— the extra one a leftover from an earlier session. Nothing wrong entered the tree (the
|
||||
whole-binary gate is the sole arbiter, G3/P9, and it banks only byte-identical output), but the
|
||||
run banked a function it was never asked to try and would have committed it under a message
|
||||
naming a different one. A stage that silently widens its own input set is the same defect class
|
||||
as a scanner that silently narrows it (R32): in both, the report and the work diverge."""
|
||||
out = indir + suffix
|
||||
shutil.rmtree(os.path.join(REPO, out), ignore_errors=True)
|
||||
cmd = [PY, f"tools/{tool}", "--overlay", ov, "--in", indir, "--out", out] + (extra or [])
|
||||
r = sh(cmd, timeout=900)
|
||||
return out if _isdir(out) else indir
|
||||
@@ -305,8 +316,19 @@ def _run_gate_locked(drafts, binary, src, asm, out, good_sha, propagate, source_
|
||||
|
||||
commit_sha = None
|
||||
if commit and verified:
|
||||
sh(["git", "add", src, "src/shared/engine_core.h", DEDUP_YAML] +
|
||||
glob.glob(os.path.join(REPO, "src/ov_*/*.c")))
|
||||
# `git add -u src/` = every MODIFIED TRACKED file under src/ — the TU the draft landed in
|
||||
# (whichever split that is), engine_core.h, engine_types.h, and every overlay a propagate
|
||||
# touched. Two bugs this replaces:
|
||||
# 1. it passed `src` straight to git add, and src is DELIBERATELY never defaulted (the
|
||||
# Phase 26-A audit) — so every caller that omits it (grinder, orchestrator,
|
||||
# idiom_hunt) crashed with `TypeError: expected str … not NoneType` THE MOMENT IT
|
||||
# BANKED. Unreachable while the grinder banked nothing; the Task-13A targeting fix
|
||||
# made it win on its first directed run and it crashed immediately.
|
||||
# 2. the `src/ov_*/*.c` glob is a name pattern, and a family's members do NOT all live in
|
||||
# the same-named split — the Phase-29 §-lesson (a filename glob silently omitted 4
|
||||
# R22-verified banks from a commit). `-u` cannot miss a modified tracked file.
|
||||
sh(["git", "add", "-u", "src/"])
|
||||
sh(["git", "add", DEDUP_YAML] + ([src] if src else []))
|
||||
sh(["git", "commit", "-q", "-m",
|
||||
f"feat({os.environ.get('GATE_PHASE', 'decomp')}): {source_tag} gate — +{len(verified)} fns x{propagated} propagated (fleet {fp}%)"])
|
||||
commit_sha = sh(["git", "rev-parse", "--short", "HEAD"]).stdout.strip()
|
||||
|
||||
+14
-2
@@ -251,10 +251,22 @@ def main():
|
||||
by_bin[binary].append(fn)
|
||||
verified = set()
|
||||
for binary, fns in sorted(by_bin.items()): # one gate per source binary; propagate stamps × reach
|
||||
s = gate_stage.run_gate(DRAFTS, binary=binary, source_tag="grinder", commit=True)
|
||||
# §55b LAW: bank with --no-propagate, commit the cheap verified banks, and run
|
||||
# ONE targeted `dedup_propagate --addr <banked>` afterwards as its own batch.
|
||||
# gate_stage's propagate=True path is `dedup_propagate --auto-from`, the fleet-wide
|
||||
# slow route that timed out at 3600s and left 90/140 overlays broken (887 files) —
|
||||
# and because it runs INSIDE the gate, a propagate failure takes the banks with it.
|
||||
# The grinder is the unattended caller, so it must never fire that path.
|
||||
s = gate_stage.run_gate(DRAFTS, binary=binary, source_tag="grinder", commit=True,
|
||||
propagate=False)
|
||||
banked += s.get("banked", 0); fp = s.get("fleet_pct", fp)
|
||||
verified |= set(s.get("verified", []))
|
||||
log(f"gate {binary}: banked {s.get('banked')} (+{s.get('propagated')} prop); total {banked}; fleet {fp}%")
|
||||
log(f"gate {binary}: banked {s.get('banked')} (UN-propagated by design, §55b); "
|
||||
f"total {banked}; fleet {fp}%")
|
||||
if s.get("verified"):
|
||||
log(" -> propagate as its own batch: "
|
||||
+ "; ".join("tools/dedup_propagate.py --addr 0x%s --recover" % f.split('_')[-1]
|
||||
for f in s["verified"][:4]))
|
||||
# A permuter win the whole-binary gate STILL rejects is plumbing-bound (not regalloc/sched) —
|
||||
# re-permuting can never bank it. Blacklist so the grinder stops churning it (the §20 trap).
|
||||
rejected = [f for f, _b in won if f not in verified]
|
||||
|
||||
Reference in New Issue
Block a user