Files
BFM-decomp/phase-ends/CURRENT_PHASE.md
T

52 KiB
Raw Blame History

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/<name>.h, instantiated per stage by a .c stub that #includes 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/<space>/.
  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 — twin binaries → one source directory: SC01_005/006 (probe), SC03_118/119, SC02_000/003, SC04_018/019, SC03_014/015 (carve alignment, R60); one commit per pair; the clean fleet run after the last.
  • ☐ T4 — tools/macro_to_header.py: the fleet converted in L0-gated batches; engine_core.h/ov_setters.h/clearTbl40.h deleted (clearTbl40 → the parameterized control); func_80144B9C.h moved; the registry's source:/func: rewritten surgically; clean fleet 218/218.
  • ☐ T5 — tools/share_body.py: bucket 0 --extend (206 classes), 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 — consumers: freeze 7 (main()-time refusal, FROZEN rows), retire 3 to tools/sunset/, the ast macro-form guard in tool_census --check (negative-controlled), make kit-corpus, SETUP rows.
  • ☐ T7 — S1 strict + --selftest + C2c/C2d in make tools-health; progress.py fields + README block; the +219 correction stated; the gate negative-controlled in a worktree.
  • ☐ T8 — 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 — 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).

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 (<alias>_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 <alias>_SRC_DIR / <alias>_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/<twin>/, 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/<twin>/<twin>%.o ← src/<primary>/<primary>%.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.

Approved plan (verbatim, gate 1 — 2026-09-08)

Phase 35 — Gen3 opens: the dedup phase, "one source per unique function" (v2.0.0 → v2.1.0)

Plan mode, Max, S94, 2026-09-08. Gen3 order set by Drew this session: dedup → pins → structs → names, one phase each, planned one at a time; this plan is Phase 35 only. Gate 1 also ratifies R96–R99 (Drew: "ratify all four").

Context

Gen2 closed at v2.0.0 (218 binaries byte-identical, the repository public). Gen3's charter is readability on a byte-exact floor. The first readability defect is that the same function exists many times in the tree, in two forms:

  1. Shared bodies as macros. The dedup engine instantiates one body in every location overlay as a DEFINE_func_XXXXXXXX() macro from src/shared/engine_core.h (8.8 MB, 227,730 lines, backslash-continued, #included whole by 3,981 TUs; measured cost 0.35 s + 94 MB RSS of cpp per TU ≈ 19 CPU-minutes per fleet build). docs/gen3-standards.md §2 rule 3 requires shared engine functions to live as C, not macros.
  2. Literal duplicate copies. The July-2026 family sweeps banked proven bodies as a private copy per overlay and registered no group. On 2026-09-02 that backlog was deferred on the belief "sotn writes duplicate funcs explicitly" (memory dedup-backlog-leave-it); the decision log caveated that the claim rested on one cookbook parenthetical — which is about a cross-jump barrier idiom (docs/matching-cookbook.md:253), not about sharing.

Verified this session, as data (X2), from sotn-decomp's tree: sotn does NOT duplicate. Shared stage code lives once as plain C in src/st/<name>.h (full definitions, static tables, #ifdef STAGE_IS_… where one stage differs), and each stage overlay carries a ~90-byte .c stub (#include "nz0.h" + #include "../e_red_door.h") that instantiates it at that stage's link position; per-stage parameters are static data in the stub before the include. "Written once, instantiated per overlay by an include at the site" is the community shape — structurally what our macros do, minus the macro form. The 2026-09-02 decision is reversed on this evidence (recorded in the decision log at task 8).

Drew's requirement (this session): after the phase the tooling knows that functions are no longer duplicated across overlays and that there is exactly one source for a unique function — an invariant asserted by a gate (R36), not remembered.

Decisions at gate 1 (Drew, AskUserQuestion): twin binaries share one source directory · cross-address classes are censused and deferred to the names phase · macro-era tools are frozen with a loud refusal (the direct predecessors retire) · R96–R99 ratified. Added by the plan: no "trivial" exception — a duplicated 3-instruction accessor is still one function (this project already shares 5-instruction bodies; 341 tiny classes / 42,744 instances are in scope).

Measured shape (this session; every number carries its rule; task 1 makes them an instrument)

  • Registry (config/dedup.us.yaml via dedup_integrate.group_members): 2,220 groups / 255,708 members, all h_exact; 2,212 shorthand (one vram + name for every member), 8 verbose; median 141 members; spans 2,207 ov / 12 md / 1 main; one group with differing member names (main's clearTbl40 pair). Sources: engine_core.h 2,215 · ov_setters.h 3 (name-parameterized SETTER/RETCONST, the SC01_005≡006 pair) · clearTbl40.h 1 · func_80144B9C.h 1 (a 319-line ordinary-C header included by 141 <ov>_o0b.c — already the target form; "a header-share is as valid as a macro-share", cookbook §38).
  • The header: 5,147 #define DEFINE_func_ lines = 3,516 distinct macros; 1,631 defined twice (copy 1 inside the #ifndef ENGINE_SHB block ending at line 99,164, copy 2 after; 1,627 identical, 4 differ in one extern's (void) vs (); cpp keeps the LAST); 2,215 shared (all registered) · 218 single-site (217 of them in ov_SC03_015, 1 in ov_SC03_118) · 1,083 dead. 4,600 carry extern preambles, 451 asm-label aliases, 357 register pins (Phase 36's; kept verbatim), 0 #if, 0 __LINE__/__FILE__; exactly 8 non-DEFINE_ directives (the prelude is provably complete). All macros zero-argument. Invocation sites: 255,947 lines in 3,153 files across 153 binaries; the site is always one line DEFINE_func_X() /* dedup: … */; max 539 sites in one TU (p50 31). The charter's "5,147 macro bodies" counted define lines (R14/R41 correction, published at task 8).
  • Why include-at-site is byte-neutral and a separate object is not: a macro expands AT THE SITE to [externs + definition], so its externs become file-scope declarations at that line and later functions rely on them (cookbook §112; decision-log :441-457). An include reproduces the text at the same point. Probe P1 (run): three real bodies compiled both ways through cpp → cc1 → maspsx → as give byte-identical .o files (1,632 B, identical relocations); cc1 adds only a .file directive that as consumes. A separate .c object would delete ~4,000 declaration lines from ~3,153 TUs and cannot place interleaved functions (shared and local bodies interleave in address order, src/ov_SC06_033/ov_SC06_033.c:1-31). src/shared/ is not pruned from main's source find (Makefile:841-847) → shared bodies are .h. -MMD tracking (:849-855) recompiles on header edits.
  • Backlog, from the 218 fleet sig files (362,389 instances; 255,937 macro sites · 105,262 inline definitions · 1,190 alias-form unaccounted): h_exact classes with ≥2 instances fleet-wide: 10,180 (280,801 instances); registered 1,994 hashes / 2,220 groups; 206 registered classes have 3,996 instances not listed as members (never extended); unregistered classes with ≥2 inline copies: 7,956 classes / 20,038 copies / 12,082 collapsible copies / 478,773 ins — 4,259 same-vram (9,698 copies), 3,697 cross-vram (10,340 copies; the member's own name differs per site → deferred), 54 cross-space. Under the old propagate rule alone: 11,289 copies / 1,932 addresses / 5,083 bodies. Source text across copies: 91% identical, 8.3% (403 bodies) differ (uniquify_type suffixes, extern scoping, 9 with pins) → one chosen text re-gated per member; type-carrying bodies via tools/lift_types.py first.
  • Twin binaries: five overlay pairs have IDENTICAL payloads (equal config/check.*.sha): SC04_018/019, SC03_118/119, SC03_014/015, SC02_000/003, SC01_005/006 (10 of 141 aliases; 136 distinct payloads); their piles ≈ 7,900 of the 11,289 same-vram copies (~70%). Each twin's yaml differs from its primary's only in target_path (+ a carve delta: SC04_019 has one extra _jr_80181804 split, SC03_015 two extra); overlays.mk blocks differ only by alias; the linker script names objects by alias.
  • Header-name collisions: 6,346 of 13,355 overlay-slot vrams host >1 h_exact class fleet-wide (max 134) → a shared header cannot be keyed by address alone; of today's 2,220 groups, 1,961 get a clean name and 259 need a stable suffix.
  • Consumers: 55 live tools reference the architecture; 22 text-parse the macro form; the rest ask cpp (form-independent) or only read the registry. Two would CRASH make tools-health on the header's deletion: cdecl.audit_differential (tools/cdecl.py:1292-1323 opens engine_core.h unconditionally; make audit-cdecl is in the chain) and overlay_src_split (:667 degrades to a silently EMPTY macro table). 51 tools build src/<binary> paths themselves; only compile_only.py reads the Makefile's <alias>_SRC_DIR; corpus.py:312 maps link objects to src/{binary}/{subseg}.c. progress.py undercounts ov_SC03_015 by 219 (single-site macro sites invisible to classify()) — a real undercount the phase corrects and publishes.

Target architecture (decided)

src/shared/
  engine_prelude.h           # engine_types.h + ENGINE_SHB — every overlay/module TU includes this at line 2 (was engine_core.h)
  engine_types.h             # unchanged (tools/build_engine_types.py owns it)
  ov/            func_80128EA8.h · func_80150000__2905b55f.h     # the overlay slot 0x80128158
  slot_800CAE08/ … slot_801EF468/                                  # the 11 module slot bases, derived from <b>_VRAM_BASE (R33)
  main/          func_80037004__a0744d60.h                        # the clearTbl40 pair (the one intra-binary, name-parameterized share)
  • One plain-C header per shared body, keyed by the h_exact class: directory = address space, filename = func_<CANON_VRAM> + __<h8> iff (space, vram) hosts >1 class fleet-wide or the class spans >1 vram/space — both predicates on immutable ROM data, so names are stable under later additions (R48: never a bare name). Flat per space (address-named files list in assembly order).
  • Body text = the live macro's LAST definition, continuations stripped, re-indented; every extern, alias, comment and pin verbatim (asserted to round-trip to the same token stream). Pure fragment (no includes of its own; the prelude comes from the TU, sotn's contract). No include guard (a second include of a fixed-name header is the loud duplicate-definition error we want; the parameterized form legitimately includes twice). Banner: h_exact, canonical vram, "one source — instantiated by #include at each member's site; members: config/dedup.us.yaml" (no member count stored — derived, R51).
  • Two site forms, only two: #include "../shared/ov/func_80128EA8.h" for same-vram classes; for the cross-vram control (clearTbl40 only in this phase) #define SHARED_FN func_80037334 / #include … / #undef SHARED_FN, the header defining void SHARED_FN(void) {…}. More than two parameters → refuse (R43). The parameterized form is what the names phase will apply to the deferred cross-vram classes — clearTbl40 is its worked example and permanent negative control.
  • Single-site bodies with no fleet-wide twin → inlined at their site as plain C; dead macros dropped (listed by name in the run log — counted, never silent); engine_core.h, ov_setters.h, clearTbl40.h deleted; func_80144B9C.h moved to ov/, its guard removed (one shape). End state: src/shared/ = the prelude, engine_types.h, the per-function tree. Nothing else.
  • Twin binaries: config/overlays.mk gets ov_B_TWIN_OF := ov_A and ov_B_SRC_DIR := src/ov_A; the Makefile maps a twin's objects to its OWN build/src/ov_B/ from the primary's sources (-O0 object lists and .d paths twin-aware; check-all's per-binary parallelism never races); the twin's yaml = the primary's carve with its own target_path/sha1; its check.sha still proves it; src/ov_B/ deleted. One oracle "binary → source dir" (Makefile-derived, R33) replaces the hardcoded src/<binary> shapes in the Gen3-live tools. The registry keeps twins as members (their site resolves through the oracle to the primary's TU); no per-function groups for twins.
  • Registry v2: same file, same group_members oracle, shorthand kept; source: = the header path; func: = the defined token (SHARED_FN for the parameterized form, as CLEAR_TBL40 is today); optional form:; text-edited only, never yaml.safe_dump (the H5 precedent that decimalized every vram and deleted 47 comment lines while every gate stayed green, tools/dedup_extend.py:78-89). dedup_integrate --check gains C2c (the source is under src/shared/, defines exactly one function, and func is the token it uses — via cdecl) and C2d (every member's site file includes the source and no inline definition of that member survives in the binary).
  • The S1 invariant (permanent, in make tools-health): every same-(vram, h_exact) class with ≥2 instances is a registry group with the include at every member, or twin-covered, or a ledgered exception (config/dedup_exceptions.tsv: class hash · nins · instances · reason code {JTBL-CARVE, O0-LOCAL, TU-CONFLICT, GATE-REJECT, PINNED, CROSS-VRAM-DEFERRED, CROSS-SPACE} · evidence); no DEFINE_func_ token in src/; and a second, sig-blind oracle: no name-blind normalized definition text appears in >1 file under src/ outside src/shared/ (R34 — it cannot fail the way the sig join fails).

The three tools

tools/share_census.py (permanent; T1) — inputs: the 218 sigs enumerated from dup_report.BINARIES (refuse on a missing sig; never a glob — .run/ holds 223 sig files incl. two non-fleet ones), the registry, src/ through the source-dir oracle. Source-form index: every sig instance resolves to exactly one of def / include / param-include / stub / asm-verbatim / linked / blob — 0 or ≥2 forms is a coverage DEFECT (R32; strictly stronger than progress.py's unplaced, which is vacuous where asm/<bin>/nonmatchings/ does not exist). Verdicts per class: A registered-complete · B registered-but-site-missing · C unregistered-identical-text · D unregistered-differing-text · flags E cross-vram · F cross-space; --json, a human table, --check (S1 + the text oracle, exit code), --selftest (an in-memory fixture of 2 binaries × 7 classes covering every verdict, R39). Negative controls on the real tree: func_80144B9C = A/141; clearTbl40 = A+E; the 3 ov_setters = A; ov_SC01_005 = 657 unregistered items (S75 said 557 at 174 binaries; printed with its denominator, R41).

tools/macro_to_header.py (ONE-OFF; T3) — --plan / --dry-run [--diff] / --apply --binaries … / --verify (idempotence: a second apply changes 0 files). macro_index() keeps the LAST definition (reusing macro_draft.extract's dedent/continuation strip, tools/macro_draft.py:31-43; the 4 divergent names cross-checked against blocker_probe.py:83-90's independent list); directive_audit() asserts the 5,147 + 8 directive inventory before touching anything; site_index() refuses any site not of the one known shape; header_path() per the naming rule; emit_header() asserts token-stream round-trip; rewrite_tu() (line 2 → the prelude; each site → its include, relative to the TU's own directory); inline_single_site(); drop_dead(); registry source:/func: rewritten surgically. Asserts no emitted header carries a stray trailing \.

tools/share_body.py (permanent; T5 — the successor of dedup_propagate + dedup_extend) — --plan [--bucket] [--limit], --apply --plan-file, --extend --binaries (the never-extended 206 classes). Per class: exemplar = the registry's source if registered; else the majority name-blind text; tie → pin-free; tie → shortest (the rule printed with every share). Guards reused (R33): family_hseq.has_mid_jr → JTBL-CARVE; the -O0 split guard (dedup_propagate.py:676-687, extended to _o0b/_o0c) → O0-LOCAL; the inline-type guard (:750) → lift_types first. Sites replaced at the same position with the function's own preamble (the overlay_src_split Item model). Then L0 per TU (build that one object before/after the batch's edits in that TU; byte-equal, the Probe-P1 oracle; the exact per-TU recipe asked of the Makefile via parallel_gate.generated_paths' --eval trick, never re-derived) → on failure bisect within the TU, drop the member, ledger the compiler's message class → L1 make check BINARY= per touched binary → register (shorthand) → commit (R42) → L2 clean fleet per batch. "shared" is printed only from the gate's success line (R66). Library surface: onboarded_overlays, load_sig, sym, find_site, registered_addrs moved verbatim so the three importers of dedup_propagate change one line.

Tasks (in order; one commit each; effort per docs/effort-map.md; every verify line read by exit code, R53/R97)

T0 — Open + ground (Low, then Max for the probe). CURRENT_PHASE.md with this plan verbatim; DIGEST §3 gets R96–R99 in full; .gitignore allowlists .run/P35/; harness task list (R28). The R22 baseline from clean: make clean && make extract-all JOBS=16 && make check-all JOBS=16 → check-all: 218 passed, 0 failed of 218, wall time recorded; make tools-health OK. The probe (R37): in a scratch worktree, convert ov_SC06_033's 34 TUs by hand-driven script and run the L0 object A/B on all 34 (+ make check BINARY=ov_SC06_033), measuring the .d growth and the per-TU cpp saving. Verify: 34/34 objects byte-identical; [ OK ] … (BYTE-IDENTICAL).

T1 — tools/share_census.py + config/dedup_exceptions.tsv (Max; new instrument). Built BEFORE anything moves so every claim has a before/after. SETUP + dictionary rows (R21/R87). Verify: --selftest → 7/7 verdicts correct; --json on the unchanged tree prints the class counts above with their denominators, and the four negative controls; coverage line classified == instances.

T2 — Teach the health chain the new forms while the old tree is still green (Max design, xHigh apply). The source-dir oracle (corpus.src_dir(binary) from the Makefile's <alias>_SRC_DIR — one function; compile_only.src_dirs folded in); corpus.py (definitions may live under src/shared/**.h; :312 through the oracle); cdecl.py (audit_differential includes src/shared/**/*.h when engine_core.h is absent; MACRO_STMT :109); overlay_src_split.py (+ jr_isolate_all: an include-site anchor kind; header-resident bodies; :667 becomes a loud refusal); progress.py (classify() recognizes an include of a src/shared/ path as the definition the registry names for that site; the fold at :773 becomes shared = real ∩ dedup_members — derived from source, R33); dedup_integrate.py (C2c/C2d; the oracle for _src_paths); audit_binaries.py (the prelude include; twin citizenship: equal check.sha, SRC_DIR = the primary's, primary not a twin, carve equal — R36); lint_symbol_refs.py (:89 recursive glob); shared_lock.py; fix_arity_callers.py (:41); family_remap._unit_from_macro → read the header; blocker_probe.py; demacroize.py (macro_bodies() reads headers); export_pairs.py; harvest_verify.py:167. Both forms accepted during the transition. Verify: make tools-health OK on the UNCHANGED tree (the negative control) and share_census --selftest still 7/7.

T3 — Twin binaries → one source directory (Max for the mechanism on the probe pair; xHigh for the other four). Probe SC01_005/006 (carves already equal): the TWIN_OF declaration, the Makefile mapping, the twin's yaml = the primary's carve with its own target_path; delete src/ov_SC01_006/; make extract BINARY=ov_SC01_006 && make check BINARY=ov_SC01_006 → 56760dbe…; ov_setters.h's three groups become twin-covered (the header goes at T4). Then SC03_118/119 and SC02_000/003 (carves equal), then SC04_018/019 and SC03_014/015 (adopt the primary's carve for the twin; R60: interleave_check + pads_audit on the twin). One commit per pair; the clean fleet run after the last. Verify per pair: the twin's make check sha line; after all: share_census twin-covered copies ≈ 7,900, same-vram backlog copies fall by that count, ov_SC03_015's 217 single-site macros become dead.

T4 — The conversion: tools/macro_to_header.py applied fleet-wide; engine_core.h deleted (Max for the tool; xHigh to run). Order: --plan, --dry-run reviewed; --apply --binaries ov_SC06_033 + L0 + make check, commit; the remaining binaries in ~8 batches of ~27, each L0-gated (obj A/B: N/N byte-identical); then delete engine_core.h / ov_setters.h / clearTbl40.h (clearTbl40 rewritten as the parameterized control), move func_80144B9C.h, rewrite the 141 <ov>_o0b.c includes; the registry's source:/func: rewritten surgically; L2. Verify, in order: --verify → idempotent: 0 files would change; L0 fleet N/N; check-all: 218 passed, 0 failed of 218; git grep -c '^#define DEFINE_func_' -- src and git grep -cP '^\s*DEFINE_func_' -- src empty; tools/audit_text_sources.py OK (every new include resolves in-repo); the fleet build wall time vs T0's baseline (the 8.8 MB header no longer preprocessed per TU); share_census: 2,215 registered classes intact, the 1,083 dead listed, the fleet function count +219 (ov_SC03_015's correction — published at T8 as a corrected undercount, never buried).

T5 — tools/share_body.py + the same-vram backlog (Max for the tool; xHigh for the runs; batched largest reach first). Bucket 0: --extend the 206 never-extended classes (3,996 instances). Then the same-vram buckets: 32+ members same-text (1,899 classes / 4,234 copies / 249,554 ins) → 32+ differing-text (168 / 760 / 55,820) → 16–31 (1,033 / 2,231) → 8–15 (986 / 2,106) → the tiny classes (no trivial exception). Per batch: share_body --apply → banked N/M classes, K copies collapsed; J gate rejects → check-all: 218 passed → commit. Differing-text bodies: one chosen text per the rule; type-carrying bodies: lift_types first, retry; what still fails is ledgered with its message class (budget ~2–5% of sites). Cross-vram classes are not touched (listed by T1; published at T8 as CROSS-VRAM-DEFERRED with their count and copies). Verify at task end: share_census --check → same-vram unregistered copies 0 (or = the ledger's count, each with a reason).

T6 — Consumers, second half: freeze / retire / the guard (xHigh). Drop macro-form support from the T2 set; FREEZE the 7 matching-era parsers (family_sweep, gen_harvest_targets, p16_improve, recover_giant, restore_dropped_decls, normalize_self_decls, o0_subsplit) with one shared refusal in main() — never at import (cdecl.audit_differential imports gen_harvest_targets; an import-time exit would take the health chain down) — dictionary status FROZEN, successor named; RETIRE the 3 direct predecessors to tools/sunset/ (dedup_propagate, dedup_extend → share_body.py; macro_draft → product: the headers) after repointing their 9 callers (gate_stage.py:522, bulk_harvest.py:267, auto_driver.py:140, lora_grind.py:230, gate_lane.py:86, grinder.py:351, the 3 importers); the guard in tool_census.py --check: every LIVE, non-FROZEN tool parsed with ast — no non-docstring string constant contains DEFINE_func_ or engine_core.h (prose mentions in comments/docstrings are historical record and survive; 4,570 DEFINE_func_ mentions in src/ comments are deliberately not rewritten). Negative control (R39): on the pre-T4 tree the guard flags exactly the 22 parsers and none of the comment-only tools; flipping one row to FROZEN un-flags it. make kit-corpus, SETUP rows (R21). Verify: tool_census --check → macro-form guard: 0 LIVE tools reference the retired form (7 frozen, 3 retired); make tools-health OK.

T7 — Wire the invariants + regenerate every published number (xHigh). In make tools-health after report BINARY=main: share_census.py --check (strict) + --selftest; dedup_integrate --check C2c/C2d. progress.py: two generated fields (unique_function_bodies, duplicate_source_copies) in docs/progress.json and the README block (:1146-1166) sourced from the census; progress.py --readme --check, timeline.py, make audit-digest (the +219 correction stated with its cause). Negative- control the new gate: in a worktree revert one member's site to an inline copy → share_census --check exits 1 naming that class. Verify: make tools-health OK; progress.py --readme --check fresh.

T8 — The record (xHigh). Wiki: The-dedup-engine.md rewritten as the shared-source model (headers, twins, the census, the sotn fact as read), Repository-layout.md, Where-the-project-goes-next.md, Verification-and-progress.md; how-to ch.10 (the Gen3 outcome; history kept); README:117 prose; gen3-standards.md §4 row + DoD line and gen3-handoff.md §2.2/§3 as dated snapshots with the derivation; a cookbook section replacing §14/§38's macro narrative; docs/decision-log.md P35 (R31: the 2026-09-02 reversal with the sotn evidence, the 5,147-vs-3,516 miscount, the twin discovery, the +219 undercount); docs/accelerators.md; DIGEST §4; tools/sunset/README.md rows; the memory dedup-backlog-leave-it rewritten; doc_links --strict, wiki_render --selftest, cookbook_index --check, kit_coverage. Verify: doc_links 0 broken / 0 pending; the checks green.

T9 — Close (Max, Tier 1). R22 clean fleet run → 218/218; make tools-health OK (S1 strict + the guard); the metrics table before/after (macro lines 5,147 → 0; engine_core.h 8.8 MB → deleted; same-vram duplicate copies → 0 + ledger N; twins 5 pairs / 10 aliases; cross-vram classes deferred N / copies M; registry groups 2,220 → ~6,500; fleet build wall time; the +219); the reviewer sequence documented; PhaseEnd_Phase35.md + DIGEST §0/§2/§3 + the log archived (R19), left for Drew's close commit; v2.1.0. Rules check (P6) after T3 and T7.

Effort: Max for T0's probe, T1, T2's design, T3's probe pair, T4's and T5's tool, T9; xHigh elsewhere; no Ultracode (the parallelism is machine parallelism: L0 at JOBS=16 ≈ 13 min fleet-wide; the clean fleet run 3–5 min). Sessions (R41, summed from the task sizes above): T0–T1 ≈ 1 · T2 ≈ 1 · T3 ≈ 1 · T4 ≈ 1 · T5 ≈ 1–2 · T6–T7 ≈ 1 · T8–T9 ≈ 1 → ≈ 7–8 sessions; the tail is the differing-text and type-carrying bodies and the consumer edits, not the gates.

Which gate proves which step

step gate the line that banks it
one TU converted/shared L0 object A/B (Probe P1) obj A/B: N/N byte-identical
one binary make check BINARY=<b> [ OK ] build/<b>/<b> … (BYTE-IDENTICAL)
a batch / the phase make clean && make extract-all JOBS=16 && make check-all JOBS=16 (R22) check-all: 218 passed, 0 failed of 218
the registry is honest tools/dedup_integrate.py --check dedup-check: N validated, 0 failed
the invariant holds tools/share_census.py --check S1: one source per unique function — …, 0 unregistered, N excepted
no live tool assumes the macro form tools/tool_census.py --check macro-form guard: 0 LIVE tools reference the retired form
everything make tools-health tools-health: OK — …

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/<space>/.
  2. tools/share_census.py --check exit 0: same-vram duplicate copies 0 (or each ledgered with a reason); the five twins built from one source directory each; cross-vram classes published as a deferred count.
  3. make tools-health OK with S1 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 + DIGEST written.

Verification (the reviewer's sequence from a fresh clone, documented at T9)

make bootstrap
make clean && make extract-all JOBS=16 && make check-all JOBS=16   # 218 passed, 0 failed of 218
make tools-health                                                   # tools-health: OK — …
tools/share_census.py --selftest && tools/share_census.py --check    # S1 … 0 unregistered, N excepted
tools/tool_census.py --check                                         # macro-form guard: 0 LIVE …
tools/progress.py --readme --check                                   # docs/progress.json + README block are fresh
git grep -c '^#define DEFINE_func_' -- src                           # (no output)

Risks — settled by probe, or carried with its probe

Settled: include-vs-macro byte identity (P1, .o-level); the 4 divergent twins (last wins, uniform: copy 1 < 99,164 < copy 2); __LINE__/__FILE__ absent and no -g; the prelude's completeness (the 5,147 + 8 directive inventory); header-name collisions (the stable suffix rule); ld_interleave never reads C. Carried: .d/file-count growth (measured at T0; fallback a vram>>12 fan-out, mechanical since paths are generated); a backlog site's TU rejecting the exemplar text (L0 localizes; ledgered); the registry text edits (never yaml.safe_dump); the health-chain crash on deletion (T2 lands before T4); pins spread by a share (the exemplar rule prefers pin-free; PINNED is a ledger class, never a spread).

Rules at gate 1

R96 (a) a scratch prune is an instrument change — re-run every tool that writes under it before calling the prune done. R97 (b) "green" is read from a check's EXIT CODE, never its last line; every chain sets pipefail. R98 (c) a step that hands a file to a third party is proven through that party's own toolchain on the file itself before the owner's browser session, and the proving tool writes the paste. R99 (d) what a public tree carries is decided before the flip; a retired document gets its Archive-index row and is deleted in the same commit — history keeps it. Candidate for the PhaseEnd: "a shared body has exactly one source; a duplicate copy is a defect the health chain asserts, and a count of them is published with its rule" (this phase's invariant).

🛑 SESSION CHECKPOINT — S94 (2026-09-08): Phase 35 OPEN at gate 1; T0 ☑, T1 ☑ (the census), T2 ☑ (the health chain knows the include + twin forms; the +7 correction published); NEXT = T3 twin binaries → one source directory (probe pair SC01_005/006)

0. How to use this block

A fresh session reads CLAUDE.md's load order, replays THIS block verbatim, and resumes at the first unchecked task in §Tasks above. Everything a task needs is in its row, its plan paragraph (§"Approved plan" above), and the carried context here. Effort: Max is session-only — ask Drew to re-apply /effort max at session start (T0's probe, T1, T2's design, T3's probe pair, T4/T5's tools, T9 are Max; the mechanical runs are xHigh). Autonomous between the gates (P3): do not stop to ask permission for planned tasks; stop only on P5's conditions. Commit per task; banks the moment they are green (R42); Drew pushes (R6).

1. Where things stand (S94, at the time of this block)

  • Baseline HEAD 48170fd7f (Drew's P34 close = v2.0.0). T0 is committed as the first Phase-35 commit (see git log); after it the tree is clean and the fleet is green: check-all: 218 passed, 0 failed of 218 from clean in 157 s wall (.run/P35/baseline/r22_open.log), tools-health: OK (.run/P35/baseline/tools_health_open3.log, 474 s). The build/ tree holds the fleet's objects from that run.
  • make tools-health regenerates every sig first (~8 min; run it in the foreground with a 600 s timeout). Two rungs bite on doc/rule edits: tool_census --check (the kit's record copies must be regenerated with make kit-corpus after ANY edit to a PhaseEnd/DIGEST/how-to/ the cookbook) and kit_coverage (every new rule needs a config/kit_coverage_map.tsv row or a kernel citation, R92).
  • The probe's evidence is .run/P35/probe/ (probe_ledger.txt, probe_convert.py, buildA.log, buildB.log; the objA/objB .o files are ignored scratch). The probe form's naming (src/shared/ov/func_<VRAM>.h, no suffix) is NOT the final naming — T4 applies the stable-suffix rule from the census.
  • The headless Ghidra MCP was launched by the SessionStart hook (pid in .run/ghidra-mcp.log); NOT used this phase (no RE work). Stop it via the sentinel before the close commit (R23).
  • Disk: 33 GB free of 73 GB at open; .run/ ≈ 29 GB.

2. Carried context per remaining task (exact invocations; gotchas)

  • T0 — DONE. The L0 recipe that worked (reuse in T4/T5): copy the A objects from build/src/<bin>/*.o, apply the edit, make check BINARY=<bin> -j16, copy the B objects, cmp per object. The probe converter's parser (macro_index last-wins, the one site shape, the prelude = engine_types.h + the ENGINE_SHB line copied from engine_core.h:20) is the seed of tools/macro_to_header.py.
  • T1 — DONE. tools/share_census.py (run it plain for the table; --check for S1; --selftest for the fixture; --no-cache after a scanner change — the cache is keyed by file mtime/size, not by the scanner's version). The numbers every later task measures against are in the log entry and .run/P35/census/share_census.json. Known shapes the scanner handles (each was a finding): K&R definitions (multi-line and the one-line void f(a, b) void *a; s16 b; {), implicit-return-type heads, a second head after extern …; on one line, the asm-label alias in both __asm__( and asm( spellings, static inline helpers (no address). The census's per-class output classes.jsonl is the input for T3's twin accounting and T5's plan (share_body.py --plan reads it).
  • T2–T9: see the task rows and the plan; the Plan agent's consumer table (which tools text-parse the macro form, which ask cpp and need nothing) is reproduced in the plan's §Consumers and §T6.

3. Numbers to re-derive, never trust (with their commands — in the plan's §Measured shape)

engine_core.h define lines 5,147 / distinct 3,516 / twice 1,631 (4 divergent) / shared 2,215 / single-site 218 / dead 1,083; registry 2,220 groups / 255,708 members; sites 255,947 in 3,153 files; twins: 5 pairs by equal config/check.*.sha; backlog A 11,289 copies / 5,083 bodies; cross-vram 3,697 classes (deferred).