# 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//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/` + `asm//nonmatchings`; main/resident the two specials) — **proven byte-exact** for all 136 (0 mismatches derivation-vs-dict), validated against the tree (`src/` 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).**