Commit Graph

847 Commits

Author SHA1 Message Date
Drew T 449acd8cb3 phase-36: T7 sweep s4 and the OUT-OF-BODY defect fixed at its cause (R14 refuses what the body-only bank cannot take)
search: 0 of 139 exemplars matched lever-free in 0.54 h (0 of 7,077 bodies behind them; 52,566 compiles) — NO-MATCH 136 · BANK-REFUSED 3

- the three refusals are the three fleet copies of func_80136824, each a real score 0 (R15 sink + R12 width + R14
  param-width) blocked by a contract rather than by a bad body: the engine verifies the whole candidate text but hands
  apply_body_core only the definition, and --propagate remaps that body to siblings, so a generator that edits lines
  outside the definition can never bank. R14 is the only such generator.
- my first diagnosis was wrong and was discarded rather than shipped: I guessed the conflicting declaration was in a
  shared header and built a 2,431-name index to refuse on, and the index said the function is not in it. Reading cmd_run
  gave the real answer.
- two fixes: param_widths refuses outright when the TU declares the function anywhere but at its definition
  (protos_outside_definition; the earlier R14 banks had no such prototype, so nothing that worked is lost), and the engine
  names the condition itself with a new OUT-OF-BODY verdict instead of letting the bank die on a compiler error that reads
  like a bad body. Controls both ways in the selftest.
- the steering measurement (R41): across s1-s4 the head's 57 classes have absorbed ~128,000 compiles for 6 closes, all of
  them R15's and all in the first sweep. The head is resistant to every mechanical generator at this width; sweeps pay on
  the tail and on targeted families, and the head is what agents are for.
- open by name for the types phase: func_80136824 (133 copies) has a real crack that needs its prototype widened with its
  definition — the second measured case where a declaration, not codegen, stands between us and the bytes.
2026-09-10 05:00:01 -06:00
Drew T d71836107c phase-36: T7 agent a3 — func_801397B0 not closed (best 2), its reading toolified as R18 the bystander move
The third agent produced no bank and a precise refutation plus a generator, which is the deliverable the brief asks for.

- it refuted the a2 hypothesis on its own body: git grep returns 1,770 declarations in two forms, both (s32 a0), no (void)
  anywhere, and the pin is on a local rather than the parameter. Three lever-free spellings reach the target's complete
  register assignment, so the class is reachable from plain C.
- its best is score 2, class ORDER, 89/89 instructions, every register correct, one displaced bystander store. The target's
  sw sits inside the lbu->addiu window and that position is forced: anti_dependence and true_dependence (sched.c:817/845)
  both hold, so the store can neither hoist nor sink. Post-sched1 stream and reg_live_length then match ours, leaving
  reg_n_refs — computed by flow on the pre-combine RTL — as the only remaining input.
- R18 moves one simple statement to each other position in its own block, up to six away. R9's adjacent swap is the special
  case; the distance is the point. It costs no instruction where R7's LOOP notes are a full sched1 barrier and always cost
  one displaced insn, so R18 is ranked ahead of R7 in every class.
- two wrong spellings before the known-true check passed: identifier-disjointness as a requirement offered three candidates
  and none of them the agent's (it is only an ordering preference now — byte-identical output is the same program, so the
  oracle is the whole correctness proof, which is R9's own footing), and a blank line counted as an obstacle, so the
  generator never offered the very move it was written from. It now reproduces that body exactly: bystander @21->17.
- delever_pack.py now writes each trace candidate's residual class beside its score, from the agent's method note: a bare
  number hid that a move had already turned this body's residual from REG into ORDER.
- delever --selftest OK (3 new controls incl. the nested-block refusal); delever_search --selftest OK; tool_census OK.
2026-09-10 04:26:00 -06:00
Drew T 5603a114c2 phase-36: T7 sweeps s2/s3 — the constant-holder census corrected (537 of 17,302, not 284 of 10,958) and 10 bodies closed; the propagate namespace bug fixed
- s2 (the head, with R16/R17 added): search: 0 of 140 exemplars matched lever-free in 0.24 h (0 of 7,085 bodies behind
  them; 23,689 compiles). The two new generators closed nothing on the head; recorded as measured.
- agent a2's "284 constant-holder pins of 10,958" verified against the source rather than believed (R14), and my first
  instrument was wrong (R40): asking R16 directly answered 33, because R16 only fires on a split declaration while most
  pins carry their value as an initialiser. R3 converts one form to the other, so the reachable family is R3+R16.
  Corrected, both figures derived: 537 constant-holder pin sites of 17,302, in 510 bodies (152 initialiser, 385 separate
  assignment; by register $2 282, $20 136, $3 28).
- s3 drew exactly those 99 function names and closed 10 bodies before crashing with
  AttributeError: 'Namespace' object has no attribute 'allow_residue'
  in propagate — the a2 fix read the flag off the caller's namespace and the search engine builds its own Namespace for
  that in-process call. Fixed with getattr(a, "allow_residue", False): a library must not assume its caller's namespace
  shape (R43).
- the ten banks were real, proven by gating the tree the crash left:
  check-all: 218 passed, 0 failed of 218
  lever_census --check: 29,533 pin/asm sites, 29,533 marked !FAKE, 0 UNMARKED — OK
- by first move the ten are R15 x3, R6 x4, R7 x2, R9 x1 — the draw was right about the family even though R16 did not fire.
- snapshot row 13; s3 re-runs from the top with the fix.
2026-09-10 02:49:05 -06:00
Drew T 975850ff84 phase-36: T7 toolify a2 — generators R16 (constant holder inlined) and R17 (constant-run split), the directed form of a move R9 reached only by luck
- R16 writes a local whose only assignment is one integer literal at every use and deletes it. R6 stops at a temp read
  exactly once, so a holder read four times was invisible to the search and its whole family with it. Deleting it is
  byte-neutral alone but removes a quantity from the block, which is what lets the next move reach the allocator.
- R17 splits a run of consecutive same-literal assignments by moving the nearest differently-valued one into it, at each
  interior split point. find_free_reg's live-range scan (local-alloc.c:2109-2110): while the two constants' ranges are
  disjoint they share a caller-saved register; splitting makes the first live across the second and it takes another colour.
- known-true check: on the seed that keeps func_80168828's semantically-forced $4 pin, R16 then R17 reaches
  score 0 (OTHER; mine 108 ins, target 108) — MATCH at three of the six offered split points, in ten compiles where the
  blind search needed 2,271.
- the engine selftest's caller-saved assertion is now the ordering invariant (every targeted lever before every blind
  family) rather than a fixed window widened once per new generator.
- delever --selftest OK (4 new controls); delever_search --selftest OK; tool_census --check OK; SETUP row (R21).
2026-09-10 01:27:20 -06:00
Drew T 9c5ca46a2a phase-36: T7 agent a2 — func_80168828 at score 0 with the constant-holder pin deleted (125 bodies; 29,697 → 29,572 sites, R22 218/218)
- two moves: delete `register s32 c40 __asm__("$3")` and its `c40 = 0x40;`, writing the literal at its four uses (byte-neutral
  on its own — the pin was never doing the work); then swap the adjacent `f1e = 0x40;` and `f1a = 0x10;` so the 0x10 store
  splits the run of 0x40 stores.
- the residual reads like cse/sched and the decision is local-alloc's. Dumps of the real TU in both orderings differ on one
  .lreg line — `Register 76 used 5 times across 10 insns` -> `across 14 insns`, `Register 76 in 2.` -> `in 3.` — which is
  find_free_reg's live-range scan at local-alloc.c:2109-2110: unswapped the two constants' ranges are disjoint and share $v0,
  swapped they overlap and the first takes $v1.
- the $4 pin STAYS, and not as a lever: src/shared/ov/func_801687CC.h declares extern void func_80168828(void), so the
  target's `move s1,a0` has no C source. An uninitialised local, a pointer-typed one, a split declaration and deleting it
  outright all give the identical score-25 residual; both parameter forms are hard cc1 errors against that header. This is
  the first measured pin that only a declaration fix can remove — one of the 51 conflicts P35 ledgered for the types phase.
  The engine's score-1 text is a coincidence (its andi truncates garbage in $s1 and never reads $a0); not proposed.
- instrument fixed in the same change: --propagate refused all 124 siblings because the reshape deliberately keeps a lever.
  The allowance is now derived from the exemplar's own banked text (its surviving !FAKE markers), and a sibling whose remap
  would carry more levers than the exemplar is refused by name.
  delever --propagate: 124 of 124 sibling(s) banked, 0 refused
- check-all: 218 passed, 0 failed of 218
  lever_census --check: 29,572 pin/asm sites, 29,572 marked !FAKE, 0 UNMARKED — OK
- snapshot row 12; delever --selftest OK. The toolify (R16, the constant-run split) follows.
2026-09-10 01:23:22 -06:00
Drew T 861dd0651c phase-36: T7 toolify a1 — generator R15, the sink (agent a1's crack made mechanical; reproduces it from the pre-bank text at score 0)
The harvest half of the one-at-a-time loop (R16): agent a1's reading of func_80156044 is now a move the engine can make
on any body, so the remaining head classes get it for free.

- R15 sinks the statement AFTER an if/else chain into every arm and deletes the variables it consumed:
  `if (c) { v = e1; } else { v = e2; } w = f(v);` -> `if (c) { w = f(e1); } else { w = f(e2); }`.
- it is a REGISTER move, not a scheduling one. A value set in every arm and read after the merge is a cross-block pseudo
  local-alloc never gives a quantity (local-alloc.c:472, next_qty reset at :517), so the arm holds two quantities and
  takes block_alloc's unrolled case 2 (:1499-1502, qty_compare :1578-1596). Sinking makes it a third block-local
  quantity, and case 3 (:1491-1496) falls through into case 2 and applies that comparison a second time, undoing its own
  exchange — the two caller-saved colours swap. It also takes the value out of global.c, where set_preference
  (global.c:1535+) had given it a copy preference through the merge result's argument copy.
- applicability is checked, never assumed: each consumed variable must be assigned exactly once in every arm by a simple
  statement, appear in the merge statement, and occur nowhere else in the function.
- if_chains() counts a line's CLOSING braces before its opening ones. On a `} else if (...) {` line the two net to zero
  and the first version's depth counter never closed the arm — the generator found 0 candidates on the very body it was
  written from. Caught by running it on that known-true case before believing it.
- ranked third in REG-caller / REG-mixed / COUNT; the engine selftest's "R5 in the first three" assertion widened to
  "R5 and R15 in the first four" rather than de-ranking the new move.
- verified: delever --selftest OK (3 new controls: a variable read after the merge, a variable one arm does not set, the
  brace walk's three arms); delever_search --selftest OK; and the known-true check — R15 run on func_80156044's
  pre-bank text emits the agent's crack and `--try` scores it
  `score 0 (OTHER; mine 74 ins, target 74) — MATCH`.
- SETUP row rewritten (R21), kit corpus regenerated, tool_census --check OK (371 copies + 30 pointers, 0 gaps).
- no src/ change in this commit; the sweep of the other 56 head classes follows.
2026-09-10 00:45:15 -06:00
Drew T 7b2200edad phase-36: the tail pass g6 + g6b (47 + 63 of 400 small classes; 186/191 siblings propagated), R22 218/218; 30,806 → 30,358 sites; --try (a candidate scored without a tree write), delever_pack.py (the 57 T7 packs + PROMPT.md), --restore refuses an empty snapshot; the checkpoint: T7 as one agent at a time, approved, starts in the fresh session 2026-09-09 23:32:57 -06:00
Drew T 2f3ce92a15 phase-36: rung G run g5 — the head re-drawn wide: 5 of 70 (small classes, 62 bodies), R22 218/218; 30,892 → 30,806 sites; the wide-search lever is spent on the big classes (112,216 compiles); R14 rewrites prototypes, R8 names repeated operands/groups, R12 splits multi-declarator lines; C/D-only bodies are done and not drawn, the seed keeps class C/D sites 2026-09-09 22:07:17 -06:00
Drew T 1ec67f6677 phase-36: rung G run g4s — func_8016E9EC's shape closed in three classes (133 bodies, R22 218/218; 31,025 → 30,892 sites); generators R12 widths (u8/short/int), R14 parameter width, R8 shared base, R10 cast alias; the bank and propagation in process (apply_body_core); the per-tag scratch-object race fixed; propagate's empty-list return 2026-09-09 20:18:43 -06:00
Drew T 584031c717 phase-36: rung G generators R10 (parameter copy), R12 (width), R13 (reassociation), R8 common-subexpression; --explain reads a residual as mnemonic blocks; four declaration-run/statement defects fixed; the 6-distance class read: one surviving copy the width move does not reach 2026-09-09 18:28:59 -06:00
Drew T a4cbe0d5a3 phase-36: rung G run g1 — 1 of 16 exemplars (func_801424E4, the count-changing body rung D left at 2) closed by three composed moves, 132 bodies banked + propagated 131/131, R22 218/218; 33,427 → 33,295 sites; R5 skips constant operands (lane B's fold claim verified on bytes); bottom-up order within a file 2026-09-09 18:22:01 -06:00
Drew T 623e553408 phase-36: rung G — tools/delever_search.py, the guided search (the score is the oracle's own object read as an edit distance, the residual classified to pick the move families, a beam composing 2–3 moves; positive controls 1–2 PASS, 3 FAIL on a missing inverse); R8/R9 + the unwrap in delever's generator registry; the 301-row ledger hash defect fixed at its cause and repaired; lane B's residual→move map banked 2026-09-09 18:11:16 -06:00
Drew T 72a9ab1129 phase-36: the free-bank sweep measured — rung R is replication, not discovery (0 of 300 at cap 40 AND at cap 400; the cap was never binding at ~57 candidates/body; the instrument cleared by hand) 2026-09-09 16:10:11 -06:00
Drew T 1c2b8f2cc8 phase-36: rung R orders its candidates by distance to the NEEDED site — the lever says where to look; a flat cap had been truncating the tail (the aborted cap-40 sweep judged ~200 bodies and closed none, while the shape that closed func_80135D20 was a block wrap well down its body) 2026-09-09 15:56:36 -06:00
Drew T 2d8ee30a10 phase-36: rung R made TU-parallel — a worker owns a whole translation unit (the oracle writes each candidate to the real source path and names its scratch object after the object it builds), shared headers stay serial (two headers can share an includer's object), bodies judged bottom-up within a file so a bank never shifts a body still to come, and the in-flight map is per-file under the lock so a killed run restores every worker's file 2026-09-09 15:56:07 -06:00
Drew T aef1159488 phase-36: T6 CLOSE — both yield lines measured (permuter 5 of 16 exemplars / 665 of 2,131 bodies; recipes 134 of 134 in 6.0 min), 664 sites gone (34,091 -> 33,427), R22 218/218 at every step; the S99 checkpoint written for T7 (which starts only on Drew's direct approval) with the parallelised rung-R sweep as the drawable work meanwhile 2026-09-09 13:02:51 -06:00
Drew T a2da99b130 src(phase-36): T6 rung D banked — the four exemplars the permuter closed, tidied and byte-judged (R22 218/218)
- delever_permute --bank: 4 winners applied through delever --apply-body, each IDENTICAL on its own object; the winner is
  now TIDIED first (pycparser reprints a body it parsed: two-space indent and a corpse `;` where a statement was inlined
  away) and the tidy is judged like any other candidate, so the source keeps the tree's shape; parenthesisation and brace
  style are deliberately left to the formatting phase, over the whole tree at once
- a slip, named: --bank re-applied a permuter body over the ONE-LINE version rung R had already banked for
  func_80135D20; the clean text was restored through the oracle (label d1fix) and --bank now skips any body the ledger
  already calls LEVER-FREE
- --recipes is killable now: the oracle writes the candidate into the tree to compile it, so the original goes into
  inflight.json first (P35's rule: a tool restores from its own snapshot) — a killed run had left a candidate in src/
- rung R's R6 generalised from "assigned once, read once" to "dead after one read" (the lever rung D actually found:
  uVar5 is assigned in two branches and only one was inlined); it still does not reproduce that class's win, which is
  recorded as an open item rather than papered over
- lever_census: 33,953 sites (was 33,957), 0 UNMARKED; lever_progress snapshot "T6 d1"; R22 218 passed, 0 failed of 218
2026-09-09 12:21:42 -06:00
Drew T 8fac96651f docs(phase-36): the lever series as a tracked deliverable — docs/levers.md + tools/lever_progress.py (Drew's directive)
The pin/hint removal's COUNT OVER TIME is a deliverable in its own right: the post-100% chart, the story's spine, a wiki
page, and the day-one rule the decomp-architect kit should carry. It is only ever counted by the phase that removes it, so
it has to be captured while the work happens — a census is a moment.

- docs/levers.md: the taxonomy (A pins · B1-B4 barriers/launders/keep-alives/hand-placed instructions · B5 GTE, not a
  lever · C volatile · D bare register · E asm-label aliases · F builtins · G attributes); a GENERATED §2; how the levers
  got in phase by phase (P18's pin toolkit took the wave close-rate 33% -> 56% -> 90%; the family engine then copied every
  lever across up to 134 overlays, which is why 1,758 distinct bodies are 12,578); the ladder with each rung's measured
  yield; §5 the prevent-vs-defer argument; §6 what the wiki, the kit and the story each take.
- tools/lever_progress.py: --snapshot appends a milestone row (the census's totals by class + HEAD) to
  docs/lever-progress.tsv and re-renders the document; the campaign table is derived from the de-lever ledger on every
  render and scored as state TRANSITIONS, so the rung that FINISHES a body gets the credit (counting first-rows-only
  reported rung R's 134-body batch as zero); --check refuses a series that is not this tree's.
- the numbers, generated: 21,061 sites removed or rewritten across 17,119 bodies against 33,957 still standing — 38% of
  the class A/B population came off with no understanding at all, which is the evidence behind §5's rule:
  BAN THE SILENCE, NOT THE LEVER (a lever is allowed and is a marked, ledgered, published debt from the first bank, with a
  one-compile bank-time trial; never block the byte gate on it).
- Reference-index row (doc_links OK), SETUP row, tool dictionary row, CURRENT_PHASE entry for the story.
2026-09-09 12:10:24 -06:00
Drew T 71312c0061 phase-36: T6 — rung R gains R7 (one statement wrapped in a block, the readable spelling first), the move that closed func_80135D20 in 24 s; --cap bounds the candidates per body 2026-09-09 11:19:16 -06:00
Drew T 1dc0751056 phase-36: T6 — delever --propagate: a reshaped body's class re-banked by address remap (one crack -> up to 134 bodies); apply-body now records the before/after body text, which the remap needs and which exists nowhere else after the write 2026-09-09 11:15:05 -06:00
Drew T 4b6a970d59 phase-36: T6 — rung R gains R6 (inline a single-set temp at its use), the move rung D found first on func_80163EC8; selftest cases for both declaration forms 2026-09-09 11:13:42 -06:00
Drew T c0e8fbdaae phase-36: T6 — the rung-D instrument fixed (the target was assembled from a listing), rung R built (R2/R3/R4/R5)
THE INSTRUMENT (R40). Two campaigns returned "0 of 16" with a straight face; both were the harness. The target object had
been assembled from a DISASSEMBLY LISTING, which is a second toolchain with its own answers:
  - objdump prints the pseudo-instruction `move` for `addu rX,rY,$zero`; gas assembles `move` as `or` — 24 wrong words in
    one 234-instruction function, silently;
  - a listing's %hi/%lo pairs come back RESOLVED with no relocation, while every candidate carries one, and the masked
    scorer compares reloc operands.
The permuter therefore scored 28 for a body that IS byte-identical: score 0 was unreachable and every NO-MATCH was its own.
  - tools/delever_permute.py: the target is now the tree's OWN (levered) body compiled by the build's tail into a
    one-function object — the candidates' relocations by construction — and `match_one` must call that body a MATCH against
    the ROM listing before the search starts (R34 keeps it from being circular). Base score for the tree's own body: 0.
  - tools/p16_permute.py `setup(target_o=)` + tools/permuter_ils.py `--target-o` (defaults unchanged).
  - `--positive-control TU FN`: perturb a matching body by one commutative swap, require the permuter back to 0.
  - tools/verbatim_target_s.py --gas now VERIFIES itself: assemble, disassemble, compare word by word with the image,
    `.word 0x…`-patch what does not reproduce (24 in that function), REFUSE what still disagrees. The listing is a public
    artifact (decomp.me) and was wrong for every function containing a `move`.

THE PROFILE. The weight profile now comes from the register a needed pin names, not just the site kind: callee-saved
($16-$23) is an allocation-order residual -> regalloc; caller-saved ($2/$3/$4-$7) is not -> cse. Read from the bytes: the
residual on func_80163EC8 (`register … __asm__("$2")`) is `and v0,v1,v0` against `and v0,v0,v1` — the operand order of one
`&` — and the regalloc profile weights perm_commutative 2.0 while cse weights it 40.0.

RUNG R (tools/delever.py --recipes): the cookbook's byte-neutral shape recipes, mechanically, seeded with the body's
lever-free text — R2 the formerly-pinned declarations permuted, R4 one moved through the whole declaration run, R3 an
initializer split placed after the run (C89), R5 the operand order of one commutative operator (the caller-saved lever, and
the only recipe needing no pinned declaration). Identity control on both the splice and the oracle before any verdict;
markers scrubbed within the banked body's own span only; selftest cases on a fixture whose answers are known by hand.

Also: a threading race in the site cache published the empty dict before filling it and made a whole batch report
"no site in this TU"; the file-scope asm dropper took an asm-LABEL clause for a statement. SETUP + dictionary rows.
2026-09-09 11:08:20 -06:00
Drew T 6e1677b4da phase-36: T6 rung D built and calibrated — tools/delever_permute.py, the GTE levers on the ladder (462/462), four harness defects
- tools/delever_permute.py: one exemplar per RESIDUE text class from the ledger (copies desc, needed asc) prepared as a
  single-function TU (delever's rung-A rewrite; other definitions -> prototypes; shared-header includes -> their prototypes;
  INCLUDE_ASM and file-scope asm dropped; the build's own CPPFLAGS through cpp -P), the target regenerated from the ROM image in
  BOTH forms (--gas for target.o, splat for match_one), permuter_ils with the profile from the NEEDED kinds, a winner banked only
  through delever --apply-body + the GTE re-fold. Scratch/winners keyed alias+fn (R48).
- the control (R39/R56, new): every attempt first requires the LEVERED body to be match_one MATCH against the regenerated target,
  then records the lever-free body's distance. --calibrate --limit 12: 12 of 12 MATCH; starting distance min 8 / median 78 / max 276.
- delever: ("B","gte-lever") joins REMOVABLE — a direct statement's clobbers reset to its canonical set, a variant-macro use pointed
  at the canonical macro whose name comes from the variant definition's SIGNATURE (gte_rt_m -> gte_rtv0tr, not Sony's gte_rt);
  462 of 462 gte-lever sites now offered to the ladder, 0 before. gte_consolidate.canonical_match() is the one reader of the
  canonical table (R33), direct_rewrite refactored onto it; both selftests green.
- p16_permute.setup(outdir=) + permuter_ils --pd: a scratch dir keyed by the caller, defaults unchanged.
- four harness defects found by running it: the splat listing is not assemblable (R98 in a second place); pycparser rejects
  __attribute__ and the permuter then silently permutes nothing; include_asm.h injects a file-scope .include "labels.inc" that
  collides with the permuter's own macro.inc; an asm-LABEL clause is not an asm statement (a bare scan ate one and left a headless
  K&R body). SETUP row (R21), dictionary row (R87), .gitignore allowlist for the outcomes ledger.
2026-09-09 10:21:16 -06:00
Drew T d025e67e71 phase-36: T5 CLOSE — the GTE consolidation and the dead-macro sweep: include/gte_inline.h (50 canonical macros for 9,102 definitions), 8,951 per-TU definitions deleted, 629 clobber variants freed byte-identical and 70 kept as marked levers, 575 direct statements → Sony-named calls, 274 dead launder macros swept; the census learns cross-file macro names (10 launders surfaced in two shared headers, 6 removed); per-TU asm macro definitions 9,540 → 314 with 0 canonical duplicates; THE NUMBER 34,091 sites (incl. 462 GTE levers) in 12,712 bodies, all marked, 0 orphans — lever_census --check OK; R22 218/218; SETUP rows; kit corpus; the 🛑 block for T6 2026-09-09 07:12:06 -06:00
Drew T 3b2c5178b6 phase-36: T5 — the scrub of 3 markers orphaned by the rejudge (R22 218/218, r22_sweep1.log); delever --scrub --dirty-ok; the sweep's dead-macro test skips a name's sibling definitions (SHB is defined twice per unit, so nothing was ever dead); kit corpus 2026-09-09 06:38:42 -06:00
Drew T 5b6e1a2fe7 phase-36: T5 — the consolidation applied (644 files: 8,951 per-TU GTE definitions gone, 629 clobber variants byte-identical without the clobber, 70 kept as marked levers, 575 direct statements → canonical calls, 85 header-bound homonyms kept) + the marker repair (scrub 344 misplaced, re-mark 349); four instrument fixes: scoped renames, header-bound homonyms kept, object-like macros, the canonical table stable (the header's definitions in the inventory) and the census cache keyed on the tables; R22 218/218; the number 34,090 (33,625 + 465 GTE levers) all marked, 0 orphans, --check OK; kit corpus; log entry 2026-09-09 06:29:00 -06:00
Drew T 0bd784c64e phase-36: T5 (header step) — the GTE consolidation: tools/gte_consolidate.py (signatures by the build's own maspsx→as tail: bytes + operand counts + clobbers; one canonical text per signature under Sony's names, Sony's clobbers canonical even when every definition carries the steer; lever variants <name>_m tried as canonical first; direct statements → canonical calls; --sweep), include/gte_inline.h (50 macros for 9,102 definitions) included from common.h — R22 218/218; the census's gte-lever class + per-TU definition count + strict gate; the cycle's MODE=gte; dictionary + SETUP rows; kit corpus; log entry 2026-09-09 05:28:50 -06:00
Drew T 917c68afd9 phase-36: T4 CLOSE — the mechanical campaign over the whole population: 16,334 bodies judged in 13 gated batches (3,341 lever-free = 20.5 %; 21,063 of 56,445 sites removed or rewritten = 37.3 %; 8,239 replays, 1 disagreement; 49,487 compiles); the file-scope asm statements judged too (batch tus11: 6 barriers NEEDED, 7 .section blocks refused as asm-data and marked); THE NUMBER 53,234 → 33,625 sites (−36.8 %) in 12,501 bodies (1,728 distinct), 33,625 marked, 0 UNMARKED, 0 orphans — lever_census --check OK; the residue 12,967 bodies in 1,803 distinct classes (pins-only 6,018 · pins+asm 4,310 · asm-only 2,141 · C/D-only 498); published by make report (README line 30, progress.json counts.levers, the timeline); kit corpus; the 🛑 block rewritten for T5 2026-09-09 05:05:33 -06:00
Drew T fa008b8629 phase-36: T4 — the census's known-true controls keyed on their bodies' T1 text hashes (N-A once the campaign edits a control body: tus7 removed func_80184034's three bare-name pins and the census refused a correct tree); the cycle's FINISH=<label> mode completes a batch from its green logs (tus7 finished so: 34f03003d); kit corpus; log entry 2026-09-09 04:04:14 -06:00
Drew T 77a1298cb7 phase-36: T4 — batch tus3 killed mid-apply by the harness's low-memory guard (22 GB free): recovered by dropping its 641 ledger rows (backup) and --restore (50 files, src clean); --restore now drops the in-flight label's rows itself (inflight.json carries the label); the cycle's usage: run it DETACHED (setsid nohup) with a tiny waiter; SETUP row; kit corpus; log entry 2026-09-09 03:35:35 -06:00
Drew T dd01cbdf6e phase-36: T4 (tool fixes between batches) — 'done' is per body (tu, fn, after-hash): keying it by text alone let every fleet-wide copy of an all-NEEDED exemplar pass as done unmarked (2204 → 2483 drawable files); the includer map cached per file (29 s → 1.3 s per batch, equal to the uncached map); the cycle waits out a transient .git/index.lock and clears a stale one (batch tus2's commit was lost to one and committed by hand, 85905840c); kit corpus; the log entry with tus1/tus2 — the number 46,424 sites in 14,758 bodies · marked 9,393 · unmarked 37,031 2026-09-09 03:30:53 -06:00
Drew T e5f59c12f4 phase-36: T3 close — the campaign tool proven end to end on ov_SC04_011 (batches t3_tus1 + t3_tus2, R22 218/218 each): the zero-register use composed into its host edit (the one refused body redrawn via --redraw), a removed site consumes its trailing !FAKE marker, the census counts ORPHAN markers (--check fails on them; the walk cache keyed on the tool's hash — it had hidden them) and delever --scrub removes them (2 scrubbed here, object identical, R22 218/218 wall 143 s); the cycle's greps fixed (no ^ anchor, an empty verify line refuses, THE PHASE'S NUMBER line, entries before the checkpoint block); the number 53,033 sites / 15,638 bodies (2,246 distinct) · 310 marked · 0 orphans; SETUP + dictionary rows; kit corpus; the t3_tus1 entry rewritten from the logs (R66); the 🛑 block rewritten for T4 2026-09-09 03:14:30 -06:00
Drew T 39e3e1851f phase-36: T3 (tools) — tools/delever.py the campaign tool: --plan/--apply (the file is the write unit, its final compile through every recipe the proof; 'done' = a ledger fact keyed by the body's normalized text before/after; replay from an exemplar in one compile; !FAKE markers on class A/B survivors; --restore from inflight.json; --apply-body for T6/T7; a selftest with a stub oracle), the launder-ASSIGNMENT rewrite (989 of 4,793 direct launders — deleting them made cc1 2.7.2 abort: the probe's 'Done' error, reproduced 3/3), macro shapes (SHB deleted, a launder expression valued, compound macros refused for T5), the oracle's COMPILE-CRASH verdict + judge_all + the mtime restore, the census's src_stamp/head, tools/delever_cycle.sh (apply → R22 → census → log + headline → commit); selftest OK; census 53,234 unchanged; calibration 177/177; plan ov_SC04_011 = 18 files / 176 bodies / 540 sites; SETUP + dictionary rows; kit corpus; T7 waves need Drew's direct approval (decisions) 2026-09-09 02:45:58 -06:00
Drew T 617f29e30c phase-36: T2 — the oracle and the probe: tools/delever_oracle.py (4,284 recipes via make -n -W; a candidate compiled in place to a scratch object and compared with the fleet run's; calibrated 177/177 untouched + twin 32/32 + positive control DIFFERS) and tools/delever.py (positional rewrites per lever class, rung A strip-all + rung B greedy, headers serial after the TU phase); --probe on 283 distinct bodies: A identical 53/283, sites removed 561/1,309 (42.9 %), needed 748 (launder 77 %, barrier 82 %, pins 45 % — v0/v1 + a0–a3 dominant), 0.225 s per compile — T4 priced at ~94k compiles ≈ 0.5 h, the residue ≈ 81 % of bodies ≈ 1,800 distinct exemplars; dictionary + SETUP rows; kit corpus; the 🛑 block for T3 2026-09-09 02:03:04 -06:00
Drew T a1407bdfc1 phase-36: T1b — the verbatim manifest learns the in-function form (49 rows: 27 PERMANENT hand asm incl. 22 per-overlay scratchpad stack-switch trampolines, 8 Sony GsTMDfast* routines carried as asm, 11 DECOMPILE-NOW + 3 UNCERTAIN game bodies never decompiled); verbatim_check detects the form structurally via lever_census.whole_body_asm_functions (--strict: 2,709 bodies, no drift); the census defers exclusion to the manifest's dispositions — the phase's number 53,234 sites in 15,679 bodies (2,227 distinct); progress.py counts PERMANENT (27) + SDK (8) with a dated correction; README/wiki/verification/gen3 docs corrected (14 game functions were asm in C shells); kit corpus 2026-09-09 01:44:31 -06:00
Drew T 357f8a1ed3 phase-36: T1 — tools/lever_census.py, the self-asserting lever census (coverage asm 80,396 = 66,415 live + 7,189 macro-block + 6,792 comment/dead; 4/4 controls; the five manifest bodies excluded): 53,221 pin/asm sites in 15,666 bodies (2,214 distinct) — 37,720 register pins + 15,501 asm statements, 0 marked; 6,911 GTE ops and 23 whole-body asm routines in C shells (2,683 sites, outside the manifest — Drew's call) set apart; progress.py levers block + README sentence; dictionary + SETUP rows; kit corpus; the 🛑 block for T2 2026-09-09 00:52:22 -06:00
Drew T ac8c29edb1 src(phase-35): T5b — the text tier: 38 same-address functions whose bytes vary per binary (the TU's declaration environment carries the original per-overlay variance) share one text each through h_text registry groups with per-member h_exact — 1,957 private copies in 1,540 TUs replaced by the include, 38 headers (func_<VRAM>__t<hash8>.h), 138/138 binaries green per binary, 0 rejected; dedup_integrate C1 per member (3173 validated, 0 failed); share_census indexes h_text groups by site, exports text classes, the S1 text half is a violation (0 now), the census json carries the oracle's counts; share_body --bucket text; progress.py/README: 103,015 bodies written once, 38 text-tier functions / 2,030 sites, 1,668 copies of 381 tiny bodies deferred; R22 clean fleet 218/218 in 90 s; SETUP; kit corpus 2026-09-08 22:39:42 -06:00
Drew T c8224e657f tools(phase-35): T7 — the S1 invariant wired into tools-health (share_census --selftest + --check --strict-macros --strict-text, by exit code), C2c/C2d in dedup_integrate --check (one source under src/shared/ defining one function; every member's site includes it — from the census's per-instance forms), progress.py: unique_function_bodies 105,007 / duplicate_source_copies 160 in 51 ledgered classes + the dated corrections list + the README sentence; the second oracle refined (distinct TUs; deferred vs pending vs violation): 380 texts deferred inside cross-address classes, 38 same-address texts / 2,030 sites byte-variant per binary (PENDING the owner), 0 violations; negative control in place: one reverted include -> S1 FAIL naming the class + C2d naming the member; tools-health OK (551 s) 2026-09-08 21:46:05 -06:00
Drew T db63fcc673 tools(phase-35): T6 part 2 — the dead macro branches dropped from 12 live tools; the macro-form guard in tool_census --check (ast scan of every LIVE tool, FROZEN/retired/6 whitelisted detectors excluded; 0 LIVE tools reference the retired form; --guard-root negative control: the pre-T4 tree flags exactly the 12 fixed + 3 retired); progress.py: an empty-bodied included member is EMPTY, not folded into REAL (the R32 bucket assertion caught the double count) — the fleet denominator 363,221 -> 363,680 (+459: SC03_015's 219 single-site macros, SC03_118 +3, the never-extended members of five groups) and REAL 360,744 -> 350,533 with EMPTY up the same; progress.json + README block + fleet table regenerated; SETUP; kit corpus 2026-09-08 20:53:05 -06:00
Drew T 5a9f455e60 tools(phase-35): T6 part 1 — 14 macro-era tools FROZEN (tools/frozen.py: one refusal from main(), imports never exit; the plan's 7 + 7 the guard census found, family_remap's CLI among them), 4 retired to tools/sunset/ (dedup_propagate + dedup_extend -> share_body.py with add_members_surgical and the load_sig library moved verbatim; macro_draft; test_reconcile_ledger), six lane callers repointed to share_body --apply --bucket new, validate_targets imports share_body, tool_census accepts FROZEN; dictionary + sunset README rows; kit corpus 2026-09-08 20:34:41 -06:00
Drew T cd43347791 config(phase-35): T5 CLOSE — the registry behind the source repaired (639 including-but-unlisted members added to 5 groups, the 5 verbose groups converted to shorthand; add_members_surgical refuses a verbose group, R43); S1: 10,180 classes, 10,180 satisfied, 0 violations (share_census --check exit 0); same-vram backlog 1,099 -> 51 classes = the ledger (50 TU-CONFLICT + 1 GATE-REJECT); dedup-check 3135/0; audit-binaries OK; registry 2,220 -> 3,135 groups; the tail run (bucket new empty); cycle logs; SETUP (the context guard); kit corpus 2026-09-08 20:24:28 -06:00
Drew T e4b25e5f70 tools(phase-35): T5 — share_body_cycle.sh, the unattended batch cycle for bucket new (batch → exit code + gated N/N → phase-log entry → commit → clean fleet run every N batches, stops on the first red); share_body --label; dictionary row + SETUP; kit corpus 2026-09-08 19:53:09 -06:00
Drew T a60340c6d4 src(phase-35): T5 — E_func_80168B70 re-exemplared from the majority text (share_body.py --reexemplar: header ← ov_SC01_000's copy, 7/7 includers green first, then 134 private copies → the include in 129 TUs, 141/141 binaries green, 0 rejected; the minority-header ledger row dropped); bucket 0 closed: 183 classes → 135 fully shared, 48 ledgered TU-CONFLICT (late-overlay declaration conflicts, for the types phase); SETUP paragraph (--batches, snapshot restore, the cause rule, --repair-registry, --reexemplar); kit corpus 2026-09-08 19:41:40 -06:00
Drew T 5325fd506b src(phase-35): T5 bucket 0 run 3 — 78 private copies in 24 TUs replaced by the shared include, 87 members extended (141/141 binaries green per binary); share_body: a twin's instance queued the same (tu, line) edit twice and the second replacement swallowed the next function (7 classes rejected in the five twin primaries on that artifact; now deduped), chained file:line: warning lines never a cause; the ledger re-judged by the fixed tool: 49 rows with real diagnostics (conflicting types / too few arguments in the late overlays), E_func_80168B70 kept with its cause pending the exemplar decision; kit corpus 2026-09-08 19:31:19 -06:00
Drew T 090f8fb428 config(phase-35): T5 — the registry repaired: 378 listed-but-private members removed from 79 groups (share_body.py --repair-registry, derived from the census on (binary, vram); the 317 ledgered rejected pairs + 61 sites the S94 bisects wiped); dedup-check 2221/0, C1 256,120/256,120; census A 1,812 · B 183, same-vram backlog 1,099 -> 999 classes; the first cut's name-only match (9,269 removed, 14 groups emptied) caught by dedup-check + a known-true control and reverted before commit 2026-09-08 19:20:48 -06:00
Drew T f4163518a2 tools(phase-35): T5 — share_body.py: the failure cause is the first non-warning file:line diagnostic (gcc 2.7.2 errors carry no 'error' token — 254 of 303 rejections had read 'Error 33'), reason codes SYMBOL-NAME / GATE-REJECT / PARSE-ERROR / TU-CONFLICT derived from it and recorded with the cause in every ledger note, the bisect restores from an in-memory pre-edit snapshot (never git checkout — it wiped the previous batch's uncommitted shares), one batch per invocation by default; controls on the real red cc1.err + six synthetic logs; ledger header + kit corpus 2026-09-08 19:14:45 -06:00
Drew T 571374b979 src(phase-35): T5 bucket 0 (first pass) — 788 members extended into their registry groups, private copies replaced by the include where the per-binary gate held (141/141 and 146/146 binaries green after bisect); share_body: the bisect now re-applies the kept classes in one bottom-up pass per TU (its per-class sequential re-application had shifted later classes' lines and rejected 125 of 183 classes on its own artifacts), the failure detail from error lines only, rejected extend classes ledgered, groups extended only with members that passed 2026-09-08 18:30:29 -06:00
Drew T 0bccef9016 tools(phase-35): T5 — share_body.py, the permanent share tool for the include-at-site form (exemplar by majority text, header written once, private copies → include at their position, per-binary gate with object comparison and bisect, registry appended by text, exception ledger); the R37 probe: func_801681FC shared by ov_SC04_008 + ov_SC05_009 (2/2 binaries green, group S_func_801681FC); the census exports per-instance line ranges; bind_alias_header factored out of macro_to_header; SETUP + dictionary rows; kit corpus 2026-09-08 18:12:41 -06:00
Drew T a8457663fc src(phase-35): T4 finalize — engine_core.h, ov_setters.h and clearTbl40.h deleted; the legacy sites converted (clearTbl40 as the SHARED_FN parameterized control in src/800_c.c; the three SC01_005 accessors as headers), the whale header moved under ov/ with every -O0 includer rewritten, 7 alias-form bodies given their own __asm__ binding, the registry's source/func lines text-edited by id, three non-shared headers rewritten; --verify OK (0 macro sites, no macro header); R22 clean fleet check-all: 218 passed, 0 failed of 218 in 145 s; dedup-check 2220/0; audit-binaries OK; the census 362,389/362,389 with 0 macro sites; SETUP + dictionary rows; kit corpus 2026-09-08 18:06:04 -06:00
Drew T c53a9e1a91 src(phase-35): T4 — every DEFINE_func_X() macro body becomes a plain-C header under src/shared/<space>/ included at its site (sotn's shape): 2,215 headers (ov/ 2,204, three module slots 12; 86 with the stable h_exact suffix), 246,347 sites in 3,818 TUs, the engine_prelude.h include in place of engine_core.h, 1,300 dead macros dropped; L0/L1: 213 binaries BYTE-IDENTICAL, 4,121/4,121 objects byte-identical before and after (tools/macro_to_header.py --apply, .run/P35/convert/ledger.txt); engine_core.h and the legacy headers still present until --finalize 2026-09-08 17:51:39 -06:00