T5.1: summary, log, tooling-inventory rows for struct_twins and lift_types --census/--fold

This commit is contained in:
Drew T
2026-09-30 17:19:57 -06:00
parent eedd97c5c7
commit d39a3f03f6
7 changed files with 119 additions and 2 deletions
+2 -1
View File
@@ -164,7 +164,8 @@ Every script under `tools/` (plus the two report make-targets), grouped by purpo
| | `tools/blocker_probe.py` | **(Phase 29 SESSION-16, cookbook §65)** WHY a byte-correct draft fails the whole-binary gate. Read-only; **two oracles** (R34): STATIC (`cdecl.parse` + `cdecl.compatible` — cc1's own acceptance question, never text equality) beside the REAL cc1 (via `rtu_match`), leading with the DISAGREEMENT table. Classes `self_decl_hdr`/`self_decl_tu`/`callee_decl`/`data_decl`/`local_type`, each mapped to a blast-radius tier (T0 draft-only / T1 binary-local / T2 fleet-shared). Blockers STACK, so a function's tier is the MAX over them. 36 drafts in ~9 s. Replaced+deleted `.run/diag_plumbing.py`. |
| | `tools/demacroize.py` | **(Phase 29 SESSION-16, cookbook §65b)** The per-overlay-local escape from a shared-header decl conflict — the largest stranded class, and the one §20 called unrecoverable. The conflicting `extern` lives INSIDE a `DEFINE_func_*` body, so it exists only at instantiation sites: this expands those instantiations **in the overlay's own TU**, correcting only the conflicting decl to the draft's byte-true sig (never dropping it, §57a-1). **T1** — writes confined to `src/<binary>/**`, so the per-binary gate suffices and no R22 risk is created by construction (contrast `fix_header_decl`, fleet-blind, §63 UPDATE). `--emit-edits` (read-only, feeds `rtu_match`) / `--apply`. **Price: the function can no longer propagate ×138 — such a bank is ×1** (full distinct-code credit, ~1/138 of instr). |
| | `tools/recover_integration.py` | **(Phase 24 T6; extended Phase 29 SESSION-16/17, cookbook §65/§66)** The stranded-draft recovery DRIVER — consumes a wave dir (`--draft-dir`, repeatable; the backlog is the wrong source: unreliable `closeness`, overlay-specific drafts), runs the declared `--stages` (`demacroize` T1 / `arity` T2), then gates in TWO passes (**gate all → exact snapshot-restore → re-stage winners only**), so a non-bank never leaves an edit behind. `--run-id` puts all scratch + `verified_out`/`failed_out` under `.run/recover/<id>/` (closes §55b trap 4); bank truth is `banked_from_source()` (the stub is GONE from src), never a gate report; `stub_map` derives from `corpus.stubs` (R33). **Blast-radius tiers are ENFORCED** (`--max-tier`, write-set assertion), and **propagation is itself fleet-tier**: it needs `--max-tier fleet` AND `--r22`, and is refused outright after `demacroize` (those banks are ×1 by construction; `--auto-from` would re-macroize and undo them) — both refusals negative-control-tested, exit 1. `--probe-only` / `--report`. Success path verified end-to-end by the §66 free re-bank test. |
| | `tools/lift_types.py` · `tools/uniquify_type.py` | **(Phase 29 SESSION-14, cookbook §64/§64a)** Fleet-wide type lift into `src/shared/engine_types.h`, and the camp-uniquify that must precede it for VARIANT names (same identifier, different layouts in different TUs — reconciling them merges two layouts and breaks the minority camp). Both are **T2**: dry-run by default, and **R22 clean-fleet is the arbiter, not the per-binary gate**. |
| | `tools/lift_types.py` · `tools/uniquify_type.py` | **(Phase 29 SESSION-14, cookbook §64/§64a)** Fleet-wide type lift into `src/shared/engine_types.h`, and the camp-uniquify that must precede it for VARIANT names (same identifier, different layouts in different TUs — reconciling them merges two layouts and breaks the minority camp). Both are **T2**: dry-run by default, and **R22 clean-fleet is the arbiter, not the per-binary gate**. **P38 T5.1:** `--census TSV` (relocate every def type_census reports outside the canonical files; `--rename` pass 1, `--exclude`/`--excluded-out`) and `--fold TSV` (one canonical name per class of type_census's `dup_gating.tsv`; `--fold-tier1`/`--fold-sdk`/`--fold-class`/`--fold-exclude`/`--fold-canon`/`--fold-report`; `--fold-dead CENSUS_JSON` deletes dead canon types). Gotcha: a layout hash must include alignment attrs. |
| | `tools/struct_twins.py` | **(P38 T5.1)** Drafts the evidence for tier-2 (all-placeholder) duplicate-layout classes from the census dir: SEPARATE / SHARED / UNBOUND per class, causes from struct_map use sites, PsyQ SDK layout as a note. `--write` regenerates `## Twins` of `docs/struct-twins.md` (which `type_census --check-structs` reads: stale lhash fails, `twins_listed=N` non-gating); `--show LHASH`. Run after every fold, as its own call after the census. |
| | `tools/backlog.py` | Near-miss ledger (`.run/backlog.jsonl` + `docs/backlog.md`); **fleet-aware** `load_best` (a 077-matched-but-stuck-local fn surfaces via its overlay record; Phase 23). | **S84 repair (2026-09-06):** `load_best` now keeps the LATEST record at equal closeness (its docstring's contract; the `(cscore, ts) <= …` compare had kept the EARLIEST, so a re-verdict at the same closeness never rendered — func_80032A74's PROVED row).
| | `tools/lora_grind.py` | Mass-run driver: rotate binaries → draft open ≤N-ins stubs with the served model → gate → propagate. `--min-reach N` (Phase 23) targets shared fns (sig-reach oracle == `dedup_propagate`). |
| | `tools/bulk_harvest.py` | **(Phase 23 / T10)** The phase-separated + parallel-gate harvester (throughput rebuild of `lora_grind`): **(A)** bulk-draft K fresh ≤N-ins stubs (GPU) → **(B)** `ProcessPoolExecutor --workers` byte-gate over DISTINCT binaries (`build/<bin>/**` isolated; `run_gate` per-binary lock + per-worker scratch, `propagate=False`/`commit=False`/`compute_fleet=False`) → **(C)** dedupe-once + ONE commit. Round-robin fuel spread; STOP-sentinel; on-demand/bounded. Measured 2026-07-01: gate **0.4s/fn** (8 workers, ~75× the serial gate) ⇒ drafting is the bottleneck (→ vLLM next). Run: `API_BASE=… MODEL=bfm-match-7b-v3 tools/bulk_harvest.py --binary-glob 'ov_SC03_*' --count 80 --workers 8 --measure`. `lora_grind` kept as the serial fallback. |
+31
View File
@@ -0,0 +1,31 @@
# T5.1 — full log (long tail: one definition per type, gate reading fixed)
Reopens T5 (committed). Two expert attempts; attempt 1 handed off (its TASK_PROGRESS.md was not on disk at respawn; state came from the router brief). Per-coder detail: logs/T5.1.c{1,2,2b,3,3b,4,5,6,7,8}.md; digest R3.38-003.
## Timeline
- c1 (b65da945f): type_census `--check-structs` reading fixed: liveness fixpoint over canon-header uses (member/alias/typedef, any length), twins ledger read from docs/struct-twins.md (stale lhash fails, `twins_listed=N` non-gating), block-scope stack frames non-gating `block_frames=N`; +selftest (member-only canon type not dead).
- c2 (6869f8f26, 446161539): lift_types `--census` + `--rename` pass; ov file-scope batch. First R22 204/218; fix = relocation pulls the whole name group (batches name-closed, not space-pure).
- c2b (c36cb4980, b0b9c4c46, c3ae8d6da + headers commit): outside_canon 1684 → 0; 28 pad renames; prim_layout_class control rewritten with a negative control.
- c3: `--fold`/`--fold-dead` written; first apply red (V3 redefinition), reverted (fe07c88a25 WIP). c3b (4e75840da, d702f389c, 5752b7762, 83d8b742b, a5c63c425, 5fcb110a2, 18829a78f): 79+10+12+3 tier-1 classes, SDK MATRIX, 24 dead defs folded; 16 tier-1 excluded with causes; dup_classes 76.
- c4 (d71d4c179): tools/struct_twins.py (80 tier-2 rows).
- c5 (ead6a3f0e, 1c842e256, f7fde90cc2, 85b377a61): c3b exclusions folded by hand-conforming; attr classes need an alignment change (trials R22 70/218, 216/218).
- c6 (343b718b21, 6b652730fb): census lhash includes packed/aligned; SDK names RECT, CVECTOR, POLY_FT4, POLY_G3, POLY_G4 (+MATRIX); offset pad_<HEX> kept where SDK pad1..3 break the pad invariant.
- expert attempt 1 (e7fc671d0): Unkstruct_800B5CB8 SPLIT call recorded, docs/struct-map-decisions.md:24-31 (T4 kept units DIFFERS 29, pad3C 3; no unions).
- c7 (ba807d1258 … 804d7d196f): every SHARED tier-2 class folded (942 names); struct_twins UNBOUND causes from use sites, SDK as note, fixed order; dup_classes=0.
- c8 (594ea80c8d, febb2c009f, eedd97c5c7): census counts a def's tag+typedef as one name (+selftest); F20T folded onto Obj20_80178D40; twins regenerated 53 rows (SEPARATE 44, UNBOUND 9); census all gating 0 except parse_error_decls; R22 218/218.
- attempt 2 (this): waited on live c8 (did not relaunch), collected commits, added docs/ops/tooling-inventory.md rows (lift_types --census/--fold, struct_twins), ran verify.
## Commands (attempt 2)
- `.run/logs/c8tw1.log`, `c8cen3.log`, `c8r22b.log` (c8's own) read by tail.
- `tools/run.sh --bg t51v1 -- bash -c "<verify>; echo CENSUS_RC; …; echo BUILD_RC"` → `.run/logs/t51v1.log`.
## Retrievers
- retriever-digest: digest of T5.1.c*.md for this log → R3.38-003.
## Hypotheses rejected
- tier-1 folds need no respell (c3b: placeholder names differ; respell required).
- layout-hash equality = type equality (c3b/c6: attrs, member twins, same-name-other-offset members break it; lhash now includes packed/aligned).
- SDK canon text re-emit via `--fold-sdk` (c6: loses offset comments, breaks pad invariant; rename by hand + alias).
## Verify
t51v1: selftest 33/33; check-structs rc 1 on parse_error_decls=1106 only (T6), rest 0, controls 4/4; extract-all 217/217; check-all 218/218, BUILD_RC=0.
+1 -1
View File
@@ -1 +1 @@
3
4
+1
View File
@@ -2,3 +2,4 @@
<!-- R<N>-<nnn> | <task or plan> | <title> | <tags> | <agent> | <date> | <n> lines -->
R3.38-001 | remaining work after P37 close (T5-T10, P35/P36 end-state, Gen3 roadmap, constraints, open decisions) | What remains after Phase 37; shape of next generation | phase37, phase38, structs, gen3, roadmap, constraints | retriever-digest | 2026-09-29 | 35 lines
R3.38-002 | dup-class tiers, dead_canon_names, outside_canon, check-structs, selftest, lift_types scope | type_census / lift_types mechanics | type_census, lift_types, tier, dead_canon, check-structs | retriever-code | 2026-09-30 | 31 lines
R3.38-003 | terse chronological digest of T5.1 coder logs for writing logs/T5.1.md and tasks/T5.1.md | T5.1 coder-log digest (c1..c8) | T5.1, bfm-decomp, type_census, lift_types, struct_twins | retriever-digest | 2026-09-30 | 41 lines
+40
View File
@@ -0,0 +1,40 @@
# R3.38-003 — T5.1 coder-log digest (c1..c8)
task: terse chronological digest of T5.1 coder logs for writing logs/T5.1.md and tasks/T5.1.md · agent: retriever-digest · model: - · date: 2026-09-30 · tags: T5.1, bfm-decomp, type_census, lift_types, struct_twins
sources:
## Answer (returned verbatim, <=40 lines)
## Findings
## Dead ends
## Answer
Logs: phase-ends/current/logs/T5.1.c{1,2,2b,3,3.progress1,3b,4,5,6,7,8}.md. No tasks/T5.1.md exists yet. Final census: dup_classes=0 outside_canon=0 dead=0 twins_stale=0 variants=0 pad_names=0 parse_error_decls=1106 (T6's) controls=4/4 twins_listed=53 dead_kept=3 block_frames=629; R22 217/217 extract, 218/218 check-all; selftest 33/33; audit-types 0 violations (c8:9-14).
## Findings (per run)
- c1 (b65da945f): type_census --check-structs reading. type_census.py: declares_object :103, ident_dropped :610, TWINS_DOC, load_twins :1042, structs_reading :1065 (dead liveness fixpoint, tier-2 allowlist, dead-kept, block frames, stale), outside_canon.tsv + dup_gating.tsv, new gate twins_stale; selftest +6 (30/30). docs/struct-twins.md skeleton. Verified (c1:22-34): dup_classes=198 outside_canon=3051 dead=3 block_frames=629 (3680-3051=629); --check before/after identical bar line 1. Dead residual 3: LineF2_8018F694, Unkstruct_80126B58, actor4c. Gotcha (c1:37) workflow: commit_task.sh staged expert's pending research/{.next,INDEX.md,R3.38-002.md} into b65da945f. c1:38-39: census regenerates docs/struct-map.md; walk cache grows.
- c2 (6869f8f26, 446161539): lift_types.py --census TSV --rename --batch {ov-file,ov-block,md,main,headers,all} --exclude-file --excluded-out -j. Rename pass 17 names/68 defs/64 files; batch ov-file 83 groups/1374 defs/1235 files. R22 204/218 first try (relocated canon redefined vs unstripped copies) -> fix: relocation pulls whole name group; retry 217/218 green (c2:11-13). Deviation c2:24: batches name-closed, not space-pure (gcc 2.7.2 rejects identical re-typedef). Gotchas c2:23 census line keys go stale after a batch -> rerun census --no-cache before each batch; c2:25 leading comment left behind; c2:26 c2_renames.tsv col 3 mangled, col 4 new name.
- c2b (c36cb4980 ov-block 694 grp/1044 defs/566 files; b0b9c4c46 md 297/359/61; c3ae8d6da main 223/236/9; headers commit 47/49/21): outside_canon 1684 -> 0. Pad renames pad_<HEX>, 28 fields/15 types, no member accesses (c2b:9). controls() #3 prim_layout_class rewritten (len(prim_defs)==1, canon, 64 B) + PRIM_FIXTURES, negative control 30/31 (c2b:10-13). R22 green after every batch; hdrchk.sh rc=0; selftest 31/31. Notes: dead 10->37 (unused local defs relocated into canon), pad_names 1->28 (brief said 1), census --no-cache ~5 min -> run.sh --bg/--wait (c2b:22-27).
- c3 / c3.progress1 (no commit; tree reverted; same content both files): lift_types.py --fold TSV [--fold-tier1 --fold-sdk --fold-class --fold-exclude --fold-report] and --fold-dead. Dry run 123 classes. Run 1 RED: 7419 respells, 3832 TUs erroring; cause `redefinition of 'V3'` (tag + typedef of one name each became alias) c3:16. Also ambiguous member (f, f0), accesses in macros, m.q1 unmapped (c3:17). SDK VECTOR 12 B vs 16 B class (c3:12).
- c3b (4e75840da, d702f389c 79 classes, f9d3c125c->redo 5752b7762 SDK-canon pad bug, 83d8b742b 12, a5c63c425 3, 5fcb110a2 MATRIX 140 defs, 18829a78f fold-dead 24 defs): alias per NAME; SDK canon only under --fold-sdk; tool refuses attr-differing defs and same-name-other-offset members (c3b:4-7). End: dup_classes=76 (t1 16, t2 60), dead=0, dead_kept=4; R22 green each; selftest 31/31. 16 t1 classes excluded with cause (c3b:22-32). SDK groups not applied (c3b:34-36). Gotchas c3b:39 generalizable layout-hash != type equality (attrs, member types, other-offset members silent to cc1); c3b:40 generalizable tier 1 = same MEANINGFUL names, placeholders need respell; c3b:41 workflow --fold-class disjoint-member batches; c3b:42 harness d71d4c179 (struct_twins) committed by another coder mid-task.
- c4 (no hash named; parallel coder's d71d4c179): new tools/struct_twins.py (binders G/L/P/A/AG/F; classes SDK>SHARED>UNBOUND>SEPARATE), --write rewrites only ## Twins, --show, --census-dir. 80 tier-2 rows: SEPARATE 19 SHARED 55 SDK 5 UNBOUND 1 (c4:4). Census c4census dup_classes=92 twins_listed=19 (c4:6). Known-true Blob36->0x80078E50 etc (c4:7). Rejected identity=(tu,fn,var), SDK by class names (c4:8). Gotchas c4:9: tier-2 set moves with folds; SDK literal rule catches 4 B CdlLOC/DVECTOR and 12 B VECTOR; scan ~60 s.
- c5 (ead6a3f0e 10 classes; 1c842e256 MATRIX/MB/V4; f7fde90cc2 H16; 85b377a61 attr subgroups): --fold-canon a,b; attrs refusal skipped if canon carries attr. Hand-conformed members. R22 evidence: a2e73cdb49a3 all->packed_word 70/218 pass (c5r22tA), 0aaa0c2b3635 all->BlockData 216/218 (c5r22tB); reverted (c5:16-19). Fix needs attrs in census lhash. State dup_classes=62, tier1=1. Gotchas c5:32-35: generalizable ambiguous respell solved by hand-conforming small-use defs / disjoint passes; generalizable member-type twin must fold first (Mat_800CB658 alias); harness ov_SC07_002_jr_8017C8D0.c cc1 line numbers ~146 off; harness sed -i on >20k file denied by read-guard hook, use python.
- c6 (343b718b21 census; 6b652730fb SDK names): type_census def_layout_hash learns packed/aligned(N) (+1 selftest 32/32); dup_classes 62->63, tier1 1->0, twins_stale 0->1 (Mtx_A8CE0 aligned(8) in c80fac242f04, expert ledger fix). SDK names by hand: RECT<-Rect, CVECTOR<-Col4_8017F8BC, POLY_FT4<-FT4_801857A4, POLY_G3<-PG3, POLY_G4<-PG4_8017FD50; SDK pad1..3 violate pad_<HEX> invariant -> offset spelling kept (c6:15). VECTOR 16 B left. --fold-sdk run was reverted (emitted SDK text) c6:16. R22 green, audit 0. Gotchas c6:28 generalizable --fold-sdk re-emits SDK body, rename by hand; c6:29 harness suppressing extract-all output hides 217 count.
- c7 (ba807d1258 97 components/2321 files; 634dfd25ed; 63214c2e41; later MainStruct commit; struct_twins e477c4a992; HEAD tree e477c4a992 census): folded every SHARED tier-2 class via union-find components (942 names total). End dup_classes=0, twins_listed=54, dead_kept=3; struct_twins 54 rows SEPARATE 44 SHARED 0 UNBOUND 10 (c7:3-6). struct_twins: SDK becomes a note, U use-site causes, --write order fixed/idempotent (cmp identical), actor4c_8015444C removed from Dead kept (c7:20-24). Canon deviations c7:18. R22 c7r22a..h green; last src commit MainStruct; later commits not re-run. Gotchas c7:35 generalizable by_member pooling -> fold same-member classes in separate runs; c7:36 generalizable whole-member use cannot be respelled, choose canon spelling of whole-member users; c7:37 harness stale .git/index.lock; commit_task.sh refuses msg >100 chars; xargs -x -a list trick for >2k paths. Notes c7:32-34 (Mat_80167540 suffix-only UNBOUND; 6ef8724a7464 F20T/Obj20 +0x20 of 0x80126B58).
- c8 (594ea80c8d tool+fold, febb2c009f struct_twins --write + census regen, 804d7d196f/eedd97c5c7 log; HEAD eedd97c5c7): type_census n_types() union-find: tag+typedef of one def = one type; selftest 33/33; only 9dec8574d64e {Actor4C, actor4c} dropped, 54->53. Folded 6ef8724a7464#0 F20T onto Obj20_80178D40 (struct_types.h:2739 canon; alias; 3 `->f12`->`->unk12` in src/shared/ov/func_80144B9C.h). twins re-written: 53 rows SEPARATE 44 UNBOUND 9. R22 c8r22a + final HEAD febb2c009f c8r22b 217/217, 218/218. Gotcha c8:20 harness census (rc 1 on parse_error_decls) && struct_twins in one call ran >285 s; run as two calls.
Done-when mapping
- dead counting + selftest: c1 structs_reading liveness fixpoint; selftest 30 -> 33 checks; dead 3 -> 37 (c2b) -> 0 (18829a78f fold-dead, c3b) ; dead_kept Unkstruct_80126B58, LineF2_8018F694, actor4c in ## Dead kept.
- tier-2 dup classes listed with lhash: docs/struct-twins.md ## Twins from tools/struct_twins.py (c4,c7,c8); 53 rows, `### <lhash>` sections, twins_listed=53, twins_stale=0.
- block_frames non-gating: 629 printed in "not gating" line (c1:26), outside_canon 3680->3051 by excluding them.
- outside_canon relocations: lift_types --census batches (c2, c2b) 1684/3051 -> 0; R22 green each.
- PsyQ Sony SDK names: MATRIX (5fcb110a2, c3b; 1c842e256 c5), RECT/CVECTOR/POLY_FT4/POLY_G3/POLY_G4 (6b652730fb c6); VECTOR 16 B and SDK-layout-only matches left/noted (c3b:36, c6:17, c7:21).
- Unkstruct_800B5CB8 split/union: docs/struct-map-decisions.md:24-31 (SPLIT stands, include/struct_types.h:6-117, no union; evidence T4 kept units DIFFERS 29, pad3C 3; Ent_8017FD58/Ent_8018D3A4 stay distinct). Not mentioned in any c*.md log (written separately).
- gating counts 0 and R22 green: c8:12-14.
Research ids cited: none in T5.1 logs except incidental R3.38-002 (c1:37, staged by commit_task.sh). No R3 citation elsewhere.
Commits named: b65da945f 6869f8f26 446161539 c36cb4980 b0b9c4c46 c3ae8d6da e7fc671d0(baseline) 4e75840da d702f389c f9d3c125c 5752b7762 83d8b742b a5c63c425 5fcb110a2 18829a78f d71d4c179 ead6a3f0e 1c842e256 f7fde90cc2 85b377a61 343b718b21 6b652730fb 43b7fd08fa(c7 start) ba807d1258 634dfd25ed 63214c2e41 e477c4a992 594ea80c8d febb2c009f 804d7d196f eedd97c5c7. c2b headers commit hash not named.
## Dead ends
git log not run; no tasks/T5.1.md; c4 names no own commit hash.
sources: phase-ends/current/logs/T5.1.c*.md, docs/struct-map-decisions.md:24-31
+1
View File
@@ -5,3 +5,4 @@ T2 | done | --check-structs instrument and actor-struct fix | - | tasks/T2.md |
T3 | done | head-type layouts and canonical files | - | tasks/T3.md | logs/T3.md | -
T4 | done | fold the head types fleet-wide (rung L) | - | tasks/T4.md | logs/T4.md | -
T5 | question | long tail: one definition per type (partial; question) | - | tasks/T5.md | logs/T5.md | -
T5.1 | done | long tail: one definition per type (gate reading fixed) | - | tasks/T5.1.md | logs/T5.1.md | R3.38-002,R3.38-003
+43
View File
@@ -0,0 +1,43 @@
# T5.1 — long tail: one definition per type (gate reading fixed)
Status: done | expert: expert-opus55 | ctx-at-completion: n/a | commit: see COMMIT | coder runs: c1 done (b65da945f), c2 done (446161539), c2b done (c3ae8d6da), c3 red/reverted, c3b done (18829a78f), c4 done (d71d4c179), c5 done (85b377a61), c6 done (6b652730fb), c7 done (804d7d196f), c8 done (eedd97c5c7)
Done: every struct type in the fleet has one definition in the canonical headers; `type_census --check-structs` gating counts dup_classes/outside_canon/dead/twins_stale/variants/pad_names all 0; R22 green.
Done (cont.): the only nonzero gating count is parse_error_decls=1106, which is T6's scope (plan), so --check-structs exits 1 on that alone.
Files:
- tools/type_census.py — check-structs reading: canon-header liveness fixpoint, twins ledger (stale lhash fails), block_frames non-gating, lhash includes packed/aligned, tag+typedef of one def = one name; selftest 33/33
- tools/lift_types.py — `--census` (relocate every outside-canon def; `--rename`, `--exclude`, `--excluded-out`) and `--fold` family (`--fold-tier1/-sdk/-class/-exclude/-canon/-report`, `--fold-dead`)
- tools/struct_twins.py — new: tier-2 class evidence (SEPARATE/SHARED/UNBOUND), `--write` regenerates docs/struct-twins.md `## Twins`, `--show`
- src/shared/engine_types.h, include/struct_types.h, src/** — defs relocated (outside_canon 1684 → 0) and folded (tier-1 all, SHARED tier-2 942 names); PsyQ layouts named MATRIX, RECT, CVECTOR, POLY_FT4, POLY_G3, POLY_G4
- docs/struct-twins.md — 53 listed tier-2 classes (SEPARATE 44, UNBOUND 9) with lhash, names, causes from struct_map use sites
- docs/struct-map-decisions.md:24-31 — Unkstruct_800B5CB8: SPLIT stands, no unions (T4 kept units DIFFERS 29, pad3C 3)
- docs/ops/tooling-inventory.md — rows for lift_types --census/--fold and struct_twins.py (H7)
Decisions:
- binding: tier-2 (all-placeholder) duplicate layouts are either folded (SHARED evidence) or listed in docs/struct-twins.md with a per-class cause; regenerate with struct_twins.py --write after every fold.
- binding: the census layout hash includes alignment attrs (packed/aligned); two defs differing only in attrs are different types.
- offset-spelled pad_<HEX> kept where SDK pad1..3 names would break the pad invariant; VECTOR (16 B) left unnamed.
- dead_kept=3 (Unkstruct_80126B58, LineF2_8018F694, actor4c) reported non-gating with their cause.
Deviations:
- attempt 2 respawned without TASK_PROGRESS.md on disk (not written/committed by attempt 1); state taken from the router brief and git log; c8 was alive and was waited on, not relaunched.
- lift_types relocation batches are name-closed, not space-pure (c2: pulling the whole name group was needed for R22).
- tier-1 folds needed member respell for placeholder names (plan premise "tier 1 needs no respell" held only for meaningful names).
Findings:
- 9 UNBOUND tier-2 classes remain listed (e.g. 64533110def7:opaque = PsyQ RECT/SVECTOR layout, a0f7100333b8:opaque = DVECTOR layout): same layout, no use-site evidence binding them.
- non-gating at close: conflicting_types=160, types_floor_lying=1796, block_frames=629, twins_listed=53.
Gotchas:
- generalizable: a struct layout hash must include alignment attrs (packed/aligned); layout-hash equality is not type equality for folding (attrs, member-type twins, same-name-other-offset members; the last is silent to cc1).
- generalizable: tier 1 = same meaningful names; placeholder names (unk*/f*/w*) differ and need respell.
- generalizable: lift_types' member respell pools candidates across all classes in one run; fold classes sharing member names in separate runs, with disjoint respelled member sets.
- generalizable: a whole-member use (`f(x.v)`) cannot be respelled; pick the canon whose spelling the whole-member users have.
- generalizable: a folded class can need a member-type twin folded first (one-line alias of 2 names instead of the whole class).
- generalizable: `--fold-sdk` re-emits the SDK body (loses offset comments, SDK pad names break the pad invariant); for a def already matching the SDK layout+names, rename by hand and alias the old name.
- workflow: tools/commit_task.sh sweeps pending phase-ends/current/research and logs into whatever commit runs next (c1 swept R3.38-002 into b65da945f); commit research deliberately.
- harness: census exits 1 on parse_error_decls; chaining it `&&` struct_twins in one call ran past 285 s; run them as two calls.
- harness: `sed -i` on a >20k file is denied by the read guard; edit through a Python script.
- harness: `make extract-all` with output suppressed hides the 217 count; run R22 without `>/dev/null`.
- harness: cc1 error line numbers in ov_SC07_002_jr_8017C8D0.c are ~146 lines off the source; per-line respell misses them.
- harness: commit_task.sh refuses >100-char messages; `xargs -x -a list bash tools/commit_task.sh …` commits >2k paths without printing the list.
- harness: the previous expert's TASK_PROGRESS.md was absent at respawn although the brief pointed at it.
Research: R3.38-002 (swept into c1's commit), R3.38-003 (digest of T5.1 coder logs)
Next task needs: T6 owns parse_error_decls=1106, the last nonzero --check-structs count; after any fold, rerun struct_twins.py --write as its own call.
Verified: `type_census --selftest` → 33/33 OK; `type_census --out-dir .run/P38/census --no-cache --check-structs` → exit 1 solely on parse_error_decls=1106 (T6 scope), all other gating counts 0, controls 4/4; `make clean && make extract-all JOBS=16 && make check-all JOBS=16` → 217/217 extracted, 218/218 passed (.run/logs/t51v1.log)
Full log: phase-ends/current/logs/T5.1.md