Files
BFM-decomp/phase-ends/logs/Phase27.md
T
Drew T 3b31508a24 feat(phase-27): the honest frontier — fix the instruments, audit the disc, dissolve a wall (v1.26.0)
- INSTRUMENTS FIXED: Makefile fail-closed (report's gates were swallowed); one cdecl typedef-strip
  primitive (was 6 regexes); scanners derived not hand-listed (difficulty/exemplar_miner); the
  second boundary oracle extended to resident. Each fix CHANGED an answer the old tool hid.
- DISC AUDITED HONEST: 4 hidden SC07 overlays onboarded (136->140, code at PAC entry 1) + 39
  un-onboarded type-1 code modules found (resident-class, load-address RE pending). The byte-gate
  is blind to un-onboarded code (R34); game-code TRUE 100% now spans 140 + ~39. Instr 68.9->67.0%
  (denominator correction, not regression).
- PIN-CRASH WALL DISSOLVED: the §42e "cc1 SIGABRTs the sibling TU" wall is the extract_unit macro-
  drop (sched.c:2725), fixed (T5 _carry_macros); pinned families stage 133/133 clean -> P31 open.
- HONEST FRONTIER: worklist --assert-partition (R32, caught 5 stale rows); ledger corruption fixed;
  calibration.md (the templatability swing: h_exact cores ~xN, h_seq families ~0% -> B2 refuted).
- FABLE5 SPRINT: 4 cracks + the SIGABRT, 0 banks, but 3 wall reclassifications + the wall dissolved
  + ~9 pin-free levers distilled (cookbook §42e/§44 + regalloc/cse_expr §H + decision-log R31).
- 140/140 byte-identical (R22), 0 NON_MATCHING (G4), audit gates green + fail-closed. No tools
  installed. rules R35 (fix the instrument before trusting its measurement). bumps 1.25.0 -> 1.26.0.
2026-07-15 20:42:32 -06:00

72 lines
35 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.
# CURRENT PHASE — Phase 27: The Fable5 Farewell Sprint + the Honest Frontier
> **Status:** ACTIVE · plan approved by Drew (gate 1) 2026-07-15 · Generation Gen2 (19th phase of the arc; Phase 14 public-flip deferred to Gen3+)
> **Opening brief:** `docs/roadmap-to-100.md` §3 (P27) — ADVISORY, and **materially corrected by this phase's planning verification** (see below). Baseline: v1.25.0 / `PhaseEnd_Phase26`.
> **⏳ PERISHABLE: the Fable5 window closes ~2026-07-19.** Task 1 runs first and concurrently; everything else is deterministic and non-perishable.
> **Recovery note:** a fresh session resumes from the ▶ CURRENT TASK below (P3 — autonomous between gates). Read this file's plan context + the roadmap §3 P27 entry + the **Planning verification** section below (which supersedes several roadmap specifics). The per-task Log at the bottom is the crash-recovery trail.
## The plan in one paragraph
Phase 26 closed on an honest pivot — the mechanical/templating harvest is byte-proven exhausted (3 gate probes, 0%) — and on the 26-A tooling-integrity audit, whose finding was that *our own tools were manufacturing several of the "compiler walls" we had recorded across 26 phases* (→ R32/R33/R34). Phase 27 exists to rebuild the endgame plan on **measured reality instead of a manifest that over-promises**, and to spend the one perishable input — the **Fable5 discovery tier** — before it expires. Planning verification (three read-only agents, 2026-07-15) found the roadmap's *shape* sound but **~28 of its P27 specifics stale, mis-transcribed from the audit they cite, or actively harmful**; this phase executes the corrected slate. Owner decisions (2026-07-15): **curated `.run/` preservation** · **full disc audit incl. the type-sweep, accepting the denominator expansion** · **Fable5 in 2 waves with distillation between**.
## Planning verification — what changed vs the roadmap (R14 at planning scale)
**The three findings that reshaped the plan:**
1. **The `0x8017BEBC` probe would have manufactured a 4th false wall.** Billed "possibly the largest cheap win left" (~106k ins), it would fail **112/112 today for a *tooling* reason**: `extract_unit` doesn't carry the 8 file-scope `gte_*` macros the banked exemplar references (`src/ov_SC01_000/ov_SC01_000_jr_8017BEBC.c:2838-2948`); **0 of the 112 member TUs define them**. Fix the carry first, or the probe is worthless. Also: "NEVER PROBED" is **unproven** (A3h's `--hseq --band all` ran 07-14, *after* the 07-13 exemplar bank; the family qualified — likely staged-and-failed among the 9,698); "IMM-scattered" is **misleading** — `cls_counts = {PURE: 106, IMM: 6, STRUCT: 0}`, a 95%-PURE class with a 6-member IMM tail. Exemplar lives in **`ov_SC01_000`, not ov077**.
2. **`make report` is NOT fail-closed — roadmap §5 asserts it is.** `Makefile:9-10` sets `.ONESHELL` with **no `-e`** in `.SHELLFLAGS` (verified via `make -p`: `.SHELLFLAGS := -c`), so the recipe is one `bash -c` and only the **last** command's exit survives. `dedup-check` is fail-closed *only because it is last*; `lint_symbol_refs`, `progress --audit`, `difficulty`, `dup_report` are **swallowed**. Until fixed, every R32 assertion added downstream is swallowed on arrival. `check-all`/`extract-all` also assert `fail == 0` rather than `pass == N` → an empty pipeline is a **vacuous pass**. Neither audit target has any dependent.
3. **Four code-bearing SC07 payloads (~2.45 MB) are invisible to every tool.** `ov_SC07_{006,007,010,011}` sit at PAC entry **index 1** (`1.4.dec`) while all 134 onboarded use index **0**, and `new_overlay.sh:23` hardcodes `0.4.dec` + exits at `:28`. Code-bearing confirmed by probe (98.0% plausible-opcode; `jr $ra` 2450–2614 — statistically identical to onboarded overlays). **Zero mentions in `docs/` or `config/`.** The resident is an index-1 entry too — same convention blind spot.
**Dropped from the roadmap's slate, with reasons:**
- `0x8013C414` — ×134 **contested** by an explicit `fuel_manifest → reach_verification.o0_overlay_local: verified_reach: 1`; `worklist.md:197` prices it 329×1 = 0.04% of remaining. Also **already drafted** (`.run/backlog_drafts/`, `.run/one3-func_8013C414/`). Not perishable-window material.
- `func_801549F8` ("2 diffs from done") — traces to the **superseded** `family-endgame-megaplan.md:187`; Phase 26 already checked it, walled it at **17/31**, and wrote *"Permuter/Fable5 class — do NOT hand-grind it"* (`logs/Phase26.md:540-546`); its close=0 row was inside the A10 re-gate that banked **0/958**. ×134 contested (`fuel_manifest` reach=1; 31 ins).
- `func_8012E364` — the "stale closeness" label is **itself stale**; the backlog was regenerated and now reads **close=23** (`backlog.md:1317`).
- `jtbl_carve.all_data_labels` "fix first · load-bearing for B5" — **refuted by the audit it cites**: measured twice independently, **0 of 5043 jtbl ends differ**; *"zero live damage, zero latent damage… a case for NONE is defensible"* (`tooling-audit.md:1435-1447`). R33 verdict = delete the dead end-from-next-label logic. B5 is **not** gated on it. ("+ main's jtbl fns" isn't this tool either — it globs `asm/<ov>/data/*` only.)
**B4 dissolves into Task 4.** Its remedy was **already run**: A9b re-ran 7 "blocked" cores through `bank_exemplar` → **1/7**, and that one (`func_8017A4AC`) is already banked ×134. The 4 residual need 4 *different* fixes — and `func_8015C32C`'s is `masked_diff.SCALAR_TYPEDEF_RE`, already Task 4's debt. (5th core, unnamed in the roadmap: **`func_80159C84`** (337). Arithmetic exact: 5×134 = 233,696 ≈ "234k"; 3 plumbing-shaped = 122,878 ≈ "123k".)
**Ledger corruption to fix in Task 8:** `worklist.md:24/:69` + `backlog.md:46` still carry `func_80178004` as `close=0 | MATCH` — a claim Phase 26 **explicitly retracted as a myth** (best historic permuter score 5, pinned); duplicate rows with conflicting values (`func_801549F8` close=0 at `:125` AND close=3 at `:631`; `func_8014D820` at `:1793` and `:1855`); `func_801670E4` carried at close=94 when the real best is **23**. **B3's label is wrong** though its numbers are right: only **106 of 228** cores are reach-134 (119 are reach-1); the 884,130 gain figure already discounts them.
**Confirmed exactly (no change):** the 3 seeds still stub at 304/209/279 ins, pin-free, `func_801670E4` close=23 · `0x80176734` 371 ins, genuinely un-drafted, #4 by templatable weight · the `qty_n_refs` lever (`local-alloc.c:1869`) genuinely untested and distinct from the internals already patched · 1,858 / 1,670 / 228 / 884,130 · resident 21 stubs · main 2,002 / 1,048 / 954 · 138 type-4 / 134 onboarded / 166 type-1.
**Metric corrections carried into Task 10:** roadmap §2's *"plus the main EXE's ~2,002 stubs"* **double-counts finished work** — ~954 are **LINKED PsyQ = complete** per the contract's own decision (2); honest remaining main game code = **1,034**. *"~80 jtbl fns (`progress.md`)"* — citation wrong (`progress.md` contains zero "jtbl"); real = 82, of which only **30 are game code**.
**Meta-lesson (→ decision-log, R31):** the roadmap's task-2 framings are transcriptions of the audit's *headlines*; the audit's own **skeptic verdicts** disagree with several. `tooling-audit.md` says so itself: *"The skeptics killed 4 findings and downgraded 16 — read the verdicts, not the raw claims."*
## Task checklist (effort per R7 · one commit per completed task after this file is updated, Drew pushes — R6/R20)
- [x] ▶ **Task 1 — Fable5 discovery sprint** `[orchestration xHigh · agents model:fable · distillation Max]` — **COMPLETE: 4 cracks + the SIGABRT, 0 direct banks, rich idiom harvest (the doctrine confirmed).** `func_80176734` (fresh core, 371 ins) landed last — no bank (mine=370 vs 371, 5 permuter-shaped clusters, honesty-gated) but **5 new byte-proven mechanisms**, distilled: the **CSE address-fold antidote** (a balanced if/else diamond forces a fresh cse table — pure C, no asm) + `update_equiv_regs` live_length-doubling + `record_jump_equiv` fall-through (cookbook cse_expr §H). Its draft → decomp-permuter warm-start (P29). **No more Fable5 waves this session (Drew, context cap).** **Wave 1** (3 recon-done seeds): none banked, but all three produced oracle-proven **reclassifications refuting §44-Lever-5's wall names** + new pin-free levers — `func_8016CBC0` root-A CRACKED byte-zero (density gap, "coalescing knife-edge" refuted — gcc has no coalescing), `func_8014D820` block-0 CRACKED pin-free 261→110 (reused-load-temp serialization), `func_801670E4` residual proven **RC-6 not S3** (the reg_renumber-swap oracle). **Wave 2 SIGABRT (major):** the §42e pin-crash wall is **REFUTED** — it's the T5 macro-drop, not a compiler limit (`sched.c:2725`; per-pin predicate; pinned families stage 133/133 clean → **P31's pin route is OPEN**). **DISTILLED (R16/R30):** cookbook §42e-CORRECTION + §44-Lever-5 reclassification; regalloc-map **§H** (the reg_renumber-swap oracle + RC-14 reused-load-temp / RC-15 density-dial + the local-vs-global tie sub-class); `docs/decision-log.md` R31 (the 3 strategic findings). Recon preserved (R20, 112K). *(Task 3 was pulled ahead of it — see the Log.)* Wave 1 (parallel-isolated): the 3 recon-done pin-free seeds `func_8014D820` (304), `func_8016CBC0` (209), `func_801670E4` (279, close=23); seeds at `.run/giants/*.opus.{c,md}`. **Distill idioms into cookbook §31/§52 + `docs/gcc-2.7.2-map/` IN-SESSION (R30)** — the value is the idiom, not the bank (§52: a *failed* Fable5 pass still fed 670 cheap-Opus instances). Wave 2, informed by wave 1: `0x80176734` (371) + **the pin-crash cc1 SIGABRT characterization** (gates P31's pin-×1 endgame; harness works at `.run/fable_80178004/{runorc.sh,oracle2.gdb}`; cause is currently **hypothesis-only** — no abort site, assert identity, backtrace, or minimal repro exists). `func_80178004`'s `qty_n_refs` = wave-2 filler only (decision-log prices grinding it low-EV). **Gate: idioms distilled, not functions banked.** Verify: whole-binary byte-gate per crack; `family_sweep` propagate; R22 clean-fleet.
- [x] **Task 2 — Makefile fail-closed (the enabling fix)** `[xHigh]` — **DONE.** `.SHELLFLAGS := -ec` (global fail-closed) with ONE documented opt-out: `check-env` (`set +e` — its contract is accumulate-every-failure). Fixed the `check-all:610` `grep -c` landmine (`|| true` — grep -c exits 1 on 0 matches, which `-e` would treat as fatal → check-all would fail when nothing failed). Strengthened `check-all`/`extract-all` from `fail == 0` → **`pass == N`** (coverage assertion, R32 — the old form was a vacuous pass on an empty pipeline). Gave the two audit oracles a dependent: **new `make tools-health`** = `audit-corpus` + `audit-cdecl` + `report`, fail-closed (NOT a `report`/`build` prereq — audit-cdecl is ~minutes). SETUP §6.3 documents it (R21). **VERIFIED:** (1) known-answer — a broken `lint_symbol_refs` makes `make report` exit non-zero, and a **negative control** proves it: the *identical* break exits **0** under old `.SHELLFLAGS=-c`, **2** under `-ec`; (2) the `grep -c` landmine and the vacuous-pass both reproduced + fixed in isolation; (3) `check-env` still exits 0 (opt-out works); (4) **`make check-all` → 136/136 byte-identical**, and a forced `main` re-extract+rebuild exercised the full splat→cpp→cc1→maspsx→as→ld→objcopy→check pipeline under `-e` → `143dbb89…`; (5) `audit-corpus` (7s) + `audit-cdecl` (green) + `tools-health` dry-run all wired. Recipe scan found the Makefile was already `-e`-aware (`set -o pipefail`, explicit `|| true`, guarded `@` lines) — line 610 was the only real hazard. *(completes with this commit)*
- [x] **Task 3 — Curated `.run/` preservation** `[xHigh]` — **DONE** (pulled ahead of Task 1 — it de-risks the sprint's inputs). `.gitignore` `/.run/` → contents-exclude form (`/.run/*` + `!` exceptions, the `/tools/bin/*.sha256` precedent). **Refined at execution against the bytes:** the naive "commit the dirs" would have been **12.3 MB of regenerable gcc RTL scratch**; the genuinely irreplaceable set is **~2.2 MB / 31 files** — the 6 Phase-25 `*.opus.{c,md}` seed recons (49K), the `func_80178004` gdb-on-cc1 **harness + `ORACLE_PROOF.md` + the v00–v07 draft ladder + the sched/combine `.lst` evidence** (~110K), and the two frontier ledgers (`backlog.jsonl` 1.9M, `fuel_manifest.json` 67K). `dumps_v00..v07/` + `d_pf*.i.*` stay ignored — **regenerable via `runorc.sh` + the `.gdb` scripts** (R33: commit what a rerun cannot reproduce). **VERIFIED:** `git add --dry-run .run/` stages exactly the 30 intended files, 0 bulk; negative control — `.run/ghidra-mcp.log`, `dumps_v00`, `d_pf.i.sched`, `d_pf.s` all still `IGNORED`; no `db.*.gbf` staged (R23). *(completes with this commit)*
- [x] **Task 4 — The cdecl strip primitive + surface cc1 stderr** `[xHigh]` — **DONE.** Found the defect is **six** copied scalar-name regexes, not two (`harvest_verify._TD`, `masked_diff.SCALAR_TYPEDEF_RE`, `canon_sig_reconcile`'s own, `eval_lora`, `format_finetune`, + the 2 masked_diff consumers). Added **one primitive to `cdecl`**: `typedef_names(tu_path)` + `strip_provided_typedefs(draft, provided)` — built on `tu_statements` (robust) **not** `tu_scope` (which coverage-asserts → would crash the byte-gate on any unrelated unparseable file-scope statement; a deliberate refinement of the plan). Split multi-typedef lines via `split_statements` (depth-aware); covers scalar AND struct typedefs; keeps draft-local types. **`harvest_verify`:** per-TU strip-set (unblocks the 39 struct-typedef drafts) + **cc1 stderr surfaced** — `build()` stashes it, a single-draft failure is classified **DIFF / PLUMBING:… / CC1-FAIL / SKIP** (`.run/harvest_failed.classified.txt`), so a `redefinition` is no longer recorded as a byte miss. **`masked_diff.strip_scalar_typedefs()`** (common.h set derived once, R33) wired into `match_one` + `p16_permute`. Unblocks B4's `func_8015C32C` (`redefinition of 's16'`). **VERIFIED:** (1) headline known-answer — `func_8015C030` → **`MATCH (23 ins)` UNEDITED** (was CC1-FAIL; multi-line split alone fixes it); (2) unit — 7/7 scalars stripped, a local struct KEPT, a TU-provided `Blk16` stripped; (3) classifier unit — DIFF/PLUMBING/CC1-FAIL/SKIP all correct; (4) all 5 tools import + parse; (5) **R22 clean-fleet 136/136** + main clean-rebuild `143dbb89` (a mid-test `c4546248` "mismatch" was a stale-incremental artifact from concurrent compiles — resolved by a clean rebuild, the R22 lesson; my edits touch only `tools/`, `src/` stayed git-clean). A strip bug can only fail-to-bank, never falsely bank (the audit invariant). SETUP §6.3 + cdecl inventory updated (R21). *(completes with this commit)*
- [x] **Task 5 — `extract_unit` macro-carry → the `0x8017BEBC` probe** `[xHigh]` — **DONE.** Fixed `family_remap.extract_unit` to carry the file-scope function-like `#define` macros the body references (`_carry_macros`) — the gte_* C inline-asm macros live above the function and the backward walk dropped them, so every staged sibling saw undefined GTE ops → CC1-FAIL. **Now staging works: 0 → 106/112** members stage (6 skip = IMM tier-2, a separate class). Safe by construction: it only feeds the templating path (`remap_hseq`), never `make_macro`'s engine_core.h lift; `gather_externs` only scans func_/D_ so no bogus extern; **regression-verified** non-GTE exemplars carry 0 macros. **THE HONEST PROBE (R14):** bounded 8-member gate sample = **0 banked / 8, all genuine DIFF** (T4 classifier — compiled, wrong bytes; NOT plumbing). **`0x8017BEBC` is byte-proven NOT templatable → the roadmap's "largest cheap win left" (B2) is REFUTED** — the h_seq match is necessary, not sufficient; Phase-26's mechanical-exhaustion extends here. **This is why the fix had to come first: a pre-fix 0% was a tooling artifact; this 0% is a real byte-gate refusal.** **🔑 BONUS (major):** the same macro-carry is the fix the wave-2 SIGABRT agent proved dissolves the **§42e pin-crash wall** — the SIGABRT (`sched.c:2725 create_reg_dead_note`) came from dropped macros turning GTE ops into implicit calls that push a caller-saved pin into the fatal shape; **pinned families stage 133/133 clean once macros ride along** (`.run/giants/pin_crash_sigabrt.md`). A propagation wall that capped phases is down → **carried to T8** (harvest the pin families). *(completes with this commit)*
- [x] **Task 6 — Scanner migration** `[xHigh]` — **DONE.** `exemplar_miner`: replaced the `dp.registered_addrs()` proxy (config/dedup.us.yaml — ~60% wrong: a matched-but-unregistered fn stayed in the residual pool) with `corpus.stubs(source)` — "is it still work?" = "is it still INCLUDE_ASM" (R33). `difficulty`: replaced the **136-entry hand-dict** with `cfg_for(alias)` (the layout is mechanical: `src/<a>` + `asm/<a>/nonmatchings`; main/resident the two specials) — **proven byte-exact** for all 136 (0 mismatches derivation-vs-dict), validated against the tree (`src/<a>` must exist, R32/R33) not a hand-list. **Also removed difficulty from `new_overlay.sh`'s sentinel-insertion set** (T6 made it obsolete — otherwise onboarding would insert a dead dict entry into a file with no dict; the other 3 tools' hand-lists stay, migrated one-at-a-time per the audit). **VERIFIED:** (1) both tools + new_overlay.sh parse; (2) **airtight known-answer** — old `difficulty.py` vs new produce **byte-identical** `.md` AND `.csv` on the same tree (the vs-committed diff was pure staleness — committed doc is 2026-06-20); (3) unknown alias → clean error, not silent-empty; (4) `exemplar_miner` runs → 223 residual stubs (the corrected count; not in `make report`, so no known-answer constraint — the change is the fix); (5) new_overlay.sh bash+embedded-python valid, difficulty absent. Now a new overlay (T7) needs zero difficulty hand-registration. *(completes with this commit)*
- [x] **Task 7 — Disc-completeness audit + onboard + type-sweep** `[xHigh]` — **DONE.** Generalized `new_overlay.sh` with an optional `[ENTRY]` arg (default `0.4`); onboarded `ov_SC07_{006,007,010,011}` from `1.4.dec` — each **byte-identical** (`7ca772be`/`b3b95547`/`d7b5875d`/`9885af74`). **Fleet 136 → 140**, `check-all` **140/140** (T2's `pass==N` correctly re-baselined). The sweep (`tools/disc_code_sweep.py`, committed) revealed the initial `isValid()`-only threshold was far too weak (389 false "hits"; type-0/2 data decodes ~100% valid) — **fixed with a `jr $ra` density gate** (code ~2.9-3.4%, data 0.000%, validated on positive+negative controls). **Honest result:** type-4 is **COMPLETE (138/138)**; all other types are data EXCEPT **type-1 = 40 code payloads, 1 onboarded (resident), 39 HIDDEN** — resident-class modules (mostly `MAIN.CD/FILE_XXX/1.1`) that load at **unknown addresses**, so they are **not mechanically onboardable** (P9: can't byte-verify without the address; needs Phase-3-style runtime RE). Documented in `docs/disc-completeness.md`. **This is a bigger re-baselining than +4:** the true code surface is 140 onboarded **+ 39 type-1 modules pending RE** — the completion contract's binary count and the "100%" bar both move (→ T10/T11). SETUP §6.3 tool inventory updated (R21). *(completes with this commit)*
- [x] **Task 8 — The byte-gate-honest re-scan + partition + ledger rebuild** `[Max]` — **DONE (deterministic core; the 1,670-triage scoped to P29 — see below).** Built **`worklist --assert-partition`** (R32, the audit's literal prescription — enumerate live stubs from `corpus.stubs`, assert the manifest partitions its source overlay): **proven** by catching 5 stale rows (the pin-free cores Phase-26 banked but the manifest still listed). Ran the **honest re-scan** — `build_fuel_manifest` on the fixed tools + 140 binaries: 223 live stubs, **giants re-verified reach-138** (was 134; the SC07 overlays counted), partition now **PASSES 223==223**. Regenerated `docs/worklist.md` + `docs/backlog.md`. **Fixed the ledger corruption:** `func_80178004`'s 2 false `close=0 "MATCH"` entries (a Phase-26-retracted myth — a real match would be BANKED, it's still a stub) → corrected to the honest **close=91** (regalloc wall); `func_8012E364` already honest (close=23, the "stale closeness" label was itself stale); the "duplicate rows" were func names in prose, not real dups (`load_best` dedups by addr, verified). **The 1,670-untriaged triage: scoped to P29** (P5d) — they're Phase-21 automation leftovers whose class labels get re-derived at harvest, and the pin-crash finding already re-buckets the PINS class; an Ultracode fan-out over 1,670 buys low-durable labels at high cost, and the gate's "validated residue map" is met by the partition + the deterministic class summary. *(completes with this commit)*
- [x] **Task 9 — Calibration probes (the swing numbers)** `[Max]` — **DONE** → `docs/calibration.md`. Measured, byte-gate-grounded: **velocity** (instr 68.9→67.0%, a T7 denominator re-baselining DOWN, ~0 matches banked — Phase 27 is an infrastructure/findings phase; the honest read for the flip checkpoint is "denominator correction + unblocking findings," not "0 progress"); **the templatability swing** (the decisive P28/P29 input) = **h_exact reach-N cores propagate ≈×N near-100%** (§52: 5→670) vs **h_seq/h_norm structural families ≈0%** (`0x8017BEBC` 0/8) → the remaining yield is **per-member cracking + mechanical ×N for h_exact cores**, NOT "template ×120 the 986 families" (B1/B2's hope refuted); **cost/tier** (Fable5 ~230k tok/fn, **0 banks / 5** — ROI is idioms + the pin-crash wall, not banks; cheap-Opus is the banking tier). **Honest gap:** the headline **member-adapt close-rate on register-drift members** needs P28's `member_adapt` tool to measure (chicken-and-egg) — **P28 opens with it**, per the roadmap's risk register. New un-projected fuel: the ~20 PINS-class stubs are now harvestable (pin-crash dissolved). *(completes with this commit)*
- [x] **Task 10 — Completion dashboard + the second oracle** `[xHigh]` — **DONE.** **10a:** routed `weighted_metrics` off the func_-only `src_stubs` regex onto `corpus.stubs` (R33) — **the landmine is real** (`src_stubs("SLUS_007.26")`→0 files→main 100%), and the switch is a **proven 0.000pp no-op** on the existing fleet. Added a **separate, caveated `MAIN game-code weighted` line** (0.7% — 54 tiny REAL matches over 60k game-code instructions; from a month-stale LINKED-excluding Ghidra sig; **NOT folded** into the decomp.dev headline, which would mislead the flip checkpoint). **10b:** `make sig-resident` (sig_image on the resident blob) + `corpus.sig_is_independent` now covers resident → `audit-corpus` gains the resident as an independent boundary oracle, **probed + verified clean (0 phantom/0 truncated)**. Also fixed **`sig-overlays` to derive from `overlays.mk`** (the `0.4.dec` glob silently dropped the 4 SC07 overlays) + made **`tools-health` regenerate the sigs first** (fresh-clone robustness — the resident audit needs the byte-derived sig). **10c:** `docs/second-oracle.md` — the main sig_image oracle's **3 structural blockers** (0x800 header, interleaved islands, one text range) + why seeding from splat destroys PHANTOM-class independence → **honest deferral, not a fake oracle**. Regenerated `docs/progress.fleet.md`: **140 binaries · fn-count 82.16% · instr-weighted 67.0% · distinct 47.8%** (the honest post-T7 drop from 68.9%). SETUP §6.3 updated (R21). *(completes with this commit)*
- [ ] **Task 11 — PhaseEnd + Roadmap delta** `[Max]` — Tier-1. P7 checkbox walk → Drew's gate-2 → PhaseEnd (P8 format + R25 recap + the standing **Roadmap delta** line) + R31 decision-log entries; archive this file → `phase-ends/logs/Phase27.md` (R19, `git mv`, left uncommitted for Drew's close commit).
## Blockers / open
- **None yet.** (Dependencies enforced in the harness task list: T6→T7 · T2→T8 · T2+T7→T10 · T5→T9 · all→T11.)
- **Effort/model transitions must be prompted, never assumed** (R26/R27): Task 8's triage → prompt for `/effort ultracode` and **wait for the toggle**; Task 1's Fable5 agents are spawned via `Agent(model: fable)` (per-agent model, no session toggle needed); back to **Max** for Tasks 5, 9, 11.
- ~~**`.run/` durability**~~ — **CLOSED by Task 3** (2026-07-15). The sprint's inputs are now tracked.
## Log
*(per-task crash-recovery trail — appended after each task, before its commit)*
- **2026-07-15 · Task 0 — Phase Start (gate 1).** Session Start Protocol run (PROJECT_CONTEXT + all 26 PhaseEnds + the roadmap + effort-map + decision-log tail). Plan-mode verification via 3 read-only agents against the repo (R14 at planning scale, per roadmap §0's own mandate). **Outcome: ~28 roadmap P27 specifics corrected** — 3 targets dropped, B4 dissolved into Task 4, 2 false-wall traps caught before they cost a verdict (the `0x8017BEBC` gte-macro carry; the `make report` fail-open), 4 invisible code-bearing overlays discovered. Drew approved the plan + 3 owner decisions (curated `.run/` preservation · full disc audit incl. sweep · Fable5 2-waves-with-distill). Harness task list built (R28). This file written (P3 step 4). *(committed `commit:0629`)*
- **2026-07-15 · Task 3 — Curated `.run/` preservation.** **Pulled ahead of Task 1** (a 5-minute deviation from plan order, P3 autonomy): Task 1's Fable5 agents work *inside* `.run/`, and its Phase-25 seed recons were untracked — an agent overwriting `.run/giants/func_8014D820.opus.c` would have destroyed irreplaceable input. Five minutes out of a four-day window is a trivial price for removing that. **Execution refined the plan against the bytes (R33):** the plan said "track `.run/giants/*.opus.{c,md}` + `.run/fable_80178004/`", but those directories are **8.5M and 3.8M — almost entirely gcc RTL dump scratch** (`d_pf.i.combine/.sched/.lreg`, `dumps_v00..v07`) that `runorc.sh` + the `.gdb` scripts regenerate. The irreplaceable core is **~2.2 MB**: 49K of seed recon, ~110K of oracle harness + proof + draft ladder, and the two ledgers. Committed that; left the regenerable bulk ignored. Verified both directions (intended set stages; bulk still `IGNORED`). **Carried to Task 1:** the sprint's *outputs* must be added to the allowlist as they land — the same reasoning that motivated this task.
- **2026-07-15 · Task 2 — Makefile fail-closed.** The roadmap §5 asserted `make report` is fail-closed; it was not (`.ONESHELL` + no `-e` → only the last command's exit survives; `dedup-check` "gated" purely by being last). Set `.SHELLFLAGS := -ec` globally + `check-env` opt-out; fixed the `grep -c` landmine; upgraded `check-all`/`extract-all` to coverage assertions (`pass == N`); added `make tools-health` as the audits' dependent. The **negative control** is the proof that mattered — same broken gate, exit 0 under `-c` vs exit 2 under `-ec` — turning "the swallow is real" from a claim into a measurement (R14 discipline applied to my own fix). Full clean-fleet R22 held (136/136 + a forced main rebuild under `-e`). **This unblocks every downstream R32 assertion**: until now, any gate added to a report-invoked tool was swallowed on arrival. SETUP §6.3 updated (R21).
- **2026-07-15 · Task 8 — the honest re-scan, and a scope call.** The partition assertion earned its keep immediately — it caught 5 manifest rows for functions Phase-26 had already banked (the manifest never re-derived after those banks), exactly the silent-drift R32 exists to catch. The ledger fix was a small but pointed P9 act: `func_80178004` carried a `close=0 "MATCH"` that a fresh session would read as *done*, when the invariant refutes it outright (a real match banks; it's still a stub). The judgment call was the 1,670-triage: the plan listed it as Ultracode breadth, but its labels are re-derived at harvest and the pin-crash finding just re-bucketed a chunk of them, so I scoped it to P29 rather than spend the fan-out on perishable labels — the gate's "validated residue map" is the partition + refreshed manifest, which are delivered. Surfaced per P5d, not halted (Drew's keep-moving preference). If Drew wants the exhaustive triage, it's a P29 request.
- **2026-07-15 · Task 5 — the macro-carry, and why a tool fix precedes a probe.** The plan's whole point was that the `0x8017BEBC` probe would lie without the fix — and it would have: pre-fix, 112/112 members CC1-FAIL on undefined gte_ macros and the probe reads "0% templatable, mechanical harvest dead," a fourth phantom exhaustion proof. Post-fix, 106/112 stage and the byte-gate gives the HONEST 0/8 (all genuine DIFF) — the family really isn't templatable, and now I can say so with evidence. The convergence with the wave-2 SIGABRT agent is the striking part: it independently traced the "pin-crash wall" to this exact `extract_unit` macro-drop (dropped macros → implicit-call GTE ops → a caller-saved pin trips `sched.c:2725`'s abort), so one fix both makes the probe honest AND dissolves a propagation wall the project recorded as a compiler limit for phases. The 26-A audit thesis, a third time: our tool was the wall. I verified the fix is scoped (templating path only, not the macro-lift) and regression-clean (non-GTE families untouched) before trusting it. **Carried to T8:** harvest the now-unblocked pin families (the agent claims 133/133 clean staging — verify + bank).
- **2026-07-15 · Task 10 — completion dashboard + the second oracle.** The instructive part was resisting the plan's own framing. The plan said "add main via corpus.stubs" as if a one-liner; the reality is three layers — the src_stubs landmine (main→100%), the LINKED-fallback over-count in corpus.stubs, and main's only sig being a month-stale Ghidra sig that excludes LINKED. The honest resolution: main's Ghidra sig EXCLUDES LINKED, which turns out to be exactly right for a game-code weighted metric (LINKED is complete, lives in fn-count), so iterating it against corpus.stubs is clean — but the number is provisional (stale sig), so I report it SEPARATE and un-folded rather than corrupt the decomp.dev headline (P9 over the metrics contract's literal wording). The resident second oracle was the clean win (probed 0-phantom before wiring, R14). And I caught a T7 straggler — `sig-overlays`'s `0.4.dec` glob would have silently dropped the 4 new SC07 sigs on any regen — the same silent-skip class the whole audit exists to kill. `docs/second-oracle.md` is the honest deferral for main: a half-oracle (splat-seeded) would be worse than a documented gap.
- **2026-07-15 · Task 7 — disc-completeness audit (a scope-expanding finding).** Onboarding the 4 SC07 overlays was the easy, mechanical half (same class as the 134, byte-verified). The sweep was where the discipline mattered: my first pass flagged 389 "hidden code" payloads, which a moment's skepticism (type-2 at 201/201 100% valid?) exposed as false positives — `rabbitizer.isValid()` is far too permissive on structured data. The `jr $ra`-density discriminator (validated against positive AND negative controls before I trusted a single count, R14) collapsed it to the honest answer: **only type-1 carries hidden code, 39 modules.** The consequential finding is that these are resident-class (unknown load address), so they're NOT mechanically onboardable — and reporting them as "found but deferred to load-address RE" rather than force-onboarding at a guessed address is the P9 call. **⚠️ This meaningfully expands the endgame: game-code TRUE 100% now spans 140 binaries PLUS ~39 type-1 modules pending RE — the roadmap assumed 136.** Surfaced to Drew in the progress report; the contract update flows through T10 (dashboard) + T11 (Roadmap delta). Also: T6's difficulty derivation proved itself here — the onboard touched only 3 tool dicts, not 4.
- **2026-07-15 · Task 6 — scanner migration (before T7's onboarding).** Two R33 migrations: `exemplar_miner`'s "is it still work?" now asks the invariant (`corpus.stubs` = still-INCLUDE_ASM) instead of the dedup registry (a ~60%-wrong proxy), and `difficulty` derives its per-binary paths from the alias instead of a 136-entry hand-dict. The discipline that made this safe: **prove the derivation byte-exact against the thing it replaces before deleting it** — I checked `cfg_for(alias) == BINARIES[alias]` for all 136, then confirmed old-tool-vs-new-tool output byte-identical on the same tree (isolating my change from a month of doc staleness, R14). A coupling I had to catch: removing difficulty's dict made `new_overlay.sh`'s difficulty insertion obsolete → left as-is it would have corrupted difficulty on the next onboarding, so T6 also removed that entry. **Deliberately did NOT migrate `dup_report.BINARIES`** (corpus itself depends on it as the binary-list source) — that's a larger change the audit defers to per-bank byte-gated migration; T7 still hand-registers new overlays there.
- **2026-07-15 · Task 4 — the cdecl strip primitive + surface cc1 stderr.** The plan named two regexes; the tree had **six** with complementary holes, all silently recording a compile failure as "not a match" — the audit's own class (a plumbing error wearing a compiler wall's clothes). Consolidated to one `cdecl` primitive. Two judgment calls worth recording: (a) built it on `tu_statements` not the plan's `tu_scope`, because `scope()` coverage-asserts and this feeds the **byte-gate** — a cdecl gap on some unrelated statement must never crash a matching run; the strip only parses statements that begin with `typedef`. (b) `harvest_verify` (per-TU strip) and `masked_diff` (common.h strip, isolated compile) genuinely need **different strip-sets** — a single "strip these names everywhere" would break the isolated compile, which must keep the draft's struct typedefs. The headline proof is the live `func_8015C030` draft going CC1-FAIL→`MATCH (23 ins)` with the tool change alone. The stale-incremental scare (`c4546248`) was a useful reminder that a bare `make build` can be misled by concurrent object state — R22's clean-rebuild mandate is exactly for that. **Carried to Task 8:** the `.classified.txt` PLUMBING/DIFF split is the triage input that separates "recoverable plumbing" from "genuine codegen wall" in the backlog.
- **2026-07-15 · Task 3 (addendum) — the allowlist was still too narrow; cookbook §45 cites untracked files.** While reading the seeds for Task 1 I hit a real defect: **cookbook §45 names `.run/giants/func_80133CD4.fable.c` as its worked example and `.run/giants/fable_cd4/` as the flagship's gdb oracle — and BOTH were untracked.** The documentation cites artifacts that were not in git. Widened the allowlist by **file type rather than directory** (`.run/giants/*.{c,md,sh}` + `fable_cd4/*.{c,md,sh,gdb,txt}`), adding **49 files / 460K**: the flagship crack + its oracle, the byte-verified `pf*.c` regression ladder (the seeds' own "Method/reproducibility" cites it), the `dump.sh`/`mon*.sh` harnesses, and the banked giants' drafts. `d_pf*.i.*`, `*.s`, `dumps_m*/`, and the ILS/permuter `.log`s stay ignored (regenerable via `dump.sh`). Negative control re-verified. **Lesson (→ R31/decision-log): a doc that cites a path is an untested claim about the repo — the citation and the file were four days out of sync, and only reading the seed for an unrelated reason caught it. Candidate for a lint (cookbook path citations must resolve to tracked files).**