52 KiB
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 touchessrc/— the clean fleet runmake 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 insrc/st/<name>.h, instantiated per stage by a.cstub that#includes it; it does not write duplicates.
Milestone (gate 2 — what Drew confirms, each with its literal output)
git grep -c '^#define DEFINE_func_' -- srcempty; noDEFINE_func_X()site;src/shared/engine_core.habsent; every registered body a plain-C header undersrc/shared/<space>/.tools/share_census.py --checkexit 0: same-vram duplicate copies 0 (or each ledgered with a reason inconfig/dedup_exceptions.tsv); the five twin overlays built from one source directory each; cross-vram classes published as a deferred count.make tools-healthOK with the S1 invariant strict and the macro-form guard; every consumer updated, frozen or retired per its dictionary row.make clean && make extract-all && make check-all→218 passed, 0 failed of 218(R22).- 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 maxat 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 touchsrc/).
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 cleancheck-all: 218 passed, 0 failed of 218in 157 s wall;make tools-healthOK (exit 0, 474 s — after two red runs fixed at their cause: the kit's record copies regenerated bymake kit-corpus, and R96–R99 dispositioned inconfig/kit_coverage_map.tsv); the probe on ov_SC06_033: 34/34 objects byte-identical in the include form, the binaryBYTE-IDENTICALboth 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),.d11.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_defsthe 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 --checkfresh · 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 bymake 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.hdeleted (clearTbl40 → the parameterized control);func_80144B9C.hmoved; the registry'ssource:/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 --checksame-vram unregistered = 0 or ledgered. - ☐ T6 — consumers: freeze 7 (main()-time refusal, FROZEN rows), retire 3 to
tools/sunset/, theastmacro-form guard intool_census --check(negative-controlled),make kit-corpus, SETUP rows. - ☐ T7 — S1 strict +
--selftest+ C2c/C2d inmake tools-health;progress.pyfields + 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/timewall 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 bygit 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 themDEFINE_func_) ·sha1 1e91d46e… == config/check.ov_SC06_033.sha (BYTE-IDENTICAL)both ways ·obj A/B: 34/34 byte-identical, 0 differing·.dbytes 11,632 → 182,252 (1,813 header dependencies; harmless) · restore verified (git statusshows 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/.svgregenerated 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_MATCHINGhalves 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 throughdedup_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-linevoid f(a, b) void *a; s16 b; {form); a second definition head on the same line after anextern …;; the alias regex spanning a previous macro site's parentheses;asm(as well as__asm__(; implicit-return-type heads with no type line;static inlinehelpers (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
1dbffee87says "kit corpus regenerated" whilemake kit-corpushad exited 2 andtool_census --checkhad 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 in72a77e7d3(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_OFin the Makefile andconfig/*.mk;corpus.src_filesando0_subseggo through it;compile_only.src_dirsdelegates to it;progress.set_binarytakes its dir from it (the table'ssrcis only a cross-check);dedup_integrate._src_pathsusescorpus.src_files. The include form:share_census.header_defs()is the one reader ([(name, empty)], masked — a macro-only header defines nothing);progress.classifycounts an include site as the function's definition (REAL/EMPTY by the header body) with the#define SHARED_FN/#undefstate 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_splitgains theincludeitem kind (anchor by the header's defined name,#undef SHARED_FNtravels with the item;split_headerno longer swallows a leading body include;macro_externs/macro_protoread the header's parts; a macro invocation with no table entry is a loud refusal, R43) andjr_isolate_alladmits the kind;dedup_integrateC2a′ requires a plain-C source to DEFINEfunc;audit_binariesacceptsengine_prelude.h, resolves the main TU through the oracle, and gains CHECK 3b (twin citizenship: primary onboarded and not a twin, same src dir, nosrc/<twin>/, equal contracts, equal carves);cdecl.audit_differentialreports "not applicable" when the macro header is gone instead of crashing;lint_symbol_refs/family_remap/fix_arity_callersglobsrc/shared/**/*.h;blocker_probe.macro_scopeanddemacroize.macro_bodiestolerate the header's absence;shared_lockdocstring;harvest_verifycomment. Verify:py_compile16 tools OK;share_census --selftest7/7;audit-binaries: OK;dedup-check: 2220 validated, 0 failed; the split tool onsrc/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.cincludes 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 bymake 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 --check17 gaps) —make kit-corpusbelongs 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). Commits6cb056c93(the tools + the +7 numbers),4ec752e68(the timeline),24e8ff72d(the close). T2 ☑. - S94 — T3 probe pair SC01_005/006 (Max). The mechanism:
config/overlays.mkov_SC01_006_TWIN_OF := ov_SC01_005+ov_SC01_006_SRC_DIR := src/ov_SC01_005; the Makefile's twin block (static pattern rulesbuild/src/<twin>/<twin>%.o ← src/<primary>/<primary>%.c+ the bare-name rule, the same recipe;TWIN_O0_OBJSkeep-O0; the twin's ownOBJS/C_DEPS);config/splat.ov_SC01_006.yamlcreate_c_files: False(src_path stays the twin's name → the .ld's 120 object paths underbuild/src/ov_SC01_006/);git rm -r src/ov_SC01_006(30 files). Verify:make extract BINARY=ov_SC01_006exit 0, nosrc/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 checkfor 005 and 006 run CONCURRENTLY → both BYTE-IDENTICAL; consumers:progress.py --binary ov_SC01_0062503/2503 (of which dedup-shared 1838, unchanged),dedup-check --binary ov_SC01_0061838 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 fromsrc/ov_SC01_005/(2 at -O0). One instrument slip caught by the census's R32 gate: my Makefile variableTWIN_SRC_DIRmatched the_SRC_DIRoracle regex as a binary namedTWIN→ renamedTWIN_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'scopiesnow 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:
- Shared bodies as macros. The dedup engine instantiates one body in every location overlay as a
DEFINE_func_XXXXXXXX()macro fromsrc/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. - 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.yamlviadedup_integrate.group_members): 2,220 groups / 255,708 members, allh_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'sclearTbl40pair). Sources:engine_core.h2,215 ·ov_setters.h3 (name-parameterized SETTER/RETCONST, the SC01_005≡006 pair) ·clearTbl40.h1 ·func_80144B9C.h1 (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_SHBblock 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 carryexternpreambles, 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 lineDEFINE_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 itsexterns 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.ofiles (1,632 B, identical relocations); cc1 adds only a.filedirective thatasconsumes. A separate.cobject 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.-MMDtracking (: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_typesuffixes, extern scoping, 9 with pins) → one chosen text re-gated per member; type-carrying bodies viatools/lift_types.pyfirst. - 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 intarget_path(+ a carve delta: SC04_019 has one extra_jr_80181804split, SC03_015 two extra);overlays.mkblocks 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-healthon the header's deletion:cdecl.audit_differential(tools/cdecl.py:1292-1323opensengine_core.hunconditionally;make audit-cdeclis in the chain) andoverlay_src_split(:667 degrades to a silently EMPTY macro table). 51 tools buildsrc/<binary>paths themselves; onlycompile_only.pyreads the Makefile's<alias>_SRC_DIR;corpus.py:312maps link objects tosrc/{binary}/{subseg}.c.progress.pyundercounts ov_SC03_015 by 219 (single-site macro sites invisible toclassify()) — 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 definingvoid 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.hdeleted;func_80144B9C.hmoved toov/, its guard removed (one shape). End state:src/shared/= the prelude,engine_types.h, the per-function tree. Nothing else. - Twin binaries:
config/overlays.mkgetsov_B_TWIN_OF := ov_Aandov_B_SRC_DIR := src/ov_A; the Makefile maps a twin's objects to its OWNbuild/src/ov_B/from the primary's sources (-O0object lists and.dpaths twin-aware;check-all's per-binary parallelism never races); the twin's yaml = the primary's carve with its owntarget_path/sha1; itscheck.shastill proves it;src/ov_B/deleted. One oracle "binary → source dir" (Makefile-derived, R33) replaces the hardcodedsrc/<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_membersoracle, shorthand kept;source:= the header path;func:= the defined token (SHARED_FNfor the parameterized form, asCLEAR_TBL40is today); optionalform:; text-edited only, neveryaml.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 --checkgains C2c (the source is undersrc/shared/, defines exactly one function, andfuncis the token it uses — viacdecl) 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); noDEFINE_func_token insrc/; and a second, sig-blind oracle: no name-blind normalized definition text appears in >1 file undersrc/outsidesrc/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)
git grep -c '^#define DEFINE_func_' -- srcempty; noDEFINE_func_X()site;src/shared/engine_core.habsent; every registered body a plain-C header undersrc/shared/<space>/.tools/share_census.py --checkexit 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.make tools-healthOK with S1 strict and the macro-form guard; every consumer updated, frozen or retired per its dictionary row.make clean && make extract-all && make check-all→218 passed, 0 failed of 218(R22).- 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 (seegit log); after it the tree is clean and the fleet is green:check-all: 218 passed, 0 failed of 218from 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-healthregenerates 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 withmake kit-corpusafter ANY edit to a PhaseEnd/DIGEST/how-to/ the cookbook) andkit_coverage(every new rule needs aconfig/kit_coverage_map.tsvrow or a kernel citation, R92).- The probe's evidence is
.run/P35/probe/(probe_ledger.txt,probe_convert.py,buildA.log,buildB.log; theobjA/objB.ofiles 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,cmpper object. The probe converter's parser (macro_indexlast-wins, the one site shape, the prelude =engine_types.h+ theENGINE_SHBline copied fromengine_core.h:20) is the seed oftools/macro_to_header.py. - T1 — DONE.
tools/share_census.py(run it plain for the table;--checkfor S1;--selftestfor the fixture;--no-cacheafter 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-linevoid f(a, b) void *a; s16 b; {), implicit-return-type heads, a second head afterextern …;on one line, the asm-label alias in both__asm__(andasm(spellings,static inlinehelpers (no address). The census's per-class outputclasses.jsonlis the input for T3's twin accounting and T5's plan (share_body.py --planreads 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).