chore(phase-35): CLOSE — Gen3's dedup phase: one source per unique function (3,175 shared headers, 3,173 registry groups incl. the h_text tier, the macro header gone, the five twins from one directory, S1 a tools-health gate with a second oracle, 14 macro-era tools frozen and 4 retired behind a guard, the published counts corrected) — v2.1.0

- PhaseEnd_Phase35.md written; CURRENT_PHASE.md archived to phase-ends/logs/Phase35.md (R19); DIGEST §0/§2 appended (step 3b)
- T0–T8 + T5b across S94–S96 (S94 died at 91 % without a checkpoint; S95 recovered it from the transcript; S96 finished)
- close: R22 clean fleet 218/218; tools-health OK (S1 10,180/10,180, 0 violations; dedup-check 3173/0; the guard 0)
- rules: R96–R99 ratified at gate 1; candidates (a)–(g) proposed for Phase 36 gate 1
- v2.0.0 -> v2.1.0
This commit is contained in:
Drew T
2026-09-08 23:19:40 -06:00
parent c1a901373f
commit e6d98dd1d4
13 changed files with 7819 additions and 8 deletions
+5
View File
@@ -0,0 +1,5 @@
.venv/bin/python tools/tool_census.py --all
tool_census: 295 tool files (find == git ls-files) + 38 retired; classes {'LIVE': 236, 'ORPHAN': 30, 'REFERENCED': 29, 'RETIRED': 38}; dictionary rows 333
tool_census: wrote docs/tool-index.md
tool_census: wrote decomp-architect/tools/MANIFEST.md
tool_census: corpus materialised — 362 verbatim copies, 30 pointers, INDEX.md
+5
View File
@@ -0,0 +1,5 @@
.venv/bin/python tools/tool_census.py --all
tool_census: 295 tool files (find == git ls-files) + 38 retired; classes {'LIVE': 236, 'ORPHAN': 30, 'REFERENCED': 29, 'RETIRED': 38}; dictionary rows 333
tool_census: wrote docs/tool-index.md
tool_census: wrote decomp-architect/tools/MANIFEST.md
tool_census: corpus materialised — 362 verbatim copies, 30 pointers, INDEX.md
+476
View File
@@ -0,0 +1,476 @@
clean: removed build/, expected/, and the regenerated splat tree (asm/, assets/, undefined_*_auto.txt).
disc-extract: up to date — extracted/retail/ matches the committed manifest (sha1 e5c6019249dec3c71bb2cf40658a78439dddb037)
splat 0.41.0 (powered by spimdisasm 1.41.0)
0%| | 0/1096 [00:00<?, ?it/s]
Loading symbols (symbols.us): 0%| | 0/1096 [00:00<?, ?it/s]
Loading symbols (symbols.us): 100%|██████████| 1096/1096 [00:00<00:00, 214200.51it/s]
0%| | 0/47 [00:00<?, ?it/s]
Loading symbols (symbols.us.ram): 0%| | 0/47 [00:00<?, ?it/s]
Loading symbols (symbols.us.ram): 100%|██████████| 47/47 [00:00<00:00, 612212.07it/s]
0%| | 0/2 [00:00<?, ?it/s]
Scanning header: 0%| | 0/2 [00:00<?, ?it/s]
Scanning main: 0%| | 0/2 [00:00<?, ?it/s]
Rodata segment '800' may belong to the text segment '800'
Based on the usage from the function LzssDecodeSector to the symbol jtbl_80072A38
The rodata segment '800' has jumptables that are not aligned properly file-wise, indicating one or more likely file split.
File split suggestions for this segment will follow in config yaml format:
- [0x6324C, .rodata]
- [0x63388, .rodata]
- [0x633FC, .rodata]
Rodata segment '800_b' may belong to the text segment '800_b'
Based on the usage from the function func_8002B0B4 to the symbol jtbl_80072E44
Rodata segment '800_b_2' may belong to the text segment '800_b_2'
Based on the usage from the function func_8002DC68 to the symbol jtbl_80072F3C
The rodata segment '800_b_2' has jumptables that are not aligned properly file-wise, indicating one or more likely file split.
File split suggestions for this segment will follow in config yaml format:
- [0x63920, .rodata]
Rodata segment '800_c' may belong to the text segment '800_c'
Based on the usage from the function func_80035270 to the symbol jtbl_800732A0
Scanning main: 100%|██████████| 2/2 [00:01<00:00, 1.62it/s]
Scanning main: 100%|██████████| 2/2 [00:01<00:00, 1.62it/s]
0%| | 0/2 [00:00<?, ?it/s]
Splitting header: 0%| | 0/2 [00:00<?, ?it/s]
Splitting main: 0%| | 0/2 [00:00<?, ?it/s]
Splitting main: 100%|██████████| 2/2 [00:00<00:00, 2.23it/s]
Splitting main: 100%|██████████| 2/2 [00:00<00:00, 2.23it/s]
0%| | 0/2 [00:00<?, ?it/s]
Linker script header: 0%| | 0/2 [00:00<?, ?it/s]
Linker script main: 0%| | 0/2 [00:00<?, ?it/s]
Linker script main: 100%|██████████| 2/2 [00:00<00:00, 91.31it/s]
Split 340 KB (82.28%) in defined segments
header: 2 KB (0.50%) 1 split, 0 cached
c: 338 KB (81.78%) 85 split, 0 cached
unknown: 0 B (0.00%) from unknown bin files
ld_interleave --order: .main island = 8 pieces [53198.data.o, 800.o, 63470.data.o, 800_b.o, 800_b_2.o, 63940.data.o, 800_c.o, 63C4C.data.o]; pre=0 text=85 empties=166 bss=85
[ OK ] resident
[ OK ] ov_SC05_000
[ OK ] ov_SC01_000
[ OK ] ov_SC04_000
[ OK ] ov_SC06_000
[ OK ] ov_SC01_006
[ OK ] ov_SC01_005
[ OK ] ov_SC03_002
[ OK ] ov_SC01_077
[ OK ] ov_SC02_000
[ OK ] ov_SC04_018
[ OK ] ov_SC02_003
[ OK ] ov_SC04_019
[ OK ] ov_SC03_006
[ OK ] ov_SC01_001
[ OK ] ov_SC03_001
[ OK ] ov_SC01_004
[ OK ] ov_SC01_074
[ OK ] ov_SC01_008
[ OK ] ov_SC07_000
[ OK ] ov_SC02_004
[ OK ] ov_SC02_015
[ OK ] ov_SC02_021
[ OK ] ov_SC01_080
[ OK ] ov_SC01_009
[ OK ] ov_SC01_084
[ OK ] ov_SC02_016
[ OK ] ov_SC02_026
[ OK ] ov_SC02_005
[ OK ] ov_SC02_031
[ OK ] ov_SC02_011
[ OK ] ov_SC02_039
[ OK ] ov_SC02_028
[ OK ] ov_SC02_027
[ OK ] ov_SC02_035
[ OK ] ov_SC03_003
[ OK ] ov_SC02_017
[ OK ] ov_SC02_041
[ OK ] ov_SC03_010
[ OK ] ov_SC03_012
[ OK ] ov_SC03_011
[ OK ] ov_SC03_013
[ OK ] ov_SC03_023
[ OK ] ov_SC03_007
[ OK ] ov_SC03_024
[ OK ] ov_SC03_031
[ OK ] ov_SC03_089
[ OK ] ov_SC03_092
[ OK ] ov_SC03_029
[ OK ] ov_SC03_014
[ OK ] ov_SC03_090
[ OK ] ov_SC03_015
[ OK ] ov_SC03_030
[ OK ] ov_SC03_028
[ OK ] ov_SC03_095
[ OK ] ov_SC03_091
[ OK ] ov_SC03_096
[ OK ] ov_SC03_093
[ OK ] ov_SC03_094
[ OK ] ov_SC03_097
[ OK ] ov_SC03_101
[ OK ] ov_SC03_098
[ OK ] ov_SC03_099
[ OK ] ov_SC03_109
[ OK ] ov_SC03_108
[ OK ] ov_SC03_100
[ OK ] ov_SC03_110
[ OK ] ov_SC03_102
[ OK ] ov_SC03_105
[ OK ] ov_SC03_103
[ OK ] ov_SC03_112
[ OK ] ov_SC03_104
[ OK ] ov_SC03_113
[ OK ] ov_SC03_114
[ OK ] ov_SC03_111
[ OK ] ov_SC03_115
[ OK ] ov_SC03_116
[ OK ] ov_SC03_126
[ OK ] ov_SC03_121
[ OK ] ov_SC04_003
[ OK ] ov_SC03_117
[ OK ] ov_SC03_118
[ OK ] ov_SC04_008
[ OK ] ov_SC04_006
[ OK ] ov_SC03_119
[ OK ] ov_SC04_009
[ OK ] ov_SC03_125
[ OK ] ov_SC04_004
[ OK ] ov_SC04_007
[ OK ] ov_SC04_002
[ OK ] ov_SC04_005
[ OK ] ov_SC04_010
[ OK ] ov_SC03_124
[ OK ] ov_SC04_012
[ OK ] ov_SC04_021
[ OK ] ov_SC04_016
[ OK ] ov_SC05_006
[ OK ] ov_SC05_002
[ OK ] ov_SC05_004
[ OK ] ov_SC04_015
[ OK ] ov_SC05_009
[ OK ] ov_SC04_020
[ OK ] ov_SC05_003
[ OK ] ov_SC05_001
[ OK ] ov_SC05_007
[ OK ] ov_SC05_005
[ OK ] ov_SC05_008
[ OK ] ov_SC04_011
[ OK ] ov_SC05_011
[ OK ] ov_SC05_010
[ OK ] ov_SC05_019
[ OK ] ov_SC06_015
[ OK ] ov_SC06_013
[ OK ] ov_SC06_014
[ OK ] ov_SC06_008
[ OK ] ov_SC06_010
[ OK ] ov_SC06_011
[ OK ] ov_SC06_016
[ OK ] ov_SC05_017
[ OK ] ov_SC05_018
[ OK ] ov_SC06_020
[ OK ] ov_SC06_018
[ OK ] ov_SC06_027
[ OK ] ov_SC06_025
[ OK ] ov_SC06_006
[ OK ] ov_SC06_022
[ OK ] ov_SC06_024
[ OK ] md_MAIN_013
[ OK ] ov_SC07_008
[ OK ] md_MAIN_014
[ OK ] md_MAIN_016
[ OK ] md_MAIN_015
[ OK ] ov_SC07_002
[ OK ] ov_SC07_001
[ OK ] md_MAIN_018
[ OK ] md_MAIN_017
[ OK ] ov_SC06_030
[ OK ] md_MAIN_019
[ OK ] md_MAIN_020
[ OK ] md_MAIN_021
[ OK ] md_MAIN_022
[ OK ] md_MAIN_023
[ OK ] md_MAIN_024
[ OK ] md_MAIN_025
[ OK ] md_MAIN_026
[ OK ] md_MAIN_028
[ OK ] md_MAIN_027
[ OK ] md_MAIN_029
[ OK ] md_MAIN_030
[ OK ] ov_SC07_009
[ OK ] md_MAIN_031
[ OK ] ov_MAIN_012
[ OK ] md_MAIN_033
[ OK ] md_MAIN_032
[ OK ] md_MAIN_035
[ OK ] md_MAIN_034
[ OK ] md_MAIN_036
[ OK ] ov_SC06_033
[ OK ] ov_SC07_011
[ OK ] ov_SC06_032
[ OK ] md_MAIN_037
[ OK ] md_MAIN_039
[ OK ] md_MAIN_040
[ OK ] md_MAIN_038
[ OK ] md_MAIN_041
[ OK ] md_MAIN_042
[ OK ] md_MAIN_043
[ OK ] md_MAIN_044
[ OK ] ov_SC06_029
[ OK ] md_MAIN_045
[ OK ] md_MAIN_046
[ OK ] md_MAIN_047
[ OK ] md_MAIN_008
[ OK ] md_MAIN_011
[ OK ] ov_SC07_010
[ OK ] md_MAIN_001
[ OK ] md_SC03_074
[ OK ] md_SC03_073
[ OK ] md_SC03_078
[ OK ] md_SC03_075
[ OK ] md_SC03_077
[ OK ] ov_SC07_007
[ OK ] md_SC03_076
[ OK ] md_SC03_133
[ OK ] md_SC03_132
[ OK ] md_SC03_079
[ OK ] md_SC03_137
[ OK ] md_SC03_134
[ OK ] md_SC03_136
[ OK ] ov_SC03_107
[ OK ] md_SC03_135
[ OK ] md_SC04_025
[ OK ] md_SC04_024
[ OK ] md_SC03_138
[ OK ] md_SC04_026
[ OK ] md_MAIN_003
[ OK ] md_SC04_029
[ OK ] md_SC04_028
[ OK ] md_SC04_027
[ OK ] md_SC04_030
[ OK ] md_SC05_023
[ OK ] md_SC05_024
[ OK ] md_SC05_025
[ OK ] md_SC05_028
[ OK ] md_MAIN_009
[ OK ] md_MAIN_007
[ OK ] md_SC05_027
[ OK ] md_SC03_053
[ OK ] ov_SC02_037
[ OK ] md_SC05_026
[ OK ] md_SC05_029
[ OK ] md_SC03_054
[ OK ] md_SC03_056
[ OK ] md_SC02_009
[ OK ] ov_SC07_006
[ OK ] md_SC07_004
[ OK ] md_SC07_003
extract-all: 217 extracted, 0 failed of 217 (+ main, serial)
[ OK ] resident
[ OK ] ov_SC01_000
[ OK ] ov_SC05_000
[ OK ] ov_SC01_006
[ OK ] ov_SC01_005
[ OK ] ov_SC01_001
[ OK ] ov_SC04_000
[ OK ] ov_SC03_002
[ OK ] ov_SC03_006
[ OK ] ov_SC06_000
[ OK ] ov_SC04_019
[ OK ] ov_SC01_077
[ OK ] ov_SC04_018
[ OK ] ov_SC03_001
[ OK ] ov_SC02_003
[ OK ] ov_SC02_000
[ OK ] ov_SC01_004
[ OK ] ov_SC01_074
[ OK ] ov_SC07_000
[ OK ] ov_SC02_004
[ OK ] ov_SC01_008
[ OK ] ov_SC01_080
[ OK ] ov_SC01_009
[ OK ] ov_SC02_015
[ OK ] ov_SC01_084
[ OK ] ov_SC02_016
[ OK ] ov_SC02_021
[ OK ] ov_SC02_026
[ OK ] ov_SC02_011
[ OK ] ov_SC02_017
[ OK ] ov_SC02_005
[ OK ] ov_SC02_039
[ OK ] ov_SC02_031
[ OK ] ov_SC02_027
[ OK ] ov_SC02_041
[ OK ] ov_SC03_003
[ OK ] ov_SC02_035
[ OK ] ov_SC02_028
[ OK ] ov_SC03_012
[ OK ] ov_SC03_010
[ OK ] ov_SC03_007
[ OK ] ov_SC03_011
[ OK ] ov_SC03_013
[ OK ] ov_SC03_023
[ OK ] ov_SC03_014
[ OK ] ov_SC03_015
[ OK ] ov_SC03_030
[ OK ] ov_SC03_031
[ OK ] ov_SC03_024
[ OK ] ov_SC03_029
[ OK ] ov_SC03_089
[ OK ] ov_SC03_092
[ OK ] ov_SC03_028
[ OK ] ov_SC03_090
[ OK ] ov_SC03_093
[ OK ] ov_SC03_094
[ OK ] ov_SC03_096
[ OK ] ov_SC03_095
[ OK ] ov_SC03_091
[ OK ] main
[ OK ] ov_SC03_098
[ OK ] ov_SC03_097
[ OK ] ov_SC03_100
[ OK ] ov_SC03_101
[ OK ] ov_SC03_099
[ OK ] ov_SC03_102
[ OK ] ov_SC03_109
[ OK ] ov_SC03_103
[ OK ] ov_SC03_108
[ OK ] ov_SC03_110
[ OK ] ov_SC03_104
[ OK ] ov_SC03_111
[ OK ] ov_SC03_113
[ OK ] ov_SC03_105
[ OK ] ov_SC03_114
[ OK ] ov_SC03_112
[ OK ] ov_SC03_115
[ OK ] ov_SC03_116
[ OK ] ov_SC03_117
[ OK ] ov_SC03_118
[ OK ] ov_SC03_126
[ OK ] ov_SC03_119
[ OK ] ov_SC03_121
[ OK ] ov_SC03_125
[ OK ] ov_SC04_003
[ OK ] ov_SC04_006
[ OK ] ov_SC04_008
[ OK ] ov_SC04_004
[ OK ] ov_SC03_124
[ OK ] ov_SC04_002
[ OK ] ov_SC04_007
[ OK ] ov_SC04_005
[ OK ] ov_SC04_009
[ OK ] ov_SC04_010
[ OK ] ov_SC04_012
[ OK ] ov_SC04_021
[ OK ] ov_SC04_016
[ OK ] ov_SC04_015
[ OK ] ov_SC04_020
[ OK ] ov_SC04_011
[ OK ] ov_SC05_003
[ OK ] ov_SC05_006
[ OK ] ov_SC05_002
[ OK ] ov_SC05_001
[ OK ] ov_SC05_005
[ OK ] ov_SC05_004
[ OK ] ov_SC05_008
[ OK ] ov_SC05_007
[ OK ] ov_SC05_009
[ OK ] ov_SC05_010
[ OK ] ov_SC05_011
[ OK ] ov_SC05_019
[ OK ] ov_SC05_018
[ OK ] ov_SC06_008
[ OK ] ov_SC06_015
[ OK ] ov_SC06_006
[ OK ] ov_SC06_013
[ OK ] ov_SC06_011
[ OK ] ov_SC06_014
[ OK ] ov_SC06_010
[ OK ] ov_SC06_016
[ OK ] ov_SC06_020
[ OK ] ov_SC05_017
[ OK ] ov_SC06_018
[ OK ] ov_SC06_022
[ OK ] ov_SC06_024
[ OK ] ov_SC06_025
[ OK ] ov_SC06_027
[ OK ] md_MAIN_013
[ OK ] md_MAIN_014
[ OK ] ov_SC07_008
[ OK ] md_MAIN_015
[ OK ] ov_SC07_009
[ OK ] ov_SC07_001
[ OK ] ov_SC06_030
[ OK ] md_MAIN_017
[ OK ] md_MAIN_016
[ OK ] md_MAIN_018
[ OK ] md_MAIN_019
[ OK ] ov_SC07_002
[ OK ] md_MAIN_020
[ OK ] md_MAIN_021
[ OK ] md_MAIN_022
[ OK ] md_MAIN_023
[ OK ] md_MAIN_024
[ OK ] md_MAIN_025
[ OK ] md_MAIN_026
[ OK ] md_MAIN_028
[ OK ] md_MAIN_027
[ OK ] md_MAIN_029
[ OK ] ov_SC07_010
[ OK ] md_MAIN_030
[ OK ] md_MAIN_031
[ OK ] md_MAIN_032
[ OK ] ov_SC06_029
[ OK ] md_MAIN_033
[ OK ] md_MAIN_034
[ OK ] md_MAIN_035
[ OK ] md_MAIN_036
[ OK ] ov_SC07_007
[ OK ] md_MAIN_037
[ OK ] md_MAIN_039
[ OK ] md_MAIN_038
[ OK ] md_MAIN_040
[ OK ] md_MAIN_042
[ OK ] md_MAIN_041
[ OK ] md_MAIN_043
[ OK ] md_MAIN_045
[ OK ] md_MAIN_044
[ OK ] md_MAIN_046
[ OK ] md_MAIN_001
[ OK ] md_MAIN_047
[ OK ] md_MAIN_008
[ OK ] md_MAIN_011
[ OK ] md_SC03_073
[ OK ] ov_MAIN_012
[ OK ] ov_SC07_006
[ OK ] md_SC03_074
[ OK ] md_SC03_075
[ OK ] ov_SC06_032
[ OK ] ov_SC06_033
[ OK ] md_SC03_078
[ OK ] md_SC03_077
[ OK ] ov_SC07_011
[ OK ] md_SC03_079
[ OK ] md_SC03_076
[ OK ] md_SC03_132
[ OK ] md_SC03_133
[ OK ] md_SC07_003
[ OK ] md_SC03_134
[ OK ] md_SC03_137
[ OK ] md_SC03_138
[ OK ] md_MAIN_003
[ OK ] md_SC04_025
[ OK ] md_SC04_024
[ OK ] md_SC03_136
[ OK ] md_SC04_029
[ OK ] md_SC04_026
[ OK ] md_SC03_135
[ OK ] md_SC04_030
[ OK ] md_SC05_023
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -31,7 +31,7 @@
},
"duplicate_text_classes": 6398,
"duplicate_text_sites": 17779,
"elapsed_s": 26.6,
"elapsed_s": 22.6,
"flags": {
"ALIAS": 32,
"E": 3826,
+1 -1
View File
@@ -37,4 +37,4 @@ share_census: 218 binaries · 362,389 sig instances · 362,389 classified · 0 U
B E,F 11852 x 2 0x80014554,0x8001455C,0x8001513C func_80014554,func_8001455c
A - 141 x 167 0x80163C2C func_80163c2c
A - 141 x 165 0x80178004 func_80178004
macro sites 0 · duplicate-text classes 6,398 (17,779 sites) · elapsed 26.6 s
macro sites 0 · duplicate-text classes 6,398 (17,779 sites) · elapsed 22.6 s
@@ -41,7 +41,13 @@ instrument findings fixed (cdecl's scratch dir, two wiki citations, kit_coverage
**Pending by name:** the preset's creation by decomp.me's maintainers, a reply from Archipelago, frogress. Candidates (a)–(d) proposed. **Gen3 opens at Phase 35** — its seed now includes the S91-b types doctrine (R95, the canonical
type layer).
**Phase 35 OPEN (2026-09-08, S94; gate 1 in plan mode at Max) — Gen3's first phase, the DEDUP phase: "one source per unique function."**
**Phase 35 CLOSED 2026-09-08 (v2.1.0; `PhaseEnd_Phase35.md`) — Gen3's first phase, the DEDUP phase: "one source per unique function."**
Three sessions (S94–S96) / 48 commits: every shared body one plain-C header under `src/shared/` included at each site (3,175 headers, the
8.8 MB macro header gone), the five twins from one source directory, the same-address backlog 1,099 classes / 4,755 copies → 51 ledgered
/ 160, a new `h_text` registry tier for 38 byte-variant functions, S1 a tools-health gate with a second oracle, 14 macro-era tools frozen +
4 retired behind a guard, the published counts corrected (+459 functions; REAL 360,744 → 350,533 with EMPTY up the same). R96–R99 ratified;
candidates (a)–(g) proposed. **Gen3 continues at Phase 36 — pins off** (Drew's order dedup → pins → structs → names). The open paragraph:
*Phase 35 OPEN (2026-09-08, S94; gate 1 in plan mode at Max)*
Drew set the Gen3 order dedup → pins → structs → names (one phase each, planned one at a time). The phase converts the 3,516 distinct
`DEFINE_func_` macro bodies (5,147 define lines) into per-function plain-C headers under `src/shared/<space>/` included at each member's
site (sotn's shape, verified from its tree), collapses the five identical-payload twin overlays onto one source directory each, shares
@@ -193,6 +199,15 @@ dry-runs in a throwaway judged by script (run 5 PASS 20/20). Findings: the kit h
the S91-b types hindsight (a banking + width lever → the canonical type layer at Phase 6, DK-65/G62); a typed verify figure wrong twice;
four false judge flags in five runs, all the instrument's. Rules: R74–R83 ratified at gate 1; candidates (i)–(xii) proposed.
**P35 (2026-09-08, v2.1.0) GEN3 OPENS — THE DEDUP PHASE.** 3 sessions (S94–S96) / 48 commits. Gate 1 reversed the 2026-09-02 "leave the
backlog" decision on sotn's tree (it shares once, by an include). T1 `share_census` (362,389 instances, 0 unaccounted, 10,180 classes);
T2 the health chain learns the include + twin forms; T3 five twin pairs → one source dir (166 files deleted); T4 `macro_to_header`: 246,347
sites → 2,215 headers, 213/213 binaries and 4,121/4,121 objects byte-identical, `engine_core.h` deleted; T5 `share_body` (bucket 0 183 →
135 shared / 48 ledgered; bucket new 915 → 914 / 3; a re-exemplar), the S94 death at 91 % and the S95 transcript recovery, four tool
defects fixed at their cause; T5b the `h_text` tier (38 classes / 2,030 sites); T6 14 frozen / 4 retired / the guard; T7 S1 strict + C2c/C2d
in tools-health, the digest corrected; T8 the record (wiki, cookbook §453, decision log). Close: R22 218/218; S1 10,180/10,180, 0
violations; fleet clean-run 157 s → 84–90 s. Rules: R96–R99 ratified; candidates (a)–(g).
## 3. Every rule, in full (transcribe these at session start; P/G/H/X are in PROJECT_CONTEXT.md)
- **R1 — H1 relaxed while private.** ROM-derived content (`asm/`, `assets/`, `extracted/`, decompressed `.CD`) MAY be
committed while the repo is private; accidental inclusion is not a violation. The raw multi-GB disc dump stays ignored
@@ -0,0 +1,205 @@
# PhaseEnd — Phase 35: Gen3 opens — the dedup phase, "one source per unique function"
**Date:** 2026-09-08 · **Project Version:** 2.1.0 · **Phase Status:** Complete (milestone: see §Milestone — every item with its literal output; gate 2 = Drew's close commit) · **Generation:** Gen3 (the first phase; Drew's Gen3 order: dedup → pins → structs → names, one phase each, planned one at a time)
> Chartered at gate 1 (S94, 2026-09-08, plan mode, Max) from `docs/gen3-handoff.md` + `docs/gen3-standards.md`, on evidence read from
> sotn-decomp's tree that reversed the 2026-09-02 "leave the dedup backlog" decision. Ran **three sessions (S94–S96, all 2026-09-08)** and
> **48 commits** (`48170fd7f..HEAD`, plus this close). The granular trail — every task's verify lines, the S94 death and the S95
> recovery, every tool defect with its cause — is at **`phase-ends/logs/Phase35.md`** (R19, on demand). Owner decisions (Drew): gate 1's
> four (twins → one source directory; cross-address classes censused and deferred; macro-era tools frozen with a loud refusal; R96–R99
> ratified); no "trivial" exception; the tooling must know there is one source per unique function (→ the S1 gate); the recovery session's
> scope ("capture only"); the effort levels per step (Max for two decisions delegated to Claude, high/xHigh otherwise); T9 run in the same
> session at xHigh.
## Build Log
**The phase in one line:** every shared function body became one plain-C header included at each member's site (sotn's shape), the
five identical-payload overlay twins build from one source directory, the 4,755 already-matched duplicate copies of 1,099 same-address
classes were shared down to 160 copies in 51 ledgered classes, 38 functions whose bytes vary per overlay share one text through a new
registry tier, the invariant "one source per unique function" is a `tools-health` gate with a second, disagreeing oracle, the macro-era
tools are frozen or retired behind a guard, the published numbers were corrected where the old counting was blind — and every step was
proven by the 218 hashes from a clean rebuild.
**Files created/changed and complete — do not recreate** (category summaries; the per-commit list is `git log 48170fd7f..HEAD` and the
archived log):
- **The shape (T3, T4, T5, T5b).** `src/shared/engine_prelude.h` (what every overlay/module TU includes at line 2), `src/shared/{ov,main,
slot_800CAE08,slot_801E25E8,slot_801EF468}/func_<VRAM>[__<h8>|__t<h8>].h` — **3,175 headers**, one per shared body (2,215 converted from
the macro header at T4, 914 + 1 + 38 written by the share tool); `src/shared/engine_core.h`, `ov_setters.h`, `clearTbl40.h` deleted;
the whale `func_80144B9C.h` moved under `ov/`; **3,173 registry groups** in `config/dedup.us.yaml` (2,220 at the open; 38 of them
`tier: h_text` in the verbose member form with per-member `h_exact`); `config/dedup_exceptions.tsv` (the S1 ledger: 51 rows, each with
the compiler's diagnostic and a reason code); `config/overlays.mk` `<twin>_TWIN_OF/_SRC_DIR` for SC01_006, SC03_119, SC02_003, SC04_019,
SC03_015 (their `src/` directories deleted, 166 files; the twins' yamls = the primaries' carves with `create_c_files: False`, their
`JTBL_PADS` lines regenerated); the Makefile's twin block.
- **The tools (T1, T2, T4, T5, T5b, T6, T7).** `tools/share_census.py` (the S1 census + gate: every sig instance resolves to one source form;
verdicts A/B/C/D/M, flags E/F/TWIN/PINS/ALIAS; `--selftest` fixture; `--check --strict-macros --strict-text`; `text_classes`; the second,
sig-blind oracle keyed by (text, address)), `tools/macro_to_header.py` (the T4 converter, kept as `share_body`'s library), **`tools/
share_body.py`** (the permanent share tool: `--plan / --apply --bucket extend|new|text / --reexemplar / --repair-registry`, the
per-binary gate with object comparison and a snapshot-based bisect, the ledger, `--batches 1`), `tools/share_body_cycle.sh` (the
unattended batch cycle: batch → exit code → phase-log entry → commit → periodic clean fleet run), `tools/frozen.py` (the one refusal
14 FROZEN tools print from `main()`), `tool_census.py` (status FROZEN; the `ast` macro-form guard with `--guard-root` for the negative
control), `dedup_integrate.py` (C2c/C2d; the `h_text` tier with C1 per member), `progress.py` (the include form as a definition, the
source-dir oracle, the empty-shared fold, `unique_function_bodies`, `duplicate_source_copies/_classes`, `text_tier_*`,
`deferred_same_address_*`, a dated `corrections` list, the README sentence), `corpus.py` (`src_dir/twin_of`, the one source-dir oracle),
16 health-chain tools taught the include + twin forms (T2), 12 tools' dead macro branches dropped (T6); `tools/sunset/`: `dedup_propagate`,
`dedup_extend` (their library surface moved verbatim into `share_body`), `macro_draft`, `test_reconcile_ledger`; the Makefile's
`tools-health` gained `share_census --selftest` and the strict check before `report`.
- **The record (T8).** `docs/wiki/The-dedup-engine.md` rewritten for the shared-source model; `Repository-layout.md`,
`Where-the-project-goes-next.md`, `Verification-and-progress.md`, how-to ch.10, README prose and the generated block (with the
"One source per unique function" sentence), `docs/gen3-standards.md` (§4 row struck, the DoD's "0 macro bodies" met), `docs/gen3-
handoff.md` (dated snapshots), cookbook **§453** + a retirement banner on §14, `docs/decision-log.md` P35 (R31), `docs/accelerators.md`
P35 (five), DIGEST §0/§2/§3/§4, `docs/SETUP.md` P35 sections (T1, T3–T5, T6, T7/T5b, the context guard), `docs/tool-index.md` and the
kit corpus regenerated, the memory `dedup-backlog-leave-it` rewritten as REVERSED.
- **Evidence (`.run/P35/`, allowlisted text):** `baseline/` (every R22 and tools-health log, the kit-corpus logs), `census/` (the census
json/txt, `check_t5.txt`), `share/` (every batch record `batch_<label>.json`, every run log, the 146 per-binary gate logs, the registry
repair record, the old header of the re-exemplar), `convert/` (T4's batch scripts, ledger and apply logs), `probe/` (T0's object A/B).
- **Outside the repository:** `~/.claude/statusline.sh` writes the context percentage; `~/.claude/ctx_guard.sh` (a user-settings
`PostToolUse` hook) injects "90% context. decide on the best place to checkpoint for a fresh session" once per session — built after
S94 died at 91 % without a checkpoint; it fired in S96 exactly at the right moment.
**Tools/packages installed:** none (no apt/pip). Agents: three at gate 1 (two Explore, one Plan; ~680k tokens); none during execution —
every task was the coordinator's own work and deterministic gates.
**Verification results (literal, at close — S96, HEAD `c1a901373` + this close):**
- T9 R22 from clean: `extract-all: 217 extracted, 0 failed of 217 (+ main, serial)` · **`check-all: 218 passed, 0 failed of 218`** · `wall=87.62 s` · exit 0` (`.run/P35/baseline/r22_t9.log`).
- T9 `make tools-health` (foreground): `tools-health: OK — sigs fresh; corpus(+resident) + cdecl + binaries + report(lint+dedup) + cookbook-index all green.` (run 2, 431 s, exit 0; run 1 was red only at the kit corpus, which had not yet copied this file and the DIGEST edit — regenerated, re-run) (`.run/P35/baseline/tools_health_t9.log`) carrying `S1: one source per unique function — 10,180 classes, 10,180 satisfied (3,507 twin-covered, 51 excepted, 3,801 deferred cross-address), 0 VIOLATION(S) — OK`, `dedup-check: 3173 validated, 0 failed | C1 coverage 262573/262573 members signed`,
`macro-form guard: 0 LIVE tools reference the retired form (217 scanned, 14 frozen, 6 whitelisted detectors, 38 retired)`.
- `git grep -c '^#define DEFINE_func_' -- src` → empty; `tools/macro_to_header.py --verify` → `OK — 0 macro sites, no macro header, the
prelude present`; the census `macro sites 0` (two block-comment lines in prose still mention the token — comments are the record);
`src/shared/engine_core.h` absent.
- `tools/share_census.py --selftest` → `7/7 verdicts correct`; the strict check's second oracle: `0 same-address definition texts
duplicated across TUs`, `381 … inside the deferred cross-address classes (1,668 sites)`.
- `tools/progress.py --json --readme --check` → fresh; `timeline --check: fresh (74 rows)`; `doc_links` strict `0 pending, 0 broken`;
`wiki_render --selftest: 12 cases, 0 failed; 32 pages, 0 unlisted`; `cookbook-index OK (1170 sections)`; `kit_coverage: OK`;
`tool_census --check: OK` (the guard: 217 scanned, 14 frozen, 6 whitelisted detectors, 38 retired).
- The negative controls on record (R39): the guard against a worktree of the pre-T4 tree flags exactly the 15 tools with macro-form code
(`--guard-root`); one member's include reverted in place → `S1 … 1 VIOLATION(S) — FAIL` naming the class, C2d naming the member, restored → OK.
**Milestone achieved (gate 2 — Drew's close commit is the confirmation; each item with its literal output):**
1. `git grep -c '^#define DEFINE_func_' -- src` empty; no `DEFINE_func_X()` site (`macro_to_header --verify` 0; the census 0);
`src/shared/engine_core.h` absent; every registered body a plain-C header under `src/shared/<space>/` (`dedup-check` C2c, 3,173 groups).
2. `tools/share_census.py --check --strict-macros --strict-text` exit 0: `S1: one source per unique function — 10,180 classes, 10,180
satisfied (3,507 twin-covered, 51 excepted, 3,801 deferred cross-address), 0 VIOLATION(S) — OK` — same-vram duplicate copies 160, each
in a ledgered class with its reason; the five twins built from one source directory each (`audit-binaries` CHECK 3b); the cross-vram
classes published as a deferred count (3,801; plus the 381 tiny-body texts / 1,668 copies inside them).
3. `make tools-health` OK with S1 strict and the macro-form guard; every consumer updated (16 + 12), frozen (14) or retired (4) per its
dictionary row.
4. `make clean && make extract-all && make check-all` → `check-all: 218 passed, 0 failed of 218` (R22, T9 and after every batch).
5. README/wiki/kit regenerated (R75), decision log (R31), SETUP rows (R21), this PhaseEnd + the DIGEST; v2.1.0.
**Next:** **Phase 36 — pins off** (Drew's Gen3 order). Open a fresh session in **plan mode, Max** (Tier 1) from `docs/gen3-handoff.md`
§5–§7 and `docs/gen3-standards.md`: the 44,243 `register … __asm__` pins (most come off byte-identical once the source shape is right —
Phase 32's finding), family-batched, byte-gated per binary, R22 per batch; the S1 gate stays in the chain (a pin removed inside a shared
header reaches every member — one edit, one gate). Inherited by name: the 51 ledgered declaration conflicts (the types phase), the 3,801
cross-address classes and the 381 tiny-body texts (the names phase's parameterized form), the kit split, xsig v2.
## Roadmap delta (what Phase 35 changed about the road ahead)
- **The Gen3 charter's first item is met and measured:** "shared engine functions live as C, not as macros" — 0 macro bodies; the
charter's "5,147" counted define lines (3,516 distinct macros; R14/R41 correction published in the log and the wiki).
- **A new registry tier exists (`h_text`)** for the shape the byte tier cannot hold: identical C whose bytes vary per binary through
the translation unit's declaration environment. The types phase must treat those 38 headers as compiling per unit by design.
- **The names phase inherits a precise list:** 3,801 cross-address classes (E flag), 381 same-address tiny-body texts inside them, and
the parameterized `SHARED_FN` form as the intended shape (one worked example, `clearTbl40`).
- **The types phase inherits the ledger:** 50 declaration conflicts in the late-onboarded overlays (`config/dedup_exceptions.tsv`,
each with its diagnostic) and one byte-variant body — exactly where a canonical declaration layer (R95) pays.
- **Scale, honestly (R41):** the plan priced the phase at 7–8 sessions; it took three (one of them a recovery), because the tooling was
built to gate itself and the batches ran unattended. The cost that was real: one dead session's 35 minutes rebuilt from its transcript,
four tool defects found from their artifacts, and nine red health-chain runs across T6–T7, every one an instrument finding.
## Deviations
| Item | Plan (gate-1 plan) | Actual | Reason |
|---|---|---|---|
| Sessions | 7–8 | 3 (S94–S96) + this close | the gates were the tool's; batches ran unattended (`share_body_cycle.sh`) |
| S94 | a checkpoint at every pause | died at 91 % context waiting on a background run, no checkpoint for T5; S95 rebuilt the state from the transcript with no runs (Drew's scope) | two bank commits carried no log line; rule candidate (b); the context guard built |
| `share_body` | designed at T5 | four defects found from S94's artifacts and fixed at S96: the cause extractor (no "error" token in gcc 2.7.2), `git checkout` as restore, a twin's duplicate edit, wholesale registry extension | each caught by a gate or a known-true control; cookbook §453 |
| Bucket 0's residue | ledgered with a message class | 48 late-overlay declaration conflicts ledgered TU-CONFLICT for the types phase; `E_func_80168B70` re-exemplared from the majority text (Claude's delegated decision at Max) | the header carried a 7-overlay minority spelling; the cast form compiles under both environments (141/141) |
| The second oracle | "a second, disagreeing oracle" | it disagreed: 38 same-address texts / 2,030 copies byte-variant per binary → **T5b added** (the `h_text` tier; Claude's delegated decision at Max); 381 tiny-body texts inside the deferred classes stay deferred | no later phase would remove the copies; one header per address for the empties would be undone by the names phase's form |
| T6's counts | freeze 7, retire 3 | freeze **14**, retire **4**; the guard's census measured 30 hits, not 22; `family_cousins` stays LIVE (`make atlas` runs it) with its dead branch dropped | the plan's counts came from a partial census |
| `progress.py` | "the +219 correction" | +459 (SC03_015's 219 + SC03_118's 3 + the never-extended members of five groups) and REAL −10,211 → EMPTY (the fold); both dated in `progress.json` `corrections` | the include form made invisible sites visible; the macro-era fold had counted empty shared bodies as REAL |
| T9 | Max, fresh session | run in S96 at xHigh (Drew) | owner's call; the checkpoint carried the brief |
## What we believed, what failed, and what we would do sooner (for the retrospective; detail in `docs/decision-log.md` P35)
- **Believed (2026-09-02):** sotn writes duplicate functions explicitly, so ~12,000 duplicate copies are the normal end state. **False:**
read from its tree, sotn shares stage code once and instantiates it by an include. **Sooner:** read the target project's tree, never a
memory of it, before setting a policy on its precedent.
- **Believed:** refreshing the checkpoint at every task close was enough. **S94 refreshed it five times and still died with 35 minutes
of state only in its transcript** — two bank commits inside a task carried no log line, and a background wait consumed the rest.
**Sooner:** every commit that advances a task carries its log line and the headline; past ~85 % context, checkpoint before any long wait.
- **Believed:** a green per-binary gate meant the tool's edits were what it reported. **Its restore was `git checkout`,** which wiped the
previous batch's uncommitted shares and returned green; its cause lines read "Error 33" for 254 of 303 rejections. **Sooner:** a tool's
restore path is part of the tool (R57); read a compiler's diagnostics by their form.
- **Believed:** the byte join sees every duplicate. **The text oracle found 38 functions in 2,030 copies it could never class.** **Sooner:**
build the disagreeing oracle before the batch runs, and measure the disagreement before believing either side (R34).
- **Cost:** no model tokens beyond the coordinator and gate 1's three agents; the phase's expense was wall-clock in gates (≈2.5 h of
`make check` and fleet runs) and the recovery (≈1 h reading a 6 MB transcript).
## Commit Message
``
(Phase 35 landed as 48 commits 48170fd7f..c1a901373, 2026-09-08 (S94–S96). This close = the archived log + this PhaseEnd + the DIGEST
update + the kit's record copies, Drew's milestone-close commit.)
chore(phase-35): CLOSE — Gen3's dedup phase: one source per unique function (3,175 shared headers, 3,173 registry groups incl. the
h_text tier, the macro header gone, the five twins from one directory, S1 a tools-health gate with a second oracle, 14 macro-era tools
frozen and 4 retired behind a guard, the published counts corrected) — v2.1.0
- PhaseEnd_Phase35.md written; CURRENT_PHASE.md archived to phase-ends/logs/Phase35.md (R19); DIGEST §0/§2 appended (step 3b)
- T0–T8 + T5b across S94–S96 (S94 died at 91 % without a checkpoint; S95 recovered it from the transcript; S96 finished)
- close: R22 clean fleet 218/218; tools-health OK (S1 10,180/10,180, 0 violations; dedup-check 3173/0; the guard 0)
- rules: R96–R99 ratified at gate 1; candidates (a)–(g) proposed for Phase 36 gate 1
- v2.0.0 -> v2.1.0
``
## Rules Added This Phase
**Ratified at gate 1 (2026-09-08):** **R96–R99** (the PhaseEnd_Phase34 candidates (a)–(d)); full text in `phase-ends/DIGEST.md` §3.
**Candidates recorded in the log, for Drew to accept, modify or reject at Phase 36 gate 1 (P10):**
| Rule | Reason |
|---|---|
| **(a) A shared body has exactly one source; a duplicate copy is a defect the health chain asserts, and its count is published with its rule.** | The phase's invariant (S1), a `tools-health` gate; 1,099 classes / 4,755 copies → 51 / 160, every remainder ledgered with its diagnostic. |
| **(b) Every commit that advances a task — an intra-task bank included — carries its log line and the 🛑 headline; a checkpoint older than HEAD is a dead session's checkpoint.** | S94 refreshed the block at every task close, made two T5 bank commits with no log line, then died at 91 % context; S95 rebuilt 35 minutes of state from the transcript. |
| **(c) A tool that restores files restores from its own snapshot, never `git checkout` on a tree it did not commit.** | `share_body`'s first bisect wiped the previous batch's uncommitted shares (~50 sites) and returned green. |
| **(d) A failure-cause extractor is negative-controlled against the compiler's real message forms, not against the word "error".** | gcc 2.7.2 prints errors without it and exits 33; 254 of 303 rejection lines read "Error 33". |
| **(e) Build the disagreeing oracle before the batch runs, and measure its disagreement before believing either side (R34 operated).** | The text oracle's 4,312 hits decomposed into twin false positives, the gate-1 deferral, and 38 genuine byte-variant functions — three different actions. |
| **(f) A registry lists a member only after the gate has spoken for it; a listed member whose site does not share is a defect the check names.** | The first pass extended 788 members wholesale; 317 were private after the run (C2d exists now). |
| **(g) A policy taken on a remembered precedent is a belief — read the target project's tree.** | The 2026-09-02 deferral rested on one parenthetical about a cross-jump idiom. |
## PhaseEnd Changelog
**v2.0.0 → v2.1.0 — Phase 35 complete (Gen3's first phase).** Every shared function body in the fleet is one plain-C header included at
each member's site, sotn's shape, verified from its tree; the 8.8 MB macro header and its 5,147 define lines are gone; the five overlay
twins build from one source directory each; the same-address duplicate backlog fell from 1,099 classes and 4,755 private copies to 51
ledgered classes and 160 copies, each with the compiler's own reason; 38 functions whose bytes vary per overlay share one text through a
new registry tier; the invariant "one source per unique function" is asserted on every health-chain run by a census with a self-test and
a second, sig-blind oracle, and by four registry checks; fourteen macro-era tools are frozen and four retired behind a guard that scans
every live tool; the published numbers were corrected where the macro-era counting had been blind, dated and explained. Every batch was
proven by the 218 hashes from a clean rebuild, which now takes 84–90 seconds instead of 157. R96–R99 ratified; seven candidates proposed.
## Plain-English Recap
This phase made the code say each thing once. Before it, when the same function appeared in many of the game's 141 level files, our source
held it as a macro in one enormous header, or as a private copy pasted into each level, thousands of times over. Now every shared function
is one small ordinary C file, included wherever it is used, exactly the way the best-known PlayStation decompilation does it, and a check that
runs with every health check proves that no function has two sources. Along the way the tool that does the sharing was caught making four
kinds of mistake by its own gates and fixed; one session ran out of memory in the middle and the next rebuilt its state from the transcript;
a second, independent check found 38 functions the first could never have seen, and they got their own way of being shared. Fifty-one
functions could not be shared yet because their surrounding declarations disagree between level files, and they are listed with the
compiler's own reason for the next phase to settle. The numbers on the public page were corrected where the old counting had been blind.
All 218 game files still rebuild byte for byte, and faster than before.
## 🛑 Stop Here
PhaseEnd written; `CURRENT_PHASE.md` archived → `phase-ends/logs/Phase35.md` (R19, via `git mv`); `phase-ends/DIGEST.md` §0/§2 appended
(step 3b); the kit's record corpus regenerated (`make kit-corpus`) — **all left uncommitted for Drew's milestone-close commit** (R6 gate-2
sign-off; the message is above). The Phase-35 work is committed across the sessions (`48170fd7f..c1a901373`; nothing pushed). The headless
Ghidra MCP was stopped via the sentinel (R23); nothing under `ghidra/` is tracked. **Drew, from the repository root:**
``
git add -A phase-ends decomp-architect docs .run/P35/baseline .run/P35/census
git commit -m "chore(phase-35): CLOSE — Gen3's dedup phase: one source per unique function (3,175 shared headers, 3,173 registry groups incl. the h_text tier, the macro header gone, the five twins from one directory, S1 a tools-health gate with a second oracle, 14 macro-era tools frozen and 4 retired behind a guard, the published counts corrected) — v2.1.0"
git tag -a v2.1.0 -m "v2.1.0 — Phase 35: one source per unique function; 218 binaries byte-identical"
git push origin main --tags
``
Gen3 continues — do **NOT** start Phase 36 here. Start a **fresh session** (effort **Max**, **plan mode**) for **Phase 36 — pins off**,
planning from `docs/gen3-handoff.md` and `docs/gen3-standards.md`. Keep this file forever.
+2 -2
View File
@@ -89,6 +89,6 @@
| 2026-09-05 | 83 | P31 (v1.30.0) | 218 | 100.0% | 100.0% | 100.0% | 97.7% | 4 | 787 / 2091 |
| 2026-09-06 | 36 | P32 (v1.31.0) | 218 | 100.0% | 100.0% | 100.0% | 100.0% | 0 | 789 / 2091 |
| 2026-09-07 | 61 | P33 (v1.32.0) | 218 | 100.0% | 100.0% | 100.0% | 100.0% | 0 | — |
| 2026-09-08 | 72 | P33.5 (v1.32.1), P34 (v2.0.0) | 218 | 100.0% | 100.0% | 100.0% | 100.0% | 0 | — |
| 2026-09-08 | 75 | P33.5 (v1.32.1), P34 (v2.0.0), P35 (v2.1.0) | 218 | 100.0% | 100.0% | 100.0% | 100.0% | 0 | — |
74 dated rows · phase ticks from the 35 PhaseEnds · the chart: `docs/story-timeline.svg`.
74 dated rows · phase ticks from the 36 PhaseEnds · the chart: `docs/story-timeline.svg`.
+1
View File
@@ -50,6 +50,7 @@
<line x1="969.3" y1="360" x2="969.3" y2="352" stroke="#888"/>
<line x1="980.0" y1="360" x2="980.0" y2="352" stroke="#888"/>
<line x1="980.0" y1="360" x2="980.0" y2="352" stroke="#888"/>
<line x1="980.0" y1="360" x2="980.0" y2="352" stroke="#888"/>
<line x1="466.5" y1="30" x2="466.5" y2="360" stroke="#c33" stroke-dasharray="4,3"/><text x="470.5" y="44" font-size="11" fill="#c33">2026-07-22: main enters the denominators</text>
<polyline fill="none" stroke="#1f77b4" stroke-width="2" points="348.8,169.4 359.5,152.3 370.2,149.5 380.9,133.5 391.6,135.5 402.3,125.8 413.0,122.1 423.7,111.7 434.4,108.2 445.1,102.6 455.8,102.5 466.5,100.5 477.2,98.1 487.9,96.3 498.6,94.1 509.3,90.4 520.0,81.5 530.7,74.4 541.4,72.3 552.1,68.9 562.8,65.8 573.5,55.0 594.9,50.8 605.6,48.1 616.3,46.5 627.0,49.7 637.7,50.5 669.8,48.7 680.5,47.0 691.2,46.0 701.9,45.9 712.6,45.5 723.3,44.8 734.0,44.6 744.7,43.6 755.3,42.9 808.8,42.8 830.2,38.6 840.9,34.9 851.6,34.2 873.0,33.6 883.7,33.3 894.4,32.1 905.1,31.6 915.8,31.0 926.5,30.9 937.2,30.1 947.9,30.0 958.6,30.0 969.3,30.0 980.0,30.0"/><text x="70" y="352" font-size="12" fill="#1f77b4">instruction-weighted (all binaries)</text>
<polyline fill="none" stroke="#2ca02c" stroke-width="2" points="348.8,263.2 359.5,230.9 370.2,225.5 380.9,197.6 391.6,196.8 402.3,184.2 413.0,181.7 423.7,159.9 434.4,152.9 445.1,140.5 455.8,140.4 466.5,136.8 477.2,136.7 487.9,136.7 498.6,134.8 509.3,131.5 520.0,114.5 530.7,106.2 541.4,103.4 552.1,100.4 562.8,94.4 573.5,77.8 594.9,69.5 605.6,65.5 616.3,64.8 627.0,70.9 637.7,72.4 669.8,69.1 680.5,65.6 691.2,63.7 701.9,63.3 712.6,62.7 723.3,61.3 734.0,60.8 744.7,58.5 755.3,57.0 808.8,56.9 830.2,47.8 840.9,40.3 851.6,38.8 873.0,37.9 883.7,37.4 894.4,34.8 905.1,33.8 915.8,32.2 926.5,32.0 937.2,30.3 947.9,30.1 958.6,30.0 969.3,30.0 980.0,30.0"/><text x="70" y="338" font-size="12" fill="#2ca02c">distinct code (each body once)</text>

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

+16 -1
View File
@@ -41,7 +41,13 @@ instrument findings fixed (cdecl's scratch dir, two wiki citations, kit_coverage
**Pending by name:** the preset's creation by decomp.me's maintainers, a reply from Archipelago, frogress. Candidates (a)–(d) proposed. **Gen3 opens at Phase 35** — its seed now includes the S91-b types doctrine (R95, the canonical
type layer).
**Phase 35 OPEN (2026-09-08, S94; gate 1 in plan mode at Max) — Gen3's first phase, the DEDUP phase: "one source per unique function."**
**Phase 35 CLOSED 2026-09-08 (v2.1.0; `PhaseEnd_Phase35.md`) — Gen3's first phase, the DEDUP phase: "one source per unique function."**
Three sessions (S94–S96) / 48 commits: every shared body one plain-C header under `src/shared/` included at each site (3,175 headers, the
8.8 MB macro header gone), the five twins from one source directory, the same-address backlog 1,099 classes / 4,755 copies → 51 ledgered
/ 160, a new `h_text` registry tier for 38 byte-variant functions, S1 a tools-health gate with a second oracle, 14 macro-era tools frozen +
4 retired behind a guard, the published counts corrected (+459 functions; REAL 360,744 → 350,533 with EMPTY up the same). R96–R99 ratified;
candidates (a)–(g) proposed. **Gen3 continues at Phase 36 — pins off** (Drew's order dedup → pins → structs → names). The open paragraph:
*Phase 35 OPEN (2026-09-08, S94; gate 1 in plan mode at Max)*
Drew set the Gen3 order dedup → pins → structs → names (one phase each, planned one at a time). The phase converts the 3,516 distinct
`DEFINE_func_` macro bodies (5,147 define lines) into per-function plain-C headers under `src/shared/<space>/` included at each member's
site (sotn's shape, verified from its tree), collapses the five identical-payload twin overlays onto one source directory each, shares
@@ -193,6 +199,15 @@ dry-runs in a throwaway judged by script (run 5 PASS 20/20). Findings: the kit h
the S91-b types hindsight (a banking + width lever → the canonical type layer at Phase 6, DK-65/G62); a typed verify figure wrong twice;
four false judge flags in five runs, all the instrument's. Rules: R74–R83 ratified at gate 1; candidates (i)–(xii) proposed.
**P35 (2026-09-08, v2.1.0) GEN3 OPENS — THE DEDUP PHASE.** 3 sessions (S94–S96) / 48 commits. Gate 1 reversed the 2026-09-02 "leave the
backlog" decision on sotn's tree (it shares once, by an include). T1 `share_census` (362,389 instances, 0 unaccounted, 10,180 classes);
T2 the health chain learns the include + twin forms; T3 five twin pairs → one source dir (166 files deleted); T4 `macro_to_header`: 246,347
sites → 2,215 headers, 213/213 binaries and 4,121/4,121 objects byte-identical, `engine_core.h` deleted; T5 `share_body` (bucket 0 183 →
135 shared / 48 ledgered; bucket new 915 → 914 / 3; a re-exemplar), the S94 death at 91 % and the S95 transcript recovery, four tool
defects fixed at their cause; T5b the `h_text` tier (38 classes / 2,030 sites); T6 14 frozen / 4 retired / the guard; T7 S1 strict + C2c/C2d
in tools-health, the digest corrected; T8 the record (wiki, cookbook §453, decision log). Close: R22 218/218; S1 10,180/10,180, 0
violations; fleet clean-run 157 s → 84–90 s. Rules: R96–R99 ratified; candidates (a)–(g).
## 3. Every rule, in full (transcribe these at session start; P/G/H/X are in PROJECT_CONTEXT.md)
- **R1 — H1 relaxed while private.** ROM-derived content (`asm/`, `assets/`, `extracted/`, decompressed `.CD`) MAY be
committed while the repo is private; accidental inclusion is not a violation. The raw multi-GB disc dump stays ignored
+205
View File
@@ -0,0 +1,205 @@
# PhaseEnd — Phase 35: Gen3 opens — the dedup phase, "one source per unique function"
**Date:** 2026-09-08 · **Project Version:** 2.1.0 · **Phase Status:** Complete (milestone: see §Milestone — every item with its literal output; gate 2 = Drew's close commit) · **Generation:** Gen3 (the first phase; Drew's Gen3 order: dedup → pins → structs → names, one phase each, planned one at a time)
> Chartered at gate 1 (S94, 2026-09-08, plan mode, Max) from `docs/gen3-handoff.md` + `docs/gen3-standards.md`, on evidence read from
> sotn-decomp's tree that reversed the 2026-09-02 "leave the dedup backlog" decision. Ran **three sessions (S94–S96, all 2026-09-08)** and
> **48 commits** (`48170fd7f..HEAD`, plus this close). The granular trail — every task's verify lines, the S94 death and the S95
> recovery, every tool defect with its cause — is at **`phase-ends/logs/Phase35.md`** (R19, on demand). Owner decisions (Drew): gate 1's
> four (twins → one source directory; cross-address classes censused and deferred; macro-era tools frozen with a loud refusal; R96–R99
> ratified); no "trivial" exception; the tooling must know there is one source per unique function (→ the S1 gate); the recovery session's
> scope ("capture only"); the effort levels per step (Max for two decisions delegated to Claude, high/xHigh otherwise); T9 run in the same
> session at xHigh.
## Build Log
**The phase in one line:** every shared function body became one plain-C header included at each member's site (sotn's shape), the
five identical-payload overlay twins build from one source directory, the 4,755 already-matched duplicate copies of 1,099 same-address
classes were shared down to 160 copies in 51 ledgered classes, 38 functions whose bytes vary per overlay share one text through a new
registry tier, the invariant "one source per unique function" is a `tools-health` gate with a second, disagreeing oracle, the macro-era
tools are frozen or retired behind a guard, the published numbers were corrected where the old counting was blind — and every step was
proven by the 218 hashes from a clean rebuild.
**Files created/changed and complete — do not recreate** (category summaries; the per-commit list is `git log 48170fd7f..HEAD` and the
archived log):
- **The shape (T3, T4, T5, T5b).** `src/shared/engine_prelude.h` (what every overlay/module TU includes at line 2), `src/shared/{ov,main,
slot_800CAE08,slot_801E25E8,slot_801EF468}/func_<VRAM>[__<h8>|__t<h8>].h` — **3,175 headers**, one per shared body (2,215 converted from
the macro header at T4, 914 + 1 + 38 written by the share tool); `src/shared/engine_core.h`, `ov_setters.h`, `clearTbl40.h` deleted;
the whale `func_80144B9C.h` moved under `ov/`; **3,173 registry groups** in `config/dedup.us.yaml` (2,220 at the open; 38 of them
`tier: h_text` in the verbose member form with per-member `h_exact`); `config/dedup_exceptions.tsv` (the S1 ledger: 51 rows, each with
the compiler's diagnostic and a reason code); `config/overlays.mk` `<twin>_TWIN_OF/_SRC_DIR` for SC01_006, SC03_119, SC02_003, SC04_019,
SC03_015 (their `src/` directories deleted, 166 files; the twins' yamls = the primaries' carves with `create_c_files: False`, their
`JTBL_PADS` lines regenerated); the Makefile's twin block.
- **The tools (T1, T2, T4, T5, T5b, T6, T7).** `tools/share_census.py` (the S1 census + gate: every sig instance resolves to one source form;
verdicts A/B/C/D/M, flags E/F/TWIN/PINS/ALIAS; `--selftest` fixture; `--check --strict-macros --strict-text`; `text_classes`; the second,
sig-blind oracle keyed by (text, address)), `tools/macro_to_header.py` (the T4 converter, kept as `share_body`'s library), **`tools/
share_body.py`** (the permanent share tool: `--plan / --apply --bucket extend|new|text / --reexemplar / --repair-registry`, the
per-binary gate with object comparison and a snapshot-based bisect, the ledger, `--batches 1`), `tools/share_body_cycle.sh` (the
unattended batch cycle: batch → exit code → phase-log entry → commit → periodic clean fleet run), `tools/frozen.py` (the one refusal
14 FROZEN tools print from `main()`), `tool_census.py` (status FROZEN; the `ast` macro-form guard with `--guard-root` for the negative
control), `dedup_integrate.py` (C2c/C2d; the `h_text` tier with C1 per member), `progress.py` (the include form as a definition, the
source-dir oracle, the empty-shared fold, `unique_function_bodies`, `duplicate_source_copies/_classes`, `text_tier_*`,
`deferred_same_address_*`, a dated `corrections` list, the README sentence), `corpus.py` (`src_dir/twin_of`, the one source-dir oracle),
16 health-chain tools taught the include + twin forms (T2), 12 tools' dead macro branches dropped (T6); `tools/sunset/`: `dedup_propagate`,
`dedup_extend` (their library surface moved verbatim into `share_body`), `macro_draft`, `test_reconcile_ledger`; the Makefile's
`tools-health` gained `share_census --selftest` and the strict check before `report`.
- **The record (T8).** `docs/wiki/The-dedup-engine.md` rewritten for the shared-source model; `Repository-layout.md`,
`Where-the-project-goes-next.md`, `Verification-and-progress.md`, how-to ch.10, README prose and the generated block (with the
"One source per unique function" sentence), `docs/gen3-standards.md` (§4 row struck, the DoD's "0 macro bodies" met), `docs/gen3-
handoff.md` (dated snapshots), cookbook **§453** + a retirement banner on §14, `docs/decision-log.md` P35 (R31), `docs/accelerators.md`
P35 (five), DIGEST §0/§2/§3/§4, `docs/SETUP.md` P35 sections (T1, T3–T5, T6, T7/T5b, the context guard), `docs/tool-index.md` and the
kit corpus regenerated, the memory `dedup-backlog-leave-it` rewritten as REVERSED.
- **Evidence (`.run/P35/`, allowlisted text):** `baseline/` (every R22 and tools-health log, the kit-corpus logs), `census/` (the census
json/txt, `check_t5.txt`), `share/` (every batch record `batch_<label>.json`, every run log, the 146 per-binary gate logs, the registry
repair record, the old header of the re-exemplar), `convert/` (T4's batch scripts, ledger and apply logs), `probe/` (T0's object A/B).
- **Outside the repository:** `~/.claude/statusline.sh` writes the context percentage; `~/.claude/ctx_guard.sh` (a user-settings
`PostToolUse` hook) injects "90% context. decide on the best place to checkpoint for a fresh session" once per session — built after
S94 died at 91 % without a checkpoint; it fired in S96 exactly at the right moment.
**Tools/packages installed:** none (no apt/pip). Agents: three at gate 1 (two Explore, one Plan; ~680k tokens); none during execution —
every task was the coordinator's own work and deterministic gates.
**Verification results (literal, at close — S96, HEAD `c1a901373` + this close):**
- T9 R22 from clean: `extract-all: 217 extracted, 0 failed of 217 (+ main, serial)` · **`check-all: 218 passed, 0 failed of 218`** · `wall=87.62 s` · exit 0` (`.run/P35/baseline/r22_t9.log`).
- T9 `make tools-health` (foreground): `tools-health: OK — sigs fresh; corpus(+resident) + cdecl + binaries + report(lint+dedup) + cookbook-index all green.` (run 2, 431 s, exit 0; run 1 was red only at the kit corpus, which had not yet copied this file and the DIGEST edit — regenerated, re-run) (`.run/P35/baseline/tools_health_t9.log`) carrying `S1: one source per unique function — 10,180 classes, 10,180 satisfied (3,507 twin-covered, 51 excepted, 3,801 deferred cross-address), 0 VIOLATION(S) — OK`, `dedup-check: 3173 validated, 0 failed | C1 coverage 262573/262573 members signed`,
`macro-form guard: 0 LIVE tools reference the retired form (217 scanned, 14 frozen, 6 whitelisted detectors, 38 retired)`.
- `git grep -c '^#define DEFINE_func_' -- src` → empty; `tools/macro_to_header.py --verify` → `OK — 0 macro sites, no macro header, the
prelude present`; the census `macro sites 0` (two block-comment lines in prose still mention the token — comments are the record);
`src/shared/engine_core.h` absent.
- `tools/share_census.py --selftest` → `7/7 verdicts correct`; the strict check's second oracle: `0 same-address definition texts
duplicated across TUs`, `381 … inside the deferred cross-address classes (1,668 sites)`.
- `tools/progress.py --json --readme --check` → fresh; `timeline --check: fresh (74 rows)`; `doc_links` strict `0 pending, 0 broken`;
`wiki_render --selftest: 12 cases, 0 failed; 32 pages, 0 unlisted`; `cookbook-index OK (1170 sections)`; `kit_coverage: OK`;
`tool_census --check: OK` (the guard: 217 scanned, 14 frozen, 6 whitelisted detectors, 38 retired).
- The negative controls on record (R39): the guard against a worktree of the pre-T4 tree flags exactly the 15 tools with macro-form code
(`--guard-root`); one member's include reverted in place → `S1 … 1 VIOLATION(S) — FAIL` naming the class, C2d naming the member, restored → OK.
**Milestone achieved (gate 2 — Drew's close commit is the confirmation; each item with its literal output):**
1. `git grep -c '^#define DEFINE_func_' -- src` empty; no `DEFINE_func_X()` site (`macro_to_header --verify` 0; the census 0);
`src/shared/engine_core.h` absent; every registered body a plain-C header under `src/shared/<space>/` (`dedup-check` C2c, 3,173 groups).
2. `tools/share_census.py --check --strict-macros --strict-text` exit 0: `S1: one source per unique function — 10,180 classes, 10,180
satisfied (3,507 twin-covered, 51 excepted, 3,801 deferred cross-address), 0 VIOLATION(S) — OK` — same-vram duplicate copies 160, each
in a ledgered class with its reason; the five twins built from one source directory each (`audit-binaries` CHECK 3b); the cross-vram
classes published as a deferred count (3,801; plus the 381 tiny-body texts / 1,668 copies inside them).
3. `make tools-health` OK with S1 strict and the macro-form guard; every consumer updated (16 + 12), frozen (14) or retired (4) per its
dictionary row.
4. `make clean && make extract-all && make check-all` → `check-all: 218 passed, 0 failed of 218` (R22, T9 and after every batch).
5. README/wiki/kit regenerated (R75), decision log (R31), SETUP rows (R21), this PhaseEnd + the DIGEST; v2.1.0.
**Next:** **Phase 36 — pins off** (Drew's Gen3 order). Open a fresh session in **plan mode, Max** (Tier 1) from `docs/gen3-handoff.md`
§5–§7 and `docs/gen3-standards.md`: the 44,243 `register … __asm__` pins (most come off byte-identical once the source shape is right —
Phase 32's finding), family-batched, byte-gated per binary, R22 per batch; the S1 gate stays in the chain (a pin removed inside a shared
header reaches every member — one edit, one gate). Inherited by name: the 51 ledgered declaration conflicts (the types phase), the 3,801
cross-address classes and the 381 tiny-body texts (the names phase's parameterized form), the kit split, xsig v2.
## Roadmap delta (what Phase 35 changed about the road ahead)
- **The Gen3 charter's first item is met and measured:** "shared engine functions live as C, not as macros" — 0 macro bodies; the
charter's "5,147" counted define lines (3,516 distinct macros; R14/R41 correction published in the log and the wiki).
- **A new registry tier exists (`h_text`)** for the shape the byte tier cannot hold: identical C whose bytes vary per binary through
the translation unit's declaration environment. The types phase must treat those 38 headers as compiling per unit by design.
- **The names phase inherits a precise list:** 3,801 cross-address classes (E flag), 381 same-address tiny-body texts inside them, and
the parameterized `SHARED_FN` form as the intended shape (one worked example, `clearTbl40`).
- **The types phase inherits the ledger:** 50 declaration conflicts in the late-onboarded overlays (`config/dedup_exceptions.tsv`,
each with its diagnostic) and one byte-variant body — exactly where a canonical declaration layer (R95) pays.
- **Scale, honestly (R41):** the plan priced the phase at 7–8 sessions; it took three (one of them a recovery), because the tooling was
built to gate itself and the batches ran unattended. The cost that was real: one dead session's 35 minutes rebuilt from its transcript,
four tool defects found from their artifacts, and nine red health-chain runs across T6–T7, every one an instrument finding.
## Deviations
| Item | Plan (gate-1 plan) | Actual | Reason |
|---|---|---|---|
| Sessions | 7–8 | 3 (S94–S96) + this close | the gates were the tool's; batches ran unattended (`share_body_cycle.sh`) |
| S94 | a checkpoint at every pause | died at 91 % context waiting on a background run, no checkpoint for T5; S95 rebuilt the state from the transcript with no runs (Drew's scope) | two bank commits carried no log line; rule candidate (b); the context guard built |
| `share_body` | designed at T5 | four defects found from S94's artifacts and fixed at S96: the cause extractor (no "error" token in gcc 2.7.2), `git checkout` as restore, a twin's duplicate edit, wholesale registry extension | each caught by a gate or a known-true control; cookbook §453 |
| Bucket 0's residue | ledgered with a message class | 48 late-overlay declaration conflicts ledgered TU-CONFLICT for the types phase; `E_func_80168B70` re-exemplared from the majority text (Claude's delegated decision at Max) | the header carried a 7-overlay minority spelling; the cast form compiles under both environments (141/141) |
| The second oracle | "a second, disagreeing oracle" | it disagreed: 38 same-address texts / 2,030 copies byte-variant per binary → **T5b added** (the `h_text` tier; Claude's delegated decision at Max); 381 tiny-body texts inside the deferred classes stay deferred | no later phase would remove the copies; one header per address for the empties would be undone by the names phase's form |
| T6's counts | freeze 7, retire 3 | freeze **14**, retire **4**; the guard's census measured 30 hits, not 22; `family_cousins` stays LIVE (`make atlas` runs it) with its dead branch dropped | the plan's counts came from a partial census |
| `progress.py` | "the +219 correction" | +459 (SC03_015's 219 + SC03_118's 3 + the never-extended members of five groups) and REAL −10,211 → EMPTY (the fold); both dated in `progress.json` `corrections` | the include form made invisible sites visible; the macro-era fold had counted empty shared bodies as REAL |
| T9 | Max, fresh session | run in S96 at xHigh (Drew) | owner's call; the checkpoint carried the brief |
## What we believed, what failed, and what we would do sooner (for the retrospective; detail in `docs/decision-log.md` P35)
- **Believed (2026-09-02):** sotn writes duplicate functions explicitly, so ~12,000 duplicate copies are the normal end state. **False:**
read from its tree, sotn shares stage code once and instantiates it by an include. **Sooner:** read the target project's tree, never a
memory of it, before setting a policy on its precedent.
- **Believed:** refreshing the checkpoint at every task close was enough. **S94 refreshed it five times and still died with 35 minutes
of state only in its transcript** — two bank commits inside a task carried no log line, and a background wait consumed the rest.
**Sooner:** every commit that advances a task carries its log line and the headline; past ~85 % context, checkpoint before any long wait.
- **Believed:** a green per-binary gate meant the tool's edits were what it reported. **Its restore was `git checkout`,** which wiped the
previous batch's uncommitted shares and returned green; its cause lines read "Error 33" for 254 of 303 rejections. **Sooner:** a tool's
restore path is part of the tool (R57); read a compiler's diagnostics by their form.
- **Believed:** the byte join sees every duplicate. **The text oracle found 38 functions in 2,030 copies it could never class.** **Sooner:**
build the disagreeing oracle before the batch runs, and measure the disagreement before believing either side (R34).
- **Cost:** no model tokens beyond the coordinator and gate 1's three agents; the phase's expense was wall-clock in gates (≈2.5 h of
`make check` and fleet runs) and the recovery (≈1 h reading a 6 MB transcript).
## Commit Message
``
(Phase 35 landed as 48 commits 48170fd7f..c1a901373, 2026-09-08 (S94–S96). This close = the archived log + this PhaseEnd + the DIGEST
update + the kit's record copies, Drew's milestone-close commit.)
chore(phase-35): CLOSE — Gen3's dedup phase: one source per unique function (3,175 shared headers, 3,173 registry groups incl. the
h_text tier, the macro header gone, the five twins from one directory, S1 a tools-health gate with a second oracle, 14 macro-era tools
frozen and 4 retired behind a guard, the published counts corrected) — v2.1.0
- PhaseEnd_Phase35.md written; CURRENT_PHASE.md archived to phase-ends/logs/Phase35.md (R19); DIGEST §0/§2 appended (step 3b)
- T0–T8 + T5b across S94–S96 (S94 died at 91 % without a checkpoint; S95 recovered it from the transcript; S96 finished)
- close: R22 clean fleet 218/218; tools-health OK (S1 10,180/10,180, 0 violations; dedup-check 3173/0; the guard 0)
- rules: R96–R99 ratified at gate 1; candidates (a)–(g) proposed for Phase 36 gate 1
- v2.0.0 -> v2.1.0
``
## Rules Added This Phase
**Ratified at gate 1 (2026-09-08):** **R96–R99** (the PhaseEnd_Phase34 candidates (a)–(d)); full text in `phase-ends/DIGEST.md` §3.
**Candidates recorded in the log, for Drew to accept, modify or reject at Phase 36 gate 1 (P10):**
| Rule | Reason |
|---|---|
| **(a) A shared body has exactly one source; a duplicate copy is a defect the health chain asserts, and its count is published with its rule.** | The phase's invariant (S1), a `tools-health` gate; 1,099 classes / 4,755 copies → 51 / 160, every remainder ledgered with its diagnostic. |
| **(b) Every commit that advances a task — an intra-task bank included — carries its log line and the 🛑 headline; a checkpoint older than HEAD is a dead session's checkpoint.** | S94 refreshed the block at every task close, made two T5 bank commits with no log line, then died at 91 % context; S95 rebuilt 35 minutes of state from the transcript. |
| **(c) A tool that restores files restores from its own snapshot, never `git checkout` on a tree it did not commit.** | `share_body`'s first bisect wiped the previous batch's uncommitted shares (~50 sites) and returned green. |
| **(d) A failure-cause extractor is negative-controlled against the compiler's real message forms, not against the word "error".** | gcc 2.7.2 prints errors without it and exits 33; 254 of 303 rejection lines read "Error 33". |
| **(e) Build the disagreeing oracle before the batch runs, and measure its disagreement before believing either side (R34 operated).** | The text oracle's 4,312 hits decomposed into twin false positives, the gate-1 deferral, and 38 genuine byte-variant functions — three different actions. |
| **(f) A registry lists a member only after the gate has spoken for it; a listed member whose site does not share is a defect the check names.** | The first pass extended 788 members wholesale; 317 were private after the run (C2d exists now). |
| **(g) A policy taken on a remembered precedent is a belief — read the target project's tree.** | The 2026-09-02 deferral rested on one parenthetical about a cross-jump idiom. |
## PhaseEnd Changelog
**v2.0.0 → v2.1.0 — Phase 35 complete (Gen3's first phase).** Every shared function body in the fleet is one plain-C header included at
each member's site, sotn's shape, verified from its tree; the 8.8 MB macro header and its 5,147 define lines are gone; the five overlay
twins build from one source directory each; the same-address duplicate backlog fell from 1,099 classes and 4,755 private copies to 51
ledgered classes and 160 copies, each with the compiler's own reason; 38 functions whose bytes vary per overlay share one text through a
new registry tier; the invariant "one source per unique function" is asserted on every health-chain run by a census with a self-test and
a second, sig-blind oracle, and by four registry checks; fourteen macro-era tools are frozen and four retired behind a guard that scans
every live tool; the published numbers were corrected where the macro-era counting had been blind, dated and explained. Every batch was
proven by the 218 hashes from a clean rebuild, which now takes 84–90 seconds instead of 157. R96–R99 ratified; seven candidates proposed.
## Plain-English Recap
This phase made the code say each thing once. Before it, when the same function appeared in many of the game's 141 level files, our source
held it as a macro in one enormous header, or as a private copy pasted into each level, thousands of times over. Now every shared function
is one small ordinary C file, included wherever it is used, exactly the way the best-known PlayStation decompilation does it, and a check that
runs with every health check proves that no function has two sources. Along the way the tool that does the sharing was caught making four
kinds of mistake by its own gates and fixed; one session ran out of memory in the middle and the next rebuilt its state from the transcript;
a second, independent check found 38 functions the first could never have seen, and they got their own way of being shared. Fifty-one
functions could not be shared yet because their surrounding declarations disagree between level files, and they are listed with the
compiler's own reason for the next phase to settle. The numbers on the public page were corrected where the old counting had been blind.
All 218 game files still rebuild byte for byte, and faster than before.
## 🛑 Stop Here
PhaseEnd written; `CURRENT_PHASE.md` archived → `phase-ends/logs/Phase35.md` (R19, via `git mv`); `phase-ends/DIGEST.md` §0/§2 appended
(step 3b); the kit's record corpus regenerated (`make kit-corpus`) — **all left uncommitted for Drew's milestone-close commit** (R6 gate-2
sign-off; the message is above). The Phase-35 work is committed across the sessions (`48170fd7f..c1a901373`; nothing pushed). The headless
Ghidra MCP was stopped via the sentinel (R23); nothing under `ghidra/` is tracked. **Drew, from the repository root:**
``
git add -A phase-ends decomp-architect docs .run/P35/baseline .run/P35/census
git commit -m "chore(phase-35): CLOSE — Gen3's dedup phase: one source per unique function (3,175 shared headers, 3,173 registry groups incl. the h_text tier, the macro header gone, the five twins from one directory, S1 a tools-health gate with a second oracle, 14 macro-era tools frozen and 4 retired behind a guard, the published counts corrected) — v2.1.0"
git tag -a v2.1.0 -m "v2.1.0 — Phase 35: one source per unique function; 218 binaries byte-identical"
git push origin main --tags
``
Gen3 continues — do **NOT** start Phase 36 here. Start a **fresh session** (effort **Max**, **plan mode**) for **Phase 36 — pins off**,
planning from `docs/gen3-handoff.md` and `docs/gen3-standards.md`. Keep this file forever.
@@ -75,7 +75,7 @@
digest + README sentence. Effort: high (Drew's default).
- ☑ **T8** (S96; doc_links strict 0 broken, wiki 32/32, cookbook §453 + index, decision log, accelerators, DIGEST §4, the memory) — the record: wiki (4 pages), how-to ch.10, README:117, the charter rows as dated snapshots, the cookbook section, decision log
(R31), accelerators, DIGEST §4, sunset rows, the memory rewritten; doc_links/wiki_render/cookbook_index/kit_coverage green.
- ☐ **T9** — close (Tier 1): R22 → 218/218; tools-health OK; the metrics table; the reviewer sequence; PhaseEnd + DIGEST + log archived; v2.1.0.
- ☑ **T9** (S96, xHigh by Drew's choice) — close (Tier 1): R22 → 218/218; tools-health OK; the metrics table; the reviewer sequence; PhaseEnd + DIGEST + log archived; v2.1.0.
- Rules check (P6): after T3 and after T7.
## Decisions (owner's words, in order)
@@ -583,6 +583,19 @@
index regenerated (`1170 sections, 14 symptom buckets`) and `cookbook-index OK` · `kit_coverage: OK` · kit corpus + `tool_census
--check: OK`. **T8 ☑.** (`tools/sunset/README.md` rows were written at T6.)
- **S96 — T9, the close (run in S96 at xHigh by Drew's choice; the plan said Max in a fresh session).** R22 from clean:
`extract-all: 217 extracted, 0 failed of 217 (+ main, serial)` · **`check-all: 218 passed, 0 failed of 218`** · `wall=87.62 s` · exit 0
(`.run/P35/baseline/r22_t9.log`). `make tools-health` run 1 (467 s) was green through S1 / dedup-check / the guard and red only at
`tool_census --check` — the kit's record copies of `DIGEST.md` and the new `PhaseEnd_Phase35.md` (both written while the chain ran);
`make kit-corpus` regenerated them and the chain was re-run (its line is appended below). The headless Ghidra MCP stopped via the
sentinel: `Save succeeded for processed file: /SLUS_007.26` (R23; unused all phase). `PhaseEnd_Phase35.md` written (the metrics table,
the milestone items with literal output, the reviewer sequence, seven rule candidates, the recap); DIGEST §0 refreshed + §2's P35
synopsis appended (step 3b). **The chain, run 2:** `tools-health: OK — sigs fresh; corpus(+resident) + cdecl + binaries +
report(lint+dedup) + cookbook-index all green.` (`.run/P35/baseline/tools_health_t9.log`, 431 s, exit 0, 0 gaps) with `S1 … 10,180
satisfied … 0 VIOLATION(S) — OK`, `dedup-check: 3173 validated, 0 failed`, `macro-form guard: 0 LIVE …`. The log archived to
`phase-ends/logs/Phase35.md` (R19); `make kit-corpus` + `tool_census --check` after the PhaseEnd's last edit; everything left
uncommitted for Drew's close commit (R6). **T9 ☑ — Phase 35 milestone met; v2.1.0.**
## 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)
@@ -882,7 +895,7 @@ snapshot" (share_body's bisect wiped the previous batch's uncommitted shares; R4
negative-controlled against the compiler's real message forms, not against the word error" (gcc 2.7.2 prints errors without it;
254 of 303 rejection lines read `Error 33`).
## 🛑 SESSION CHECKPOINT — S96 close (2026-09-08, written at the 90 % context guard): Phase 35 T0–T8 ☑ (+ T5b); NEXT = T9, THE CLOSE (Tier 1, Max) in a FRESH session
## 🛑 SESSION CHECKPOINT — S96 close (2026-09-08): Phase 35 COMPLETE — T0–T9 ☑ (+ T5b); PhaseEnd_Phase35.md written, this log archived; NEXT = Drew's close commit, then Phase 36 (pins) in a fresh session at Max, plan mode
### 0. How to use this block
A fresh session (S97) reads CLAUDE.md's load order, replays THIS block verbatim, asks Drew for `/effort max` (T9 is Tier 1: the PhaseEnd