# CURRENT_PHASE — Phase 35: Gen3 opens — the dedup phase, "one source per unique function" (v2.0.0 → v2.1.0) > **Gate 1 approved 2026-09-08 (Drew, plan mode, Max, Fable 5.1; session S94).** Rules **R96–R99 ratified at gate 1** (the Phase-34 > candidates (a)–(d); binding; full text in `phase-ends/DIGEST.md` §3). The approved plan is reproduced VERBATIM at the end of this file > (§"Approved plan") — its `~/.claude/plans/` copy is not part of the repo. **Gen3 order (Drew, S94): dedup → pins → structs → names, > one phase each, planned one at a time; this phase is dedup only.** Gen3's charter: `docs/gen3-handoff.md` + `docs/gen3-standards.md`. > **Baseline HEAD at open: `48170fd7f`** (Drew's Phase-34 CLOSE commit = v2.0.0; tree clean; `origin/main == main`). > **Build inputs change in this phase (every shared body moves): R22 is owed after every batch that touches `src/`** — the clean fleet run > `make clean && make extract-all JOBS=16 && make check-all JOBS=16` → `check-all: 218 passed, 0 failed of 218`, read by exit code (R97). > **The 2026-09-02 "leave the dedup backlog" decision is REVERSED at this gate** on evidence read from sotn-decomp's tree (X2): sotn shares > stage code once as plain C in `src/st/.h`, instantiated per stage by a `.c` stub that `#include`s it; it does not write duplicates. ## Milestone (gate 2 — what Drew confirms, each with its literal output) 1. `git grep -c '^#define DEFINE_func_' -- src` empty; no `DEFINE_func_X()` site; `src/shared/engine_core.h` absent; every registered body a plain-C header under `src/shared//`. 2. `tools/share_census.py --check` exit 0: same-vram duplicate copies 0 (or each ledgered with a reason in `config/dedup_exceptions.tsv`); the five twin overlays built from one source directory each; cross-vram classes published as a deferred count. 3. `make tools-health` OK with the S1 invariant strict and the macro-form guard; every consumer updated, frozen or retired per its dictionary row. 4. `make clean && make extract-all && make check-all` → `218 passed, 0 failed of 218` (R22). 5. README/wiki/kit regenerated (R75), decision log (R31), SETUP rows (R21), `PhaseEnd_Phase35.md` + DIGEST written; v2.1.0. ## Effort / model (R7/R26/R27 — every transition is PROMPTED, never assumed) - **Max** for T0's probe, T1, T2's design, T3's probe pair, T4's and T5's tool, T9 (Tier 1 — prompt Drew before starting the close); **xHigh** for the mechanical runs (T3's other pairs, T4's batches, T5's batches, T6, T7, T8); **Low** for T0's bookkeeping. Max is session-only — ask Drew to re-apply `/effort max` at each session start. **No Ultracode anywhere** (nothing is agent-breadth; the parallelism is machine parallelism: L0 at JOBS=16 ≈ 13 min fleet-wide, the clean fleet run 3–5 min). - **Drew-only (R6):** every `git push`; the gate-2 confirmation; the close commit + tag. Claude commits per task (R42 for banks: the moment a batch is green, before the next command that can touch `src/`). ## Tasks (plan order; one commit each; ☐ → ☑ with the verify line quoted in the log) - ☑ **T0** — Open + ground (S94): this file; DIGEST §0/§3 (R96–R99); `.gitignore` `.run/P35/`; the R22 baseline from clean `check-all: 218 passed, 0 failed of 218` in **157 s wall**; `make tools-health` **OK** (exit 0, 474 s — after two red runs fixed at their cause: the kit's record copies regenerated by `make kit-corpus`, and R96–R99 dispositioned in `config/kit_coverage_map.tsv`); the probe on ov_SC06_033: **34/34 objects byte-identical** in the include form, the binary `BYTE-IDENTICAL` both ways, build 1.12 s → 0.52 s wall (CPU 12.7 s → 5.7 s), warnings 801 → 663 (all 137 macro-redefinition warnings gone), `.d` 11.6 KB → 182 KB (`.run/P35/probe/probe_ledger.txt`). - ☑ **T1** (S94) — `tools/share_census.py` + `config/dedup_exceptions.tsv`: `selftest: 7/7 verdicts correct`; `362,389 sig instances · 362,389 classified · 0 UNACCOUNTED · 10,180 h_exact classes`; the four controls as measured (see the log); SETUP + dictionary rows. - ☑ **T2** (S94) — the health chain learns the header + twin forms while the macro form still builds (16 tools; the source-dir oracle; `share_census.header_defs` the one reader). Negative control on the unchanged tree: the chain's substantive rungs green (audit-binaries OK · dedup-check 2220/0 · cdecl · report + `progress.py --check` fresh · doc_links · wiki_render · kit_lint · cookbook-index · gccmap_cites · ghidra_roster), one red rung — the kit's verbatim copies of the edited tools — fixed by `make kit-corpus` (17 copies) with the rungs after it re-run individually by exit code. The +7 count correction published. - ☑ **T3** (S94) — twin binaries → one source directory: the five pairs collapsed (probe SC01_005/006 with the race test; SC03_118/119 + SC02_000/003 equal carves; SC04_018/019 + SC03_014/015 with the primary's carve, interleave + pads regenerated, R60 checks), each twin and primary BYTE-IDENTICAL, 166 source files deleted; the census: same-vram backlog 4,667 → 1,099 classes; the clean fleet run after the last pair (see the log). - ☑ **T4** (S94) — `tools/macro_to_header.py`: 246,347 sites in 3,818 TUs → 2,215 per-function headers under `src/shared//` (213/213 binaries and 4,121/4,121 objects byte-identical), the legacy headers converted (clearTbl40 = the parameterized control), the whale moved, 7 alias bodies bound, the registry text-edited, `engine_core.h` deleted; `--verify OK`; R22 `check-all: 218 passed, 0 failed of 218` in 145 s. - ☑ **T5** (S94–S96) — `tools/share_body.py` (+ `--repair-registry`, `--reexemplar`, `share_body_cycle.sh`): bucket 0 183 classes → 135 shared / 48 ledgered; bucket `new` 915 → 914 shared / 3 ledgered; S1 10,180/10,180 satisfied, 0 violations; registry 2,220 → 3,135 groups; same-vram backlog 1,099 → 51 classes (= the ledger); R22 218/218. Recovery history (S94 died mid-task): `tools/share_body.py` built + probed (commit `0bccef901`); bucket 0 (`--bucket extend`, the registered-incomplete classes: 183 at the start) run twice — the first pass committed (`571374b97`: 788 members added to the registry, 141/141 + 146/146 binaries green per binary), the second run finished after the session died and its output (170 sites → include in 38 TUs of 8 overlays, 55 TU-CONFLICT ledger rows) is UNCOMMITTED on disk. Residue: 55 classes / 325 (class, binary) pairs stay private, 317 of them still LISTED as registry members (the first pass extended wholesale); three tool defects found by S95 (the cause extractor, the cross-batch edit loss, the ledger reason). NEXT inside T5: commit the run-2 bank → fix the tool → repair the registry → replay the suspect rejections → decide the E_func_80168B70 exemplar → bucket `new` (915 classes / 3,567 private sites) in bands, one batch per run, R22 after each. Plan text (unchanged): bucket 0 `--extend`, then the same-vram buckets largest reach first (no trivial exception); cross-vram classes untouched; `share_census --check` same-vram unregistered = 0 or ledgered. - ☑ **T6** (S96) — consumers: **14** macro-era tools FROZEN (`tools/frozen.py`, main()-time refusal; the plan's 7 + 7 the guard census found), **4** retired to `tools/sunset/` (dedup_propagate, dedup_extend → share_body.py; macro_draft; test_reconcile_ledger), 12 live tools' dead macro branches dropped, the `ast` macro-form guard in `tool_census --check` (0 LIVE hits; the pre-T4 tree flags 15 — the negative control), `progress.py`'s empty-shared fold corrected (+459 denominator, REAL −10,211 → EMPTY), kit corpus, SETUP; `tools-health: OK`. - ☑ **T7** (S96) — S1 strict (`--strict-macros --strict-text`) + `--selftest` in `make tools-health`; C2c/C2d in `dedup_integrate --check`; `progress.py` fields (105,007 bodies written once; 160 / 51 duplicate copies, all ledgered) + the dated corrections (+7, +459, REAL −10,211) + the README sentence; the gate negative-controlled in place (exit 1 naming the class; C2d naming the member); the second oracle's finding published: 380 texts deferred inside cross-address classes, 38 texts / 2,030 sites byte-variant — PENDING Drew. - ☑ **T5b** (added S96, Claude's delegated decision; done S96 — 38 groups / 2,030 sites, 138/138 green, R22 218/218) — the text tier: registry `tier: h_text` (text hash; per-member `h_exact` in the verbose member form), `dedup_integrate` C1 per member; `share_census` text classes at one address (same text, ≥2 distinct TUs, outside the deferred/ledgered sets) → the S1 text half a violation, not PENDING; `share_body --bucket text` (header named by the text hash) over the 38 classes / 2,030 sites, gated per binary, one batch per run + R22; the two counts (deferred 380/1,668; text-tier shares) in the digest + README sentence. Effort: high (Drew's default). - ☑ **T8** (S96; doc_links strict 0 broken, wiki 32/32, cookbook §453 + index, decision log, accelerators, DIGEST §4, the memory) — the record: wiki (4 pages), how-to ch.10, README:117, the charter rows as dated snapshots, the cookbook section, decision log (R31), accelerators, DIGEST §4, sunset rows, the memory rewritten; doc_links/wiki_render/cookbook_index/kit_coverage green. - ☑ **T9** (S96, xHigh by Drew's choice) — close (Tier 1): R22 → 218/218; tools-health OK; the metrics table; the reviewer sequence; PhaseEnd + DIGEST + log archived; v2.1.0. - Rules check (P6): after T3 and after T7. ## Decisions (owner's words, in order) - S94 gate 1 (AskUserQuestion): twin binaries → "One source directory per payload"; cross-address classes → "Census + defer to the names phase"; the 62 macro-era tools → "Freeze with a loud refusal"; the four rule candidates → "Ratify all four as R96–R99". - S94 (plan): no "trivial" exception — a duplicated 3-instruction accessor is still one function (this project already shares 5-instruction bodies). - S94 (Drew, mid-planning): "we will need to update our tooling to be aware that we aren't duplicating funcs across overlays anymore and that there is only one source for a unique func" → the S1 invariant + the consumer tasks (T2, T6, T7). - S95 (Drew, 2026-09-08 evening — the recovery session): "this is a recovery session. last session context filled up and didn't write a checkpoint … read last session since the last checkpoint and write an updated checkpoint"; "dont run anything like gates/builds, your job is only to capture the info from the session and create an updated checkpoint." → S95 ran no gate, build, census or tool; it read the S94 transcript (`~/.claude/projects/-home-musashi-bfm-decomp/e902c34e-e4b3-41a6-b1e4-7d2ef019a371.jsonl`), the two T5 commits, `.run/P35/share/` and the dirty tree, and wrote the log entries + the 🛑 block below. - S96 (Drew, 2026-09-08, after the E_func_80168B70 question): "I am not sure the best answer to this question. I have toggled Max effort. now decide the best answer to the question. and then pause so I can switch back to high effort" → **Claude decided at Max: RE-EXEMPLAR the header from the majority text** (the tool's own exemplar rule; T4 inherited the 7 late overlays' minority text because the registry group had been created for them; the majority's cast-at-call form compiles under BOTH declaration environments, so 141/141 is expected with no TU edit, and 7 private copies would beat 134 if not). The offered alternative "fix the 7 TUs' declarations" was mis-stated — the header passes one argument, so the TU-side repair would be the 134 units + every other caller of func_80146C3C = Phase 37's canonical-declaration work; rejected. **Policy for the other 48 rejected classes:** their headers already carry the majority text and their causes are genuine declaration conflicts in the late overlays' units → they stay ledgered TU-CONFLICT with the real diagnostic until the types phase (R95); ≈190 private copies of ≈3,900 collapsible, inside the plan's 2–5 % budget (exact count at T5's close). - S96 (Drew, after the T7 report): "Max effort set for this decision call. you review the information and decide what is best, make the decision, and then pause" → **Claude decided at Max: T5b NOW for the 38 byte-variant same-address texts (a text tier), DEFER the 380 inside the cross-address classes.** The normalizer masks only the function's own name, so the 38 are the same C; their bytes differ per overlay because the ORIGINAL builds compiled that source under per-overlay declaration environments (our TUs carry that environment) — the types phase cannot collapse them and the names phase cannot remove them; the include-at-site form already fits (body in the header, declarations in the TU, bytes proven per binary) and only the registry's single-hash group blocks it. The 380 are identical bytes at thousands of addresses (empty bodies, tiny accessors): one header per address would be undone by the names phase's parameterized form — gate 1's deferral stands; both counts are published. A plan change (P5d) under Drew's delegation: **T5b inserted before T8.** ## Log (append-only; one entry per step, with the literal verify line) - **S94 2026-09-08 — session start.** Load order read; Phase 34 closed at `48170fd7f`; no CURRENT_PHASE.md → new phase. Drew: order dedup → pins → structs → names; plan mode at Max. Exploration (two Explore agents, one Plan agent, ~680k agent tokens) + this session's own measurements; sotn's sharing model verified from its tree (`src/st/e_red_door.h` + the ~90-byte per-stage stubs). - **S94 — T0 in progress.** DIGEST §0 (the opening paragraph) + §3 (R96–R99 in full) written; `.gitignore` `.run/P35/` allowlist added; the R22 baseline from clean launched in the background (`.run/P35/baseline/r22_open.log`, `/usr/bin/time` wall clock recorded); the harness task list built (10 tasks, R28). - **S94 — T0 baseline.** `.run/P35/baseline/r22_open.log`: `extract-all: 217 extracted, 0 failed of 217 (+ main, serial)` · `check-all: 218 passed, 0 failed of 218` · `wall=157.09 s user=2231.42 s sys=542.99 s` · `exit=0`. The fleet's build-time baseline for the phase (the 8.8 MB header is preprocessed by every overlay TU today). - **S94 — T0 tools-health, run 1 RED (464 s):** `tool_census --check: FAIL` — 2 GAPs, both "corpus copy differs from its source" (`decomp-architect/corpus/record/phase-ends/DIGEST.md`, `…/PhaseEnd_Phase34.md`). Cause: the gate-1 DIGEST edit (and a pre-existing drift of the P34 record copy behind Drew's close commit); the instrument was right (R40). Fix: `make kit-corpus` (360 copies + 28 pointers materialised) → `tool_census --check: OK` (`.run/P35/baseline/kit_corpus_open.log`, `tool_census_open.log`). - **S94 — T0 probe** (`.run/P35/probe/probe_convert.py`, in-tree then restored by `git checkout -- src/ov_SC06_033`): `engine_core.h: 5147 define lines, 3516 distinct, 1631 defined twice` · `ov_SC06_033: 34 TUs, 1813 sites, 1813 distinct shared bodies` · `applied: 1813 headers under src/shared/ov, prelude written, 34 TUs rewritten` · A rebuild (macro form) `wall=1.12 s user=12.72 s`, 801 warnings (137 "redefined") · B build (include form) `wall=0.52 s user=5.70 s`, 663 warnings (5 "redefined" — none of them `DEFINE_func_`) · `sha1 1e91d46e… == config/check.ov_SC06_033.sha (BYTE-IDENTICAL)` both ways · **`obj A/B: 34/34 byte-identical, 0 differing`** · `.d` bytes 11,632 → 182,252 (1,813 header dependencies; harmless) · restore verified (`git status` shows only T0's files). The L0 object oracle is proven on a whole overlay; the plan's D6/L0 stands. - **S94 — T0 tools-health, run 2 RED (460 s):** `kit_coverage: FAIL (4 gap(s))` — `rule R96…R99 is neither cited by a registry provenance line nor dispositioned in config/kit_coverage_map.tsv` (R92, the same class P34 hit at its close). Fix: four map rows — R96/R98/R99 → DK-81 (its facts 4/1/2 ARE those rules), R97 → G29 (provenance R49 + R53). `kit_coverage: OK`; the rungs after it (xsig 8 OK, work_evidence selftest OK, split_indicator SELF-TEST PASS + 218 OK) individually green. - **S94 — T0 tools-health, run 3 GREEN:** `tools-health: OK — sigs fresh; corpus(+resident) + cdecl + binaries + report(lint+dedup) + cookbook-index all green.` `exit=0`, `wall=474.23 s` (`.run/P35/baseline/tools_health_open3.log`). `docs/story-timeline.md/.svg` regenerated by the chain (74 rows; the v2.0.0 tag row). **T0 ☑.** - **S94 — T1 `tools/share_census.py` + `config/dedup_exceptions.tsv`.** Built as designed (one pass per TU with comments, dead `#if 0`/`NON_MATCHING` halves and macro-continuation text masked; forms macro / macro-param / include / param-include / def / stub / asm-verbatim; addresses from each binary's symbol stack, never names; the fleet, the source dirs, the contracts (`_CHECK_SHA`, main = `check.us.sha`), the address spaces (`_VRAM_BASE`) and the twin sets derived from the Makefile and the contracts; classes through `dedup_integrate.group_members`). Five scanner defects found by its own self-test and coverage line, each fixed at the cause: string contents were blanked before include paths and asm labels were read; K&R definitions (a blank tail after the last `;`, and the one-line `void f(a, b) void *a; s16 b; {` form); a second definition head on the same line after an `extern …;`; the alias regex spanning a previous macro site's parentheses; `asm(` as well as `__asm__(`; implicit-return-type heads with no type line; `static inline` helpers (no address) excluded from the unresolved list. **Result: `--selftest` → `selftest: 7/7 verdicts correct`; the census → `218 binaries · 362,389 sig instances · 362,389 classified · 0 UNACCOUNTED · 10,180 h_exact classes with >=2 instances`; verdicts A 1,712 · B 282 · C 6,107 · D 1,861 · M 218 (instances 214,478 / 45,226 / 14,839 / 5,796 / 462); flags ALIAS 44 · E 3,826 · F 54 · PINS 687 · TWIN-PENDING 3,748 · TYPEDEF 96; SAME-VRAM UNREGISTERED 4,667 classes · 35,976 instances · 11,767 private copies · 31,309 collapsible · 1,710,469 ins (twin-pending 3,568 classes / 7,136 instances); CROSS-ADDRESS/SPACE deferred 3,801 classes · 30,347 instances · 12,938 private copies; macro sites 255,947; duplicate-text classes 6,845 (23,269 sites); 43 s uncached, 41 s cached (the cache is not the cost — profile at T7); exit 0.** Controls (R39): `func_80144B9C` = B/141/{'include': 141}/missing 7 (the registry lists 134 — never extended to the 7 later overlays; T5 bucket 0), `clearTbl40` = A+E/2, the three setters = B/282(E), B/145(E), B/141 (the same 2-instruction bodies also sit at other vrams), twin symmetry SC01_005/006 = 653/653. **Instrument findings for the record:** the B class is 282 registered-but-incomplete groups (204 never extended, 74 with a private-copy site — demacroized escapes —, 2 with a member the sigs do not show); a 2-instruction empty-body class (`jr ra; nop`) has 11,852 instances across every space (E,F → deferred with the cross-address set; the names phase decides how an empty function is written). Outputs `.run/P35/census/{share_census.json, share_census.txt, coverage_notes.txt}` (tracked), `classes.jsonl` + `cache/` (ignored). SETUP + dictionary rows (R21/R87). **T1 ☑.** - **S94 — T1 slip, named (R97/R66):** commit `1dbffee87` says "kit corpus regenerated" while `make kit-corpus` had exited 2 and `tool_census --check` had refused the new row (`phase=P35` — the column is the KIT LADDER phase, P1–P10, not the project phase); the chain had `&&` on an echo, not on the checks. Fixed in `72a77e7d3` (row → P10, the readability tools' rung; corpus 361 copies; `tool_census --check: OK`; `kit_coverage: OK`), chained on the checks' own exit codes; `docs/tool-index.md` (generated) committed after. - **S94 — T2 the health chain learns the header + twin forms (both forms accepted).** ONE source-dir oracle: `corpus.src_dirs()` / `src_dir()` / `twin_of()` from `_SRC_DIR` / `_TWIN_OF` in the Makefile and `config/*.mk`; `corpus.src_files` and `o0_subseg` go through it; `compile_only.src_dirs` delegates to it; `progress.set_binary` takes its dir from it (the table's `src` is only a cross-check); `dedup_integrate._src_paths` uses `corpus.src_files`. The include form: `share_census.header_defs()` is the one reader (`[(name, empty)]`, masked — a macro-only header defines nothing); `progress.classify` counts an include site as the function's definition (REAL/EMPTY by the header body) with the `#define SHARED_FN` / `#undef` state for the parameterized form, and the dedup fold keeps included members in the shared count (`(members − real − stubs) ∪ (included ∩ members)` → the README's 255,632 unchanged); `overlay_src_split` gains the `include` item kind (anchor by the header's defined name, `#undef SHARED_FN` travels with the item; `split_header` no longer swallows a leading body include; `macro_externs`/`macro_proto` read the header's parts; a macro invocation with no table entry is a loud refusal, R43) and `jr_isolate_all` admits the kind; `dedup_integrate` C2a′ requires a plain-C source to DEFINE `func`; `audit_binaries` accepts `engine_prelude.h`, resolves the main TU through the oracle, and gains CHECK 3b (twin citizenship: primary onboarded and not a twin, same src dir, no `src//`, equal contracts, equal carves); `cdecl.audit_differential` reports "not applicable" when the macro header is gone instead of crashing; `lint_symbol_refs` / `family_remap` / `fix_arity_callers` glob `src/shared/**/*.h`; `blocker_probe.macro_scope` and `demacroize.macro_bodies` tolerate the header's absence; `shared_lock` docstring; `harvest_verify` comment. **Verify:** `py_compile` 16 tools OK; `share_census --selftest` 7/7; `audit-binaries: OK`; `dedup-check: 2220 validated, 0 failed`; the split tool on `src/ov_SC06_033/ov_SC06_033_o0b.c` (a real include-form TU) → the whale's include is an item. **A count correction surfaced (R14):** `FLEET matchable 363,214 → 363,221` — the 7 overlays whose `_o0b.c` includes the whale header but were never registry members (`ov_MAIN_012`, `ov_SC02_037`, `ov_SC03_107`, `ov_SC07_006/007/010/011`) were counted by NEITHER classify (include lines skipped) NOR the registry fold; the source now decides (ov_MAIN_012: matchable 2,401 → 2,402, the known row). `docs/progress.json` + the README block regenerated by `make report BINARY=main` (`progress.py --check: … fresh`); the generated timeline follows the COMMITTED digest, so it is regenerated after the commit that carries the new digest. - **S94 — T2 close.** The chain's only red rung was the kit's verbatim copies of the 16 edited tools (`tool_census --check` 17 gaps) — `make kit-corpus` belongs in EVERY commit that edits a tool; the rungs after it re-run individually by exit code; the chain also regenerates the timeline's commits-per-day cell (it moves with every commit — committed with each task). Commits `6cb056c93` (the tools + the +7 numbers), `4ec752e68` (the timeline), `24e8ff72d` (the close). **T2 ☑.** - **S94 — T3 probe pair SC01_005/006 (Max).** The mechanism: `config/overlays.mk` `ov_SC01_006_TWIN_OF := ov_SC01_005` + `ov_SC01_006_SRC_DIR := src/ov_SC01_005`; the Makefile's twin block (static pattern rules `build/src//%.o ← src//%.c` + the bare-name rule, the same recipe; `TWIN_O0_OBJS` keep `-O0`; the twin's own `OBJS`/`C_DEPS`); `config/splat.ov_SC01_006.yaml` `create_c_files: False` (src_path stays the twin's name → the .ld's 120 object paths under `build/src/ov_SC01_006/`); `git rm -r src/ov_SC01_006` (30 files). **Verify:** `make extract BINARY=ov_SC01_006` exit 0, no `src/ov_SC01_006/` recreated; `make check BINARY=ov_SC01_006 -j16` → `sha1 56760dbe… == config/check.ov_SC01_006.sha (BYTE-IDENTICAL)` (the CC lines read `(twin of ov_SC01_005: src/ov_SC01_005/…c)`); the primary still BYTE-IDENTICAL; **the race test** — both objects trees deleted, `make check` for 005 and 006 run CONCURRENTLY → both BYTE-IDENTICAL; consumers: `progress.py --binary ov_SC01_006` 2503/2503 (of which dedup-shared 1838, unchanged), `dedup-check --binary ov_SC01_006` 1838 validated / 0 failed, `audit-binaries: OK` (CHECK 3b passes: primary onboarded, same dir, no src/, equal contracts, equal carves), `compile_only --list ov_SC01_006` → 30 TUs from `src/ov_SC01_005/` (2 at -O0). One instrument slip caught by the census's R32 gate: my Makefile variable `TWIN_SRC_DIR` matched the `_SRC_DIR` oracle regex as a binary named `TWIN` → renamed `TWIN_SRCDIR`; after it the census shows **TWIN-COVERED 575 classes** for the pair (twin-pending 3,748 → 3,173), twin symmetry 653/653 unchanged. The census's `copies` now counts DISTINCT private sites (a twin's instance resolves to its primary's TU — one source), `collapsible` = copies − 1. Commit `9b0816e74`. - **S94 — T3 pairs 2–3 (equal carves, mechanical):** `ov_SC03_119` TWIN_OF `ov_SC03_118` (31 files removed; both `77ee78dd…` BYTE-IDENTICAL), `ov_SC02_003` TWIN_OF `ov_SC02_000` (37 files; both `5ece4bca…`); `audit-binaries: OK`; dedup-check per twin 0 failed. Commit `e79cfcc06`. - **S94 — T3 pairs 4–5 (carve alignment, R60):** the twin's yaml := the primary's with the alias and `FILE_nnn` substituted (+ the twin note + `create_c_files: False`), its `_JTBL_INTERLEAVE` := the primary's substituted — and, found by the first build's failure (`missing .end at end of assembly` on `ov_SC04_019_jr_8017AE2C.o`): the per-object **`JTBL_PADS` lines are keyed by OBJECT PATH** (`build/src//…`), which my alias-normalized block diff (lines starting with the alias) never compared, so the twin still carried its retired carve's pads (4 differing lines for SC04, 2 for SC03; the three committed pairs re-checked: 0, 0, 0). Regenerated from the primaries by substitution → 0 differing. `pads_audit.py` built `src//.c` by hand and raised IndexError on a twin — now reads the source through the oracle (`corpus.src_dir` + `twin_of`). **Verify:** `ov_SC04_019` + `ov_SC04_018` BYTE-IDENTICAL (`fe9b413f…`), `ov_SC03_015` + `ov_SC03_014` (`d84b01a2…`); `interleave_check` ALIGNED (n=51, n=46); `pads_audit` ok on every carve object; dedup-check 0 failed; `audit-binaries: OK` (CHECK 3b incl. equal carves). Commits `2648aa5a9`, `6ebb3dac3`. - **S94 — T3 census after the five collapses:** TWIN-COVERED 3,748 classes (3,580 non-A, 7,186 instances); **same-vram unregistered 4,667 → 1,099 classes · 4,755 private sites · 3,658 collapsible · 28,840 instances** (twin-pending 0); `S1: … 10,180 classes, 9,081 satisfied (3,580 twin-covered, 0 excepted, 3,801 deferred cross-address), 1,099 VIOLATION(S)` — the backlog T5 shares. The controls unchanged (twin symmetry 653/653). `make kit-corpus` for `pads_audit` + `share_census`; `tool_census --check: OK`. - **S94 — Rules check (P6, after T3 = four tasks): re-read complete (CLAUDE.md's eight mandatory behaviours; PROJECT_CONTEXT's 23 P/G/H/X rules). Continuing with T4.** - **S94 — T3 close, R22:** `make clean && make extract-all JOBS=16 && make check-all JOBS=16` → `extract-all: 217 extracted, 0 failed of 217 (+ main, serial)` · **`check-all: 218 passed, 0 failed of 218`** · `wall=308.78 s` (the census and the kit corpus ran beside it) · `exit=0` (`.run/P35/baseline/r22_t3.log`). Twins: 5 pairs / 10 aliases / 166 source files deleted; every twin builds from its primary's directory. **T3 ☑.** - **S94 — T4 `tools/macro_to_header.py` (Max) + the fleet conversion.** `--plan` on the post-twin tree: `engine_core.h: 5147 define lines, 3516 distinct, 1631 twice (4 divergent asserted); 8 directives — the prelude is complete` · `sites 246,347 in 148 binaries · TUs including engine_core.h 3,818 · macros: shared 1,959 · single-site→header 257 · single-site→inline 0 · dead 1,300` · naming `{'suffixed': 86, 'plain': 1873}`. **`--apply` over all 213 non-twin binaries** (`.run/P35/convert/batch2.sh`: snapshot objects → one apply → per binary `make check` + every object compared): **213/213 BYTE-IDENTICAL, `objects byte-identical: 4121/4121`**, apply ledger `{"sites":246347,"tus":3818,"headers_written":2215,"dead":1300}`, 224 s wall (commit `c53a9e1a9`, 6,036 files). **`--finalize`:** the three legacy sites (`SETTER`/`RETCONST` ×3 in SC01_005 → `ov/func_8012AD64.h` etc.; `CLEAR_TBL40` ×2 in `src/800_c.c` → the `#define SHARED_FN` / `#include "shared/main/func_80037004.h"` / `#undef` form — the cross-address control), the whale moved to `ov/func_80144B9C.h` (guard removed) with every `-O0` includer rewritten, **7 alias-form bodies given their own binding** (`s32 aF80131CA8(int a0) __asm__("func_80131CA8");` derived from the head; the K&R head gets the unprototyped form), the registry's 2,224 `source:`/`func:` lines text-edited by id, the 3 non-shared headers that included a macro header rewritten (`src/800_shared.h`, two per-overlay `_shared.h`), `engine_core.h` + `ov_setters.h` + `clearTbl40.h` deleted; `--verify: OK — 0 macro sites, no macro header, the prelude present`. **Gates:** main `143dbb89…`, ov_SC01_005, ov_SC01_084, ov_SC02_005, ov_SC06_033, ov_SC02_027, ov_SC02_011, ov_SC02_026 and the 7 late whale includers all BYTE-IDENTICAL; `dedup-check: 2220 validated, 0 failed`; `audit-binaries: OK`; the census `362,389 classified · 0 UNACCOUNTED · macro sites 0`, verdicts A 1,712 · B 282 · C 6,640 · D 1,545 · M 1, same-vram backlog 1,099 classes (unchanged — T4 shares nothing new); **R22: `check-all: 218 passed, 0 failed of 218`, wall 145.10 s** (157 s at the open; user CPU 2,230 s vs 2,231 s — the per-overlay cpp saving the probe measured is small against extract, assemble and link fleet-wide). **Instrument findings, each caught by a gate and fixed at the cause:** (1) the first apply of "main" swapped the include line in all 3,818 TUs (main's dir is `src/`, a prefix test matched the fleet) — restored with `git checkout -- src`, the test made exact; (2) the per-binary driver paid the 218-file sig load per binary (36 binaries > 10 min) → the batch form pays it once (224 s for 213); (3) five mid-file `match_one-only` includes with trailing comments and (4) seven whale includers in `_o0c.c`/`_o0d.c` (a `*_o0b.c` glob) were missed — the census's coverage line (7 unaccounted) and `--verify` found them; (5) `verify` listed 3 of N offenders (a `[:3]` slice) — it now lists every include LINE and ignores prose; (6) `.run/P35/convert/` was not allowlisted — added. `docs/SETUP.md` P35 T3–T4 section + the dictionary row (P10, PROJECT-ONLY). **T4 ☑.** - **S94 — T5 `tools/share_body.py` (Max) + the R37 probe (commit `0bccef901`, 18:12 local).** Built as designed (411 lines): `census(jobs)` = `share_census.classify(…, keep_instances=True)` (the census now exports per-instance `line`/`end`/`nlines` and the class's `groups`; a census with unaccounted or multi-form instances is a refusal, R32); `candidates()` → `extend` = verdict-B classes (registered, some instance still a private `def`), `new` = unregistered same-vram classes with ≥1 private def — both skip A, E/F flags, TWIN-COVERED and EXCEPTED classes, sorted by (−instances, −nins); `choose_exemplar` = majority normalized text → pin-free → fewest lines (printed); `Batch.add_class` (B: the registry's header must define `func` or the class is refused; the extension list = instances not yet listed; new: header `func_[__h8].h` via `macro_to_header.Oracles.header_rel`, banner + `bind_alias_header`; every private site → `include_line(tu, hdr)` at `[line, end]`; every instance's binary is "touched", twins with their primary); `gate()` = `make check BINARY= -j16` by exit code + every object compared with the pre-batch snapshot (`.run/P35/share/check_.log`); a red binary is BISECTED (restore its TUs, re-apply classes one at a time, the culprit REJECTED and ledgered, the survivors kept); `registry_append` (shorthand, by text — never `yaml.safe_dump`), `dedup_extend.add_members_surgical` for extensions; `batch_