Files
BFM-decomp/phase-ends/PhaseEnd_Phase20.md
T
Drew T e803651f0c feat(phase-20): close — cap tool + T3a %lo crack + 3 byte-proven findings; fleet 58.00%->58.82% (v1.19.0)
- THE CAP TOOL tools/cast_call_sites.py (§17a-1 callee-cast): per draft, callee whose canonical
  TU sig != draft's intended sig -> decl->canonical + call-site cast ((ret(*)(args))func_X)(args)
  (codegen-neutral; gcc folds the cast of a known symbol -> direct jal). Recovered 6 of T6 batch-1's
  33 gate-fails byte-identical (5 x134 + 1 local). Pipeline canon_resident_calls -> cast_call_sites
  -> sig_unify -> harvest_verify --chunk 1.
- T3a CRACKED (not cited): the %lo-folding indexed-global -O0 residual falls to the array-of-STRUCT
  idiom (extern Struct base[], sizeof==stride, base[i].field; NOT *(T*)(&sym+i*stride) which
  materializes &sym). func_8013B7AC banked. Reusable idiom fleet-wide. cookbook §18/§20.
- THREE byte-proven findings (R14): (1) the wave cap is the DEF-side loose-typing wall, not
  callee-conflicts (the §20 "~33" projection was wrong); (2) the -O0 cluster is OVERLAY-LOCAL,
  not reach-134 -> the ×134 rollout is INVALID; (3) data-cast is MOOT (0 real data conflicts).
- T1 typedef type-lift (+0.35%, 9 fns x134); T2 exemplar_miner router; T4 codegen map (cookbook §20);
  T6 batch-1 (+0.28%, 8). dedup 1485->1513/0 failed. check-all 136/136 BYTE-IDENTICAL (R22);
  0 NON_MATCHING (G4). fleet 58.00% -> 58.82%.
- rule R30 (capture context-dependent knowledge before a fresh session). worklog -> logs/Phase20.md.
- bumps 1.18.0 -> 1.19.0
2026-06-21 10:26:34 -06:00

210 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PhaseEnd — Phase 20: Close the propagation cap, crack the gcc residual classes, then scale the waves
**Date:** 2026-06-21 · **Project Version:** 1.19.0 · **Phase Status:** Complete (open-ended phase, closed at a clean checkpoint — Drew, gate 2) · **Generation:** Gen2 (12th phase)
> Gen2 phase 12 of the arc (8→9→10→11→12→13→15→16→17→18→19→**20**; 14 deferred to Gen3+). Ran across **multiple
> sessions**; the granular per-task/per-session trail (the T1 type-lift, the T6 wave, the cap-tool diagnosis, the
> -O0/data-cast byte-proofs, the T3a crack) is preserved on-demand at **`phase-ends/logs/Phase20.md`** (R19 — NOT
> auto-loaded; consult only when researching a mechanism). This file is the synthesis. Owner decisions (Drew):
> class-crack first + skip the permuter grind (this phase); then exhaust the cheap-recovery levers in order
> (cap-tool → -O0 rollout → data-cast → T3a); **close Phase 20 at a clean checkpoint** and do the **automation
> architecture as a fresh-session, plan-mode Phase 21** (the approved design is the Phase-21 Backlog below).
## Build Log
**Files created/changed and complete — do not recreate:**
*New reusable tooling (the phase's durable output):*
- `tools/cast_call_sites.py` — **(THE cap tool, cookbook §20)** the §17a-1 per-site function-pointer cast recovery
for the loose-typing CALLEE-conflict class. Pure `--in`/`--out` draft transform (sibling of sig_unify /
canon_resident_calls): per draft, for each callee whose canonical TU sig differs from the draft's intended sig,
rewrite the decl line → canonical (kills the in-TU `conflicting types`, keeps the symbol in scope) AND cast each
call site → the draft's intended sig `((ret(*)(args))func_X)(args)` (decl lines never cast; gcc folds the cast of
a known symbol → direct `jal`). Whole-binary gate is the sole arbiter (G3/P9). Pipeline:
`canon_resident_calls → cast_call_sites → sig_unify → harvest_verify --chunk 1`.
- `tools/build_engine_types.py` — **(T1, extended)** added `find_typedefs()` (brace-aware anon-struct / fn-ptr /
alias typedefs) + same-name-different-layout collision + tagged-struct-typedef overlap guards; emits typedefs
after named structs in dep order. Closed the §19 type-blocked propagation cap.
- `tools/exemplar_miner.py` — **(T2)** residual router: `wall_taxonomy.json` + per-overlay reach →
`docs/exemplar_curriculum.md` + `.run/exemplar_routing.json` (WAVE/STRUCT/PINS/STUB pools, reach-ranked).
*Config / source (the matches):*
- `src/ov_SC01_077/ov_SC01_077.c` + `src/shared/engine_core.h` + `config/dedup.us.yaml` + the 134 overlay `.c`
files — T1's 9 typedef-freed fns ×134, T6 batch-1's 8 (7 ×134 + 1 local), the cap tool's 6 (5 ×134 + 1 local),
all byte-gated + propagated. `config/dedup.us.yaml` **1485 → 1513** validated cross-binary groups (0 failed).
- `src/ov_SC01_077/ov_SC01_077_o0.c` — **(T3a)** func_8013B7AC matched via the array-of-struct `%lo`-fold idiom
(×1 — the -O0 cluster is overlay-local).
*Docs / knowledge base (R16 flywheel, R21):*
- `docs/matching-cookbook.md` — **§20** (NEW: the wave-at-scale GATE CAP = loose-typing call-graph wall; the cap
tool RESOLUTION + the R14 re-diagnosis = DEF-side wall dominates, not callee-conflicts; the data-cast MOOT
finding; the confirmed-irreducible classes store-vs-load / hoist-vs-remat / IV-combine / hoisted-invariant /
the -O1 class; the stale-`.o` + args-as-array + `--chunk 1` gotchas) + **§18** (T3a `%lo`-fold CRACKED via
array-of-struct + the -O0-cluster-is-overlay-local R14 correction) + **§17a** (the gate-cap framing).
- `docs/SETUP.md` — `cast_call_sites.py` tooling-inventory row.
- `README.md` / `docs/{progress,difficulty,duplicates}.*.md` — Phase-20 status + regenerated digests.
- `phase-ends/CURRENT_PHASE.md` → **`phase-ends/logs/Phase20.md`** (R19 archive). `phase-ends/PhaseEnd_Phase20.md` — this file.
**Local artifacts (gitignored / regenerable):** `.run/drafts-t6-*` (wave + cast + sig_unify recovery stages),
`.run/drafts-t3a/*`, `.run/ghidra_c/*` (300 cached Ghidra-C), `.run/exemplar_routing.json`,
`.run/harvest_*.txt`, `build/`, `expected/`, `asm/`, `assets/`. The 134 overlay Ghidra programs are
script-reproducible (DB-commit deferred as regenerable).
**Tools/packages installed:** None — the whole phase used the existing Phase-4/6/10/11/12/13 toolchain + venv.
**Verification results (literal) — the milestone proof:**
- **`make check-all` → 136 passed, 0 failed of 136** (main `143dbb89…`, resident `8e17e02f…`, ov_SC01_077
`d19c9580…`, all 134 overlays), reproduced from clean after every banked step (R22). A stale-artifact false
failure (ov_SC01_005, from the reverted -O0 test) was caught by check-all and cleared by a clean re-extract —
see Deviations.
- **`make report`:** FLEET byte-identical **202,350 / 344,010 = 58.82%** (phase start **58.00%** / 199,541 →
**+0.82%**); LINKED 959; **dedup 1485 → 1513 validated, 0 failed**; **0 NON_MATCHING** in any default build (G4).
- **Phase arc (banked):** T1 type-lift **+0.35%** (9 fns ×134) · T6 batch-1 **+0.28%** (8 matches) · the cap tool
**+0.19%** (6 matches) · T3a func_8013B7AC (×1). The cracks/findings (below) are the durable non-% value.
- `git status`: only `config/`/`tools/`/`src/`/`docs/`/`phase-ends/` tracked; zero ROM-derived/generated bulk
staged. **No Ghidra DB change** this phase (matching used cached Ghidra-C + asm; the `db.*.gbf` churn is
SessionStart-restart noise — R23 no-op, NOT staged).
**Milestone achieved (confirmed by Drew, gate 2):** the open-ended phase is closed at a **clean checkpoint** —
fleet rose **58.00% → 58.82%**, **136/136 binaries byte-identical**, **0 NON_MATCHING**, with three reusable
tools (the cap tool, the typedef-lift, the residual router), the **gcc-2.7.2 codegen map** distilled (cookbook
§20), the **T3a `%lo`-fold class CRACKED** (array-of-struct idiom — a long-"irreducible" residual, now a reusable
cookbook idiom), and **three byte-proven strategic findings** (R14) that retire two dead levers and sharpen the
roadmap: the cap is the **DEF-side loose-typing wall** (not callee-conflicts), the **-O0 cluster is overlay-local**
(the ×134 rollout is invalid), and **data-cast is moot** (0 real data conflicts).
**Next:** **Phase 21 — the automation architecture** (the "automation manager" / supervised-autonomous grind).
A fresh session, **plan mode** (Tier-1). The full approved design + the 6 build-pieces are the **Phase-21 Backlog**
below — plan from it.
## Deviations
| Item | Plan | Actual | Reason |
|---|---|---|---|
| The cap "~33" recovery | the §20 cast tool recovers the batch's lost ~33 | **6 recovered** | R14 re-diagnosis: the 33 are NOT mostly callee-conflicts (the cast tool's class); ~18 are the DEF-side loose-typing wall (byte-proven both ways), + a DATA tail. §20 corrected. |
| -O0 ×134 rollout | bank the 6 matched -O0 fns ×134 (~+0.6% "free") | **INVALID — skipped** | R14 byte-proof: only 1/134 overlays shares the cluster bytes; the fns reference per-overlay data → overlay-local. Built+reverted the split infra; cookbook §18 corrected. |
| data-cast extension | complete the cap tool with `*(T*)&D_x` | **MOOT — not built** | R14 byte-proof: 0 drafts have a real data-type conflict; the lone case was a typedef-redef masking the def-sig wall. |
| T3a `%lo`-folding | likely cite-irreducible (§18 wall) | **CRACKED** | the array-of-struct idiom folds `%lo` (the failing forms materialize `&sym`); a better-than-expected result. |
| T3b/T3c | crack-or-cite | **cited** (T3b R14-reframed strength-reduction; T3c store-vs-load confirmed unsteerable, sched.c) | genuine compiler residuals; byte-evidenced verdicts in §20. |
| Phase close | grind T5 waves + giants | **closed at a clean checkpoint; automation → Phase 21** | Drew: the cached ≤90-ins tail is byte-exhausted; the autonomy is a Tier-1 architecture deserving a fresh plan-mode phase. |
| ov_SC01_005 check-all | (n/a) | **stale-artifact false-fail caught + fixed** | the reverted -O0 test left a stale `.ld`/asm (3-way split); `make check` doesn't re-extract → linked a deleted `.o`. Clean re-extract restored `56760dbe`. → the R22 corollary (a reverted *config* needs a re-extract). |
| Effort | Max | Max throughout (orchestration + the deep diagnosis/synthesis); no Ultracode needed (Workflow sets per-agent effort) | the cap diagnosis + T3a crack + the automation design are deep single-thread work. |
## Commit Message
```
(Phase 20 landed across multi-session commits; final session commit:0173..commit:0177 + this PhaseEnd.)
feat(phase-20): close — cap tool + T3a %lo crack + 3 byte-proven findings; fleet 58.00%->58.82% (v1.19.0)
- THE CAP TOOL tools/cast_call_sites.py (§17a-1 callee-cast): per draft, callee whose canonical
TU sig != draft's intended sig -> decl->canonical + call-site cast ((ret(*)(args))func_X)(args)
(codegen-neutral; gcc folds the cast of a known symbol -> direct jal). Recovered 6 of T6 batch-1's
33 gate-fails byte-identical (5 x134 + 1 local). Pipeline canon_resident_calls -> cast_call_sites
-> sig_unify -> harvest_verify --chunk 1.
- T3a CRACKED (not cited): the %lo-folding indexed-global -O0 residual falls to the array-of-STRUCT
idiom (extern Struct base[], sizeof==stride, base[i].field; NOT *(T*)(&sym+i*stride) which
materializes &sym). func_8013B7AC banked. Reusable idiom fleet-wide. cookbook §18/§20.
- THREE byte-proven findings (R14): (1) the wave cap is the DEF-side loose-typing wall, not
callee-conflicts (the §20 "~33" projection was wrong); (2) the -O0 cluster is OVERLAY-LOCAL,
not reach-134 -> the ×134 rollout is INVALID; (3) data-cast is MOOT (0 real data conflicts).
- T1 typedef type-lift (+0.35%, 9 fns x134); T2 exemplar_miner router; T4 codegen map (cookbook §20);
T6 batch-1 (+0.28%, 8). dedup 1485->1513/0 failed. check-all 136/136 BYTE-IDENTICAL (R22);
0 NON_MATCHING (G4). fleet 58.00% -> 58.82%.
- rule R30 (capture context-dependent knowledge before a fresh session). worklog -> logs/Phase20.md.
- bumps 1.18.0 -> 1.19.0
```
## Rules Added This Phase
| Rule | Reason |
|---|---|
| **R30 — Capture context-dependent knowledge artifacts before a fresh session.** Cookbook entries, byte-verified findings, codegen-map distillations, and doc corrections whose quality depends on the current session's full live context MUST be written DURING that session, before any fresh-session handoff (the fresh session inherits only compressed summaries and loses the detail / nuance / byte-evidence). Defer only mechanical / continuable work (build the next tool, run the next wave). Extends R16 (the flywheel — adds the timing constraint). Memory `capture-knowledge-before-fresh-session`. | Candidate since the multi-session handoff (Drew, 2026-06-21 — prompted by nearly deferring T4's §20 distillation to a fresh session that would have lost the byte-evidence). Exercised all session: §20 RESOLUTION, the §18 T3a crack, and the three R14 findings were all written during the producing session. |
*(Not elevated to rules — captured as cookbook techniques per the Phase-8+ precedent: the call-site-cast recovery (§20), the array-of-struct `%lo`-fold idiom (§18), the DEF-side-wall / overlay-local / data-cast-moot findings (§18/§20). The **R22 corollary** — a reverted **config** needs a `make extract`, not just `make check`, or it leaves a stale `.ld`/asm while `git status` looks clean — is a §13/§18 build-infra note, governed by the existing R22.)*
## PhaseEnd Changelog
**v1.18.0 → v1.19.0 — Phase 20 complete (Gen2 phase 12; open-ended, closed at a clean checkpoint).** The fleet
rose **58.00% → 58.82%** byte-identical-from-source (136/136 binaries byte-identical, 0 NON_MATCHING throughout),
banked by the **typedef type-lift** (T1, +0.35%, closing the §19 propagation cap), an **enriched wave** (T6
batch-1, +0.28%), and the phase's headline tool — **`tools/cast_call_sites.py`**, the §17a-1 per-site
function-pointer cast that recovers the loose-typing **callee-conflict** class (+0.19%, codegen-neutral, byte-gated).
The **T3a `%lo`-folding -O0 residual was CRACKED** (not the expected cite-irreducible): the **array-of-struct
idiom** (`extern Struct base[]`, `base[i].field`) folds `%lo` where `*(T*)(&sym+i*stride)` materializes — a
reusable fleet-wide idiom. The phase's most valuable output is **three byte-proven (R14) strategic findings** that
retire two dead levers and sharpen the roadmap: the wave cap is the **DEF-side loose-typing wall** (a banked caller
declares the draft's own function incompatibly; caller-side fix blocked because `INCLUDE_ASM` declares no symbol),
**not** callee-conflicts as §20 first projected; the **-O0 cluster is overlay-local** (per-overlay data addresses),
so the ×134 rollout is **invalid** (the "reach-134" label conflated function-present with byte-identical); and the
**data-cast is moot** (0 real data conflicts). The gcc-2.7.2 **codegen map** is distilled (cookbook §20). Net read:
the reach-134 ≤90-ins **cached** tail is byte-exhausted of cheap recoveries; the remaining yield is fresh targets,
the giants, and the hard walls. One rule (**R30**, capture-knowledge-before-fresh-session). The phase closes
deliberately so the **automation architecture** (the supervised-autonomous grind) gets its own fresh, plan-mode
**Phase 21** — designed and Drew-approved, captured as the Backlog below.
## Plain-English Recap
This phase squeezed the remaining easy wins out of the game's shared engine code and, just as importantly, *proved
which "easy wins" were actually mirages.* We built a tool that auto-fixes a common reason a correct function won't
slot in (a function-declaration mismatch) — it recovered six functions cleanly. We then chased two more ideas and
the automatic bit-for-bit referee proved both were dead ends (functions we thought were shared across all 134
levels turned out unique to each; "data conflicts" weren't real) — so we proved them dead, wrote down exactly why,
and faked nothing. The happy surprise: a residual we'd long called "impossible" actually *cracked* with a clean C
trick (treat the global as an array of structs), now a reusable recipe. We finished at ~58.8% of the game rebuilt
bit-for-bit, with everything still byte-perfect. The big takeaway is honest: the leftover functions in this
size-band are genuinely the hard wall now, not low-hanging fruit — so the next phase is a different shape entirely.
We designed (and you approved) an **automation manager** setup for your 5 days away: I orchestrate; swarms of AI
agents do the matching in isolated workflows (so my own memory stays clean enough to run for days); a background
brute-forcer grinds the mechanical cases; and — the key deliverable — *everything that gets close but doesn't
finish is logged as a ranked backlog* for you to hand-finish when you're back. That automation is its own fresh
phase, planned from the design captured below.
## Phase-21 Backlog — "The automation manager" (the approved design; nothing here is lost on close)
> Phase 21 opens in **plan mode** (Tier-1 architecture). Drew-approved design: **supervised-autonomous**,
> **verify-giants-first**, **build-now**. I am the orchestrator (Max); workflows are the workers (xHigh via
> `opts.effort` — no global Ultracode needed). The goal: spend ~5 idle days grinding as much as possible and
> **storing results** — banking byte-matches AND logging every near-miss (closest-achieved) as a ranked backlog
> for Drew's hand-sessions. The byte-gate (G3/P9) prevents false matches; the ROI-gate prevents wall-grinding.
**The 6 build-pieces (prioritised):**
1. **[FIRST, no MCP] Verify giants shared-ness + build the target-pool manifest.** Byte-verify the 28 giants
(reach-134 fns >150 ins) are genuinely shared ×134 (h_exact across overlays — the -O0 "reach-134" was a
mislabel, so don't trust it). Assemble the fuel manifest: fresh tractable reach-134 ov_SC01_077 stubs + the
SHARED giants + the 9 -O0 stubs (idiom-known), each tagged reach + class + size.
2. **[needs `/mcp` once, up front] Fuel prefetch.** Stop MCP (R23) → `DecompileFunctions.java` over the manifest
→ cache Ghidra-C to `.run/ghidra_c/` (cache is 300; ov_SC01_077 has 668). **CRITICAL: pre-load ALL fuel so the
unattended run never needs live MCP** (the run is cache-based — no `/mcp` reconnect mid-run).
3. **Worker workflow + deterministic gate/bank/propagate stage.** A Workflow: fan-out drafter agents (xHigh) over
the pool using the full toolkit (§17 pins, §18/T3a array-of-struct, §19 recovery, §20 cast tool) → each returns
`{matched | near-miss + best-draft + diff + class | failed}`. Deterministic stage:
`canon_resident_calls → cast_call_sites → sig_unify → harvest_verify --chunk 1 → dedup_propagate`. Returns ONE
compact summary (keeps the orchestrator's context lean). Validate on a small sample before scaling.
4. **The backlog ledger** (`docs/backlog.md` + `.run/backlog.jsonl`, committed) — **the deliverable**: every
near-miss logged with closest-achieved draft, diff score, residual class, reach, and where it stuck —
ranked for Drew's hand-sessions. Honest (P9): only byte-matches bank.
5. **Grinder workflow** — re-cast the Phase-16 `auto_driver` as a Workflow: decomp-permuter (CPU-bound, local,
free) on the regalloc/schedule-class near-misses, banking through the same gate, logging near-misses. Runs
alongside the worker waves (CPU budget vs token budget).
6. **[LAST] ROI orchestrator loop + `auto_supervisor` keep-alive.** The between-wave loop (Max): bank → route →
assess close-rate; when a pool's close-rate drops below threshold for K rounds, switch pools (≤90-ins → giants
→ -O0) or pause. Deploy the Phase-16 `auto_supervisor.sh` (detect stalled/exited session → resume via
`continue`; `auto_stop.sh` sentinel = Drew's kill switch). Sample-validate the full loop (a few hours) BEFORE
the unattended stretch, then launch.
**Carried context for the plan:**
- The reusable wave recipe (proven Phase 20): `gen_harvest_targets --min-reach 134 --max-nins 90` → filter to
cached Ghidra-C → Workflow (one agent/target, **args as a JSON array NOT a string** — the gotcha) →
`canon_resident_calls → cast_call_sites → sig_unify → harvest_verify --chunk 1 → dedup_propagate --auto-from`.
- Honest fuel/ROI caveat: the cached ≤90-ins tail is byte-exhausted; fresh targets are finite (~+a few %); the
giants are high byte-weight but low auto-yield (Phase-16 ~3% wall) → they're primarily **backlog fuel**
(workers get them close, log near-misses, Drew hand-finishes). 5 days of runtime ≠ 5 days of wins — the value
is the harvested tractable % **plus** the ranked near-miss backlog.
- The 7 callee/data-plumbing capped fns (reach-134, matched-but-local): `0x80142B2C 0x801535F4 0x80155E30
0x80157580 0x801576A8 0x80168F40 0x80170B48` — fail `compiles_standalone` on undeclared callees/data; a
macro-extern-injection (or canonical-callee-sig embed) frees them ×134 (~+0.3%). Worker-workflow fodder.
- The -O1 class (`func_80161A90`) — needs an `-O1` split file (the §18 -O0 precedent); build-infra, low priority.
## 🛑 Stop Here
PhaseEnd written; `CURRENT_PHASE.md` archived → `phase-ends/logs/Phase20.md` (R19). **Drew commits AND pushes**
this PhaseEnd + the archived log + the final-session matching commits (`commit:0173`..`commit:0177`) (R6/R8 — Drew's
commit is the gate-2 sign-off). No Ghidra DB change this phase (R23 no-op — the `db.*.gbf` churn is restart-noise,
do NOT stage it). Gen2 continues — do **NOT** start Phase 21 here. Start a **fresh session** (effort **Max**,
**plan mode**) for **Phase 21 — the automation manager** (the Backlog above; verify giants → prefetch fuel →
worker/grinder/feeder workflows + backlog ledger → ROI loop + supervisor). Keep this file forever.