Commit Graph

1093 Commits

Author SHA1 Message Date
Drew T 7ce1cd1801 docs(phase-32): T2c CLOSE — 20 free banks, R22 218/218 rc 0, census 54 stubs / 6,376 ins; disc-completeness P32 section (parked ledger EMPTY, audit-disc UNCLAIMED 0 of 220); regenerated fleet/disc/dup digests; T2d not needed 2026-09-05 00:49:07 -06:00
Drew T 8b2bbff831 fix(phase-32): T2c (1) — split_indicator's population is derived from the yamls (was a stale stored 213-name list; tools-health said "213 OK of 213" over 218 binaries); R32 denominator assertion 2026-09-05 00:08:44 -06:00
Drew T 6853c0c341 docs(phase-32): cookbook §499 (static base evidence for a never-onboarded payload; the first build is a NULL oracle for fine base errors) + decision-log P32 S81 (R31: six instrument defects, one shape) 2026-09-04 23:55:26 -06:00
Drew T 1e843c607a feat(phase-32): T2b (4) — SC03/56 ONBOARDED as md_SC03_056 @0x801CBB50 (ov_SC03_002's DESTPTR), byte-identical bc768a6b; ALL FIVE parked payloads are now binaries (fleet 213 -> 218); evidence tool v2
- md_SC03_056 (TEXT_LO 0x4, 4 stubs / 61 ins): 15/17 pointers cluster inside at 0x801CBB50; one outward call
  (0x8018151C) hits a function only 3 overlays have, ov_SC03_002 among them; req_fit 9/9 for ov_SC03_002
- payload_base_evidence.py v2 (controls 7/7 throughout): (a) STRONG = internal jals + fn-ptr-table entries on the
  module's own starts >= 2 (SC03/53 STRONG); (b) OUTWARD-EXPLAINED — a pure jal-vote base whose "internal" targets
  are function starts of the fleet's overlays is downgraded: SC03/56's 0x80178C8C was two SHARED-engine functions
  spaced like two of its five starts (and nobody's DESTPTR), a false STRONG; (c) the requester cross-check is
  informational only — shared engine code makes every requester fit (an R39 control caught it scoring: 6/7)
- memory-map §S45 p7 amended: all five rows ONBOARDED + the two instrument findings (the first build is a NULL
  oracle for FINE base errors — +8 builds byte-identical, +0x1000 fails the link; outward-explained vote bases);
  SETUP row amended. The parked-for-L3 ledger is EMPTY pending `make audit-disc` (T2c).
2026-09-04 23:52:58 -06:00
Drew T 848c7c50ab feat(phase-32): T2a — tools/payload_base_evidence.py (controls-gated static base evidence) + memory-map §S45 p7: the parked five get candidate bases
- the instrument: module-id word, TEXT_LO estimate, absolute-pointer set, lui hi-half histogram, and a
  jal->function-start VOTE (starts = prologues ∪ the word after every `jr $ra`+delay — leaf functions have no
  prologue, the recall killer of S45's vote_base 4/12); scores a BOUNDED candidate list (5 §S44 slots ∪ 134
  IDXTAB DESTPTRs ∪ vote bases): STRONG / CONSISTENT / INCONSISTENT / NO-EVIDENCE; AMBIGUOUS tie sets are
  printed, never picked; a payload with no self-reference is REFUSED as base-independent (R43)
- R39 controls run before any emission: md_MAIN_008/011/013/042, md_SC03_073, md_SC02_009, md_SC07_004
  re-derive their byte-proven bases top-ranked from their payloads alone (7/7); TEXT_LO estimates == yaml
  (incl. the header-table modules 0x7C/0x14/0x158). The first draft of the scorer FAILED 5/7 (prologue-only
  starts; a top-rank assertion on modules the bytes cannot discriminate) — fixed by the controls, not shipped
- the five (G5 static-derived, US): MAIN/7 STRONG 0x800CEDF8 (9/9 jals, 14/16 ptrs on starts); MAIN/9 STRONG
  0x800CD348 (6/6, 9/9); SC03/53 + SC03/54 CONSISTENT with 0x801EF468 top of a 12-way tie; SC03/56 SPLIT
  (jal vote 0x80178C8C vs pointers/lui ~0x801CBB50). T2b probes each with new_binary.sh — the byte gate decides
- SETUP row (R21); evidence rows .run/P32/t2a/evidence.json
2026-09-04 23:42:53 -06:00
Drew T 059266afca feat(phase-32): T1c — md_MAIN_034: func_800CB00C (123 ins) BANKED byte-identical 46153c06 from the stored S72 body; its S68 "compiler wall" pin dropped
- the census's best_draft (.run/wave_g0c/shard30, 174 ins, 7 pins) was a DIFFERENT, wrong body under the bare
  name (R48); the journal (R38) named the real one — .run/O21/opus/func_800CB00C.c (88 lines, 7 BLOCK-scope
  callee externs: gcc-2.7.2 demotes the later-definition type conflict to a warning at block scope). rtu_match
  MATCH 123/123 in the real TU (the S75 redraft too); the S72 resolver had gated only the wrong file, 3x.
- raw splice into src/md_MAIN_034/md_MAIN_034.c; module island pads derived at build (§303); make build
  BINARY=md_MAIN_034 -j8 rc 0, sha 46153c06bca859dec05aff59fb1a77d3add3d02b == check (R53); verbatim strict ok
- config/wave_exclude.txt regenerated (exclude_audit --write): the md_MAIN_034 WALL pin labelled a wrong draft,
  not a wall — 8 -> 7 entries; docs/backlog.md re-rendered (matched rows drop)
- 0 drafting tokens; no Sonnet agent needed (plan T1c adjusted: no redraft)
2026-09-04 23:38:03 -06:00
Drew T c513e1fbbd feat(phase-32): T1a (2) — resident: func_800D128C (243 ins) BANKED byte-identical 8e17e02f via the raw splice + a 5-piece carve; three instrument fixes (§498)
- BANK: the stored S71 closeness-0 draft spliced into src/resident/resident_jr_800D128C.c; jtbl_carve --func
  carved jtbl_80113FB8 (119 entries, 1 pad word trimmed) + jtbl_80114198 into [0x451c0, .rodata,
  resident_jr_800D128C] + [0x453c4, data, tail3]; JTBL_PADS 0,4; make extract + make build BINARY=resident -j8
  rc 0, sha 8e17e02ff8954d07c979449198f7e1645046b353 == check (R53). pads_audit ok/ok; interleave_check
  ALIGNED n=5; verbatim_check --strict 5==5. Resident stubs 2 -> 1 (func_800D06E8 remains).
- WHY THE GATE SAID DIFF (parallel_gate banked 0/DIFF on an rtu_match MATCH): jtbl_carve.set_overlays_var
  regenerated resident_JTBL_INTERLEAVE from the carve set and DROPPED the resident's `--pre hdr.rodata.o`
  (§8f leading-rodata sandwich); make extract refused (ld_interleave: hdr.rodata.o would be parked with
  .text), the build linked the STALE script (249,252 differing bytes from file offset 0x4), and
  harvest_verify._jtbl_prep_one never read the post-carve extract's exit code (R49/R61).
- FIXES (R35/R40/R57): jtbl_carve._merge_pre carries an existing --pre forward (idempotent; overlays
  unchanged, 4-shape unit control); harvest_verify refuses loudly on a failed post-carve extract and
  restores the snapshot (CARVE refusal, NOT a draft verdict); interleave_check's anchor accepts a leading
  --pre (was a false DRIFT n=0 on the resident; control ov_SC02_017 ALIGNED n=44 unchanged).
- cookbook §498 (+ the stale-asm-after-a-failed-extract sequencing law); SETUP rows for all three
2026-09-04 23:28:59 -06:00
Drew T c52190ca86 fix(phase-32): T1b (1) — jr_isolate_all keys a bodiless typedef struct Tag Alias; by the ALIAS (§497); ov_SC02_017 dry-run REFUSED -> CLEAN, no source rename
- _type_names returned the TAG for `typedef struct Rec801806C8_s Rec801806C8;`, so the typedef block and the
  tag's own packed struct definition collided under one key with different bodies and the R43 "CONFLICTING
  bodies — a rename is needed" refusal fired on legal C. Now keyed by the alias (_TYPEDEF_TAG_ALIAS); the
  `carried` set learns the alias; `typedef struct X X;` (alias == tag) keeps the old key so a second one
  still dedupes/refuses. Unit control on 7 block shapes PASS; ov_SC02_017 --only func_80186C64 --dry-run:
  2 region files, no carve repoints. cookbook §497; SETUP row.
2026-09-04 23:24:02 -06:00
Drew T 380ccdc843 feat(phase-32): T1a (1) — resident code subseg split (3 regions, byte-identical 8e17e02f) + jr_isolate_all include-derived provided types (§496)
- jr_isolate_all resident --only func_800D128C: [0x4 c resident] [0x12ec c resident_jr_800D00E4]
  [0x2494 c resident_jr_800D128C]; the banked jr func_800D00E4's .rodata carve + JTBL_PADS + --order
  repointed to resident_jr_800D00E4.o (config/overlays.mk resident block only, R60); make extract +
  make build BINARY=resident -j8 rc 0, sha 8e17e02ff8954d07c979449198f7e1645046b353 == check (R53)
- TOOL FIX (R43/R33): the carried-type test consulted _engine_types() (engine_types.h + common.h) for
  every TU, assuming each region includes engine_core.h; the resident includes only common.h, so its
  file-local `typedef struct {...} CdFileLoc;` (a name engine_types.h also defines) was silently NOT
  carried -> `parse error before cdFileLocTable` in both region TUs, build rc 2 while the stale binary
  on disk read green. Now _provided_types(header) derives the set from the TU's own #include lines
  (engine_core.h => engine_types.h + common.h, never engine_core's macro-internal typedefs; common.h
  => common.h) and _file_scope_decls(items, provided) uses it at both decision points. R39 controls:
  overlay header == legacy set (1,197 names); resident set lacks CdFileLoc. cookbook §496; SETUP row
- rtu_match func_800D128C --split resident_jr_800D128C: MATCH (243 ins) on the stored S71 draft;
  the gate is the next commit
2026-09-04 23:20:04 -06:00
Drew T 77df1092e2 docs(phase-31): post-close bank — accelerators.md S80 (five: loop tools must prove they iterated; the byte gate is a null oracle for 'is this C?'; a pointer-only callee's extern is unconstrained; banked-but-not-merged printed as success; Agent-tool drafters outlive the session) + wave-playbook S80 (parallel_gate's exit-2 guard and recovery route in the gate section; the one-agent-per-function shape + agent_verdicts addendum) 2026-09-04 22:36:55 -06:00
Drew T 3c292ef097 docs(phase-31): S80 — docs/frontier-p32.md, the Phase-32 jumping-off document: the last 21 functions by blocker (each with its instrument's verdict, mechanism citation, best-draft path and route — the two NON-CONTIGUOUS carves dry-run/refusal detail, the RELOC-ONLY twin, the leading-island case, the 8 pinned walls, the 3 near plateaus, the 7 far drafts), the five parked disc payloads, the routes/instruments a fresh session must know, and the proposed Phase-32 shape with its kill gate 2026-09-04 22:20:20 -06:00
Drew T 452975e852 docs(phase-31): S80 #10 CLOSE — the verbatim end-state: manifest 6 → 5 rows (the five PERMANENT rows RATIFIED in _README; the GAME-C row decompiled), cookbook §495 (two def-side declaration walls, the S79 assembly "bank" P9 correction, the gate that dropped a bank on exit 0), decision-log S80 addendum (R31), SETUP rows; tools/parallel_gate.py: banked-but-not-merged now exits 2 with the worker's raw git status kept + per-run .run/pgate_runs/<ts>.json; CURRENT_PHASE #10 bullet + the S80 #10 CLOSE checkpoint (R22 213/213, tools-health OK, census 21 stubs / 4,554 ins, NEXT #11 = PhaseEnd, gate 2); regenerated digests 2026-09-04 22:07:35 -06:00
Drew T 846c6d5891 docs(phase-31): S80 #9 CLOSE checkpoint — task #9 DONE (ten banks; open stubs 31 → 21; main REAL 777 / stubs 12 / game-code 95.1%; fleet instr 100.0%, 213/213 R22, tools-health OK); the frontier census regenerated (21 = 4 B-CARVE + 10 D-NEAR + 7 F-FAR, 4,554 ins); NEXT #10 with its design brief (main() is already C, the -O0 cluster is spent — #10 = ratify the 5 PERMANENT verbatims + decompile ov_SC03_107:func_8017D878); regenerated digests 2026-09-04 21:41:17 -06:00
Drew T 09e0b27811 docs(phase-31): S80 #9c — the S79 drafting task's NEAR/WALL ledger: 15 rows logged to the backlog (each with the residual's gcc mechanism), the ≤3 residuals pinned as WALL candidates in config/wave_exclude.txt after an 8-seed permuter_ils sweep on the now-permutable pinned seeds (no score-0; func_80039DEC 9→2 = the K&R raw-preserve register, func_80023BF0 18→11 ADDRESSING, func_8017DF28's "1" was a divergent store rewrite — closeness stays 2, R14); cookbook §494 v2 (ten banks, the Opus verdicts' idioms: P_TAG bitfield store, inverted arms, sibling-reading, the 518-ins spelling laws, gdb-on-cc1 allocno arithmetic, K&R s16 params, true_dependence, field-boundary fences, extendhisi2 orphans, [][1] decls) + the final ledger; .run/S79w allowlisted (27 drafts + 3 permuter waypoints + verdict ledger + briefs, 264 KB — R20) 2026-09-04 21:21:05 -06:00
Drew T 7fbdb8fd63 fix(phase-31): S80 #9c — the permuter could not permute a PINNED seed, and it was our instrument: hide_asm carried only the __asm__ spelling (3 S79 seeds use asm("$7")), permuter_ils warm-restarted from the DECODED waypoint (raw pins back in base.c → cycles 2..N were silent parser refusals reported "(unchanged)"), and defines_fn refused K&R-style definitions (436 stored backlog drafts kept out of the lane for four phases). Fixed + R39-controlled over 5,311 drafts (the bare word asm in INCLUDE_ASM path strings was a caught false positive): re-hide every waypoint, assert the definition survived, abort exit-2 on a refusal (R61a), flushed logs (R55). Every S79 pinned seed now iterates; ov_SC06_022:func_8017DF28 (pinned WALL, closeness 2) reached 1 in its first cycle. cookbook §493 S80 correction + §494 v1 (S79 idioms); SETUP rows (p16_permute/permuter_ils, agent_verdicts.py) 2026-09-04 20:59:35 -06:00
Drew T 2709321082 docs(phase-31): S79 HANDOFF checkpoint mid-task #9 — 7 banks this task (open stubs 51 -> 25 this session), plateaus with residuals named, 11 drafting agents still running; tools/agent_verdicts.py extracts their final JSON verdicts from the subagent transcripts for the fresh session to aggregate (procedure + paths in the 🛑 block) 2026-09-04 19:50:01 -06:00
Drew T a0139c31c8 docs(phase-31): S79 #8 close — cookbook §493 (the permuter route end-to-end; the D-NEAR ledger), p16_permute surfaces the permuter's parser refusals, SETUP row, census 31, report, checkpoint (task #9 brief)
Stubs 32 -> 31 after the func_80015760 bank (commit:3877); R22 fleet 213/213 (.run/S79_check_all_8.log);
main game-code 93.5% (38,854 / 41,534). Permuter ILS plateaus recorded with their residual named:
func_80015608 best 1, func_80039B20 best 7, func_80038698 pinned seed refused (11). The ILS runner
had reported "no waypoint" for 8 cycles in 20 s on a seed the permuter's C parser rejects; it now
prints [permuter] REFUSED and leaves PERMUTER_REFUSED.txt (positive-controlled on func_80038698).
2026-09-04 18:50:20 -06:00
Drew T 80ddd40d23 docs(phase-31): S79 #7 close — cookbook §492 (plumbing was three things: a raw-splice bank, an -O0 checker flag, two R48 same-name phantoms), census 32, report, backlog ledger, checkpoint (task #8 brief); func_80011380 pinned as the §474 proved wall
Stubs 35 -> 32 after the #7 banks (commit:3873 commit:3874); R22 fleet 213/213 (.run/S79_check_all_7.log).
ov_SC05_018:func_80180BE0 and ov_SC06_010:func_801809E4 have NO draft: their ledger drafts were other
overlays' same-named functions (.run/backlog_drafts/<fn>.c is keyed by bare fn name) -> drafting pool.
config/wave_exclude.txt: main:func_80011380 pinned WALL with the §474 proof (fold-const split_tree +
stupid.c adjacency), 4 entries.
2026-09-04 18:35:38 -06:00
Drew T 595fc9fa49 docs(phase-31): S79 #6 close — cookbook §491 (the mechanical class: a phantom stub, two jtbl twins, one clone; three tool gaps), jtbl_pads_fix regex fix (+positive control), SETUP rows, census 35, checkpoint refreshed (task #7 brief)
Stubs 38 -> 35 after the #6 banks (commit:3868 commit:3869 commit:3870 commit:3871); R22 fleet 213/213
(.run/S79_check_all_6.log); frontier_classify 35 rows (main 16, md_MAIN_003 5, resident 2, ov 12).
jtbl_pads_fix's PAD_ERR_MORE regex carried jtbl_rodata_pads' old wording and reported "no
pad-count drift" over a red build; it now accepts both spellings and, positive-controlled with a
deliberately short spec, reports "emits >4 table(s), spec declares 4". The deferred carves and
their blockers are itemised in §491 and in the checkpoint's task #7 brief.
2026-09-04 18:19:57 -06:00
Drew T 02f060f607 feat(phase-31): S79 #5 — the libpad 4.2.1 + libapi 4.2 band and the apicard region LINKED from real objects: 13 stubs + 4 TUs + the reorder island gone; main 16 stubs, fleet 38
800c3 (0x8005CE18-0x8005FC68, one contiguous run of 33 interleaved Sony objects) is now four
stub rows — libapi1 (21 BIOS trampolines + COUNTER), libpad1 (PADENTRY + PADMAIN 760), libapi2
(L02/L03), libpad2 (PADCMD PADIF PADPORTD PADSEQD WAITRC2) — fed by two WINDOWED psyq_integrate
calls from the raw .run/obj42/{libapi42,libpad421} dirs (integrate tiles each stub with one
library; every boundary checked against .text SECTION sizes). The apicard region's three
"game code" rows were libapi 4.2's C objects to the byte: 800c2 = FIRST.o (firstfile + the
"no jump table wall" stub func_80062144), 800c2_2 = PAD.o, 800c2_3 = PATCH.o + CHCLRPAD.o ->
apicard5/6/7; make_apicard_used.py sources libapi from 4.2 (the EXE's real libapi; libcard
stays 4.0) into .run/obj42/apicard_used, 26 objects / 7 blocks, no game code left in
0x80061F38-0x80062888. src/800c3.c (129 hand-matched "C", 62 verbatim bodies, 19 stubs incl.
the four §332 %lo-in-a-delay-slot "walls"), src/800c2.c, src/800c2_2.c, src/800c2_3.c removed;
REORDER_TUS is empty (mechanism kept). Cookbook §490.

Two stale instruments fixed: exclude_audit let a pinned WALL outrank LINKED (PopMatrix/
PushMatrix had sat as walls since S68 while living in libgte3, linked since Phase 8) — LINKED
dominates now, config/wave_exclude.txt 13 -> 3; frontier_classify carried a hard-coded 49-name
LINKED set (R51) and reported 337 "stubs" — derived from the Makefile now.

Verified: main 143dbb89f34491258bbc27810d0a12ec8b43a8dd WITH all SDK dirs and WITHOUT them from
a fresh extract; make tools-health OK; R22 fleet extract-all 212/212 + check-all 213/213.
Metrics: main REAL 839->773, LINKED 1,150->1,256, VERBATIM 29->3, stubs 29->16, byte-identical
2,075/2,091 = 99.2%; game-code weighted 93.3% (38,748/41,534), remainder 2,786 = the open-stub
sum; fleet stubs 51->38 (frontier_classify: 39 rows incl. the data word). Verbatim manifest
33 -> 6. Docs: worklist rows + "S79 task #5", SETUP (fresh-clone obj42 commands, Makefile
blocks, exclude_audit), decision-log "S79 addendum 2", accelerators "S79 (2)", CURRENT_PHASE
S79 FINAL refreshed (census, metrics, the task #6 brief).
2026-09-04 17:56:31 -06:00
Drew T 58996ca4f7 feat(phase-31): S79 #13 — FOUND the EXE's libpad 4.2.1 + libapi 4.2 (PsyQ RTL 4.2 archive + the J421PD patch): 46/46 band objects link byte-identical
The bounded hunt succeeded on its first lead. archive.org item
`play-station-programmer-tool-runtime-library-version-4.2.7z` (383 KB) is the PsyQ Runtime
Library 4.2 (LIB/*.LIB + INCLUDE, 1998-01-21) plus LIB/42PATCH/J421PD.ZIP — SCE R&D's
1998-02-26 "Libpad.lib version 4.2.1 for the Analog Controller (DUAL SHOCK)" patch, shipping
LIBPAD.LIB 4.2.1 with LIBAPI.LIB 4.2 and LIBPAD.H/LIBAPI.H/KERNEL.H.

Placed and byte-verified against the EXE (psyq_identify 0x8005CE18-0x800629DC, then
psyq_link.py per object): libpad 4.2.1 7/11 — PADENTRY, PADMAIN (760 ins, the 4.2.1 build,
exact), PADCMD, PADIF, PADPORTD, PADSEQD, WAITRC2 — and libapi 4.2 39/88 — the 21 band
trampolines, COUNTER, L02/L03, and the apicard-region C112/A50/A51/A54/A65/A67/A69/FIRST/A66/
PAD/A18-21/PATCH/CHCLRPAD. All 46 PASS. Neighbours for the record: plain libpad 4.2 and the
4.3 disc (DTL-S2340, 1998-05-18; PADMAIN 832 / PADIF 380 / PADSEQD 292) each place only 4;
4.2.1 is the unique exact match, so the game was built between Feb and May 1998.

Banked (R20): the 7z tracked under tools/psyq/ with sha256 + provenance in CHECKSUMS.sha256;
extracted to gitignored tools/psyq/lib42/ and lib421/ (the 4.2.1 headers are the band's
prototype oracle from now on); ELF in .run/obj42/{libpad421,libapi42}. Docs: psyq-worklist
"S79 task #13", SETUP archive table + §5.1 + S79 tool table, CURRENT_PHASE (#13 log; the S79
FINAL block's §5 records the archive and §6 is the re-scoped task #5 brief: link the whole
0x8005CE18-0x8005FC68 band and re-source the apicard region's libapi from 4.2).
2026-09-04 17:36:03 -06:00
Drew T 757bd82a0f feat(phase-31): S79 #4 — scattered-.bss split at link-prepare (psyq_bss_split): SYS.o→libgpu2, VM_F.o→snd12, GS_001.o→libgs8 LINKED; libgpu_used retired
The §9.1 "scattered .bss commons" exclusion class (Phase 8 → P31) is closed 3/3. New
tools/psyq_bss_split.py (own ELF32 REL reader/writer) cuts an object's packed .bss into
per-base NOBITS pieces: bases derived from the game bytes per HI16/LO16 pair, references
walked in offset order into single-base runs, cuts snapped to symbol starts (the linker
scattered SYMBOLS), symbols moved, a LOCAL section symbol per piece inserted, relocs
retargeted with the addend rewritten in the immediates, self-diffed. It runs inside the one
prepare step shared by psyq_link.link_object / psyq_link_region.build_region /
psyq_integrate.integrate (prepare_object before classify), re-derived every build.

GS_001.o was certified "5 interleaved bases, NOT splittable" by the S77 probe, which grouped
by BASE; by RUN it is six symbol-aligned pieces. All seven cuts across the three objects are
confirmed by the other objects' by-name recoveries (_que 0x800C5510, _svm_sreg_buf
0x800B9B58, PSDBASEX/CLIP2/PSDBASEY/POSITION/GsDRAWENV). R39 negative control: 235 placed
objects across 9 curated dirs, 0 refusals, exactly 3 splits (a libcd .bss+size end pointer
refused the first build → reference problems are fatal only when a split is needed).

Wiring: yaml 800c→libgpu2, sgap_6→sgap_6+snd12, gsgap3→libgs8 (comments rewritten);
LIBGPU_ELF := .run/obj40/libgpu (curated libgpu_used retired); libgs 34 objs/8 blocks
(make_libgs.sh +GS_001); snd 63/12 (make_snd_used.py exclusions 4→3). src/800c.c and
src/gsgap3.c removed (Sony code hand-matched as REAL/verbatim), sgap_6.c keeps only
func_8003FA54; splat-emitted libgpu2.c/libgs8.c/snd12.c stubs for the no-SDK fallback.

Verified: main 143dbb89f34491258bbc27810d0a12ec8b43a8dd WITH the SDK objects and WITHOUT
them from a fresh extract; make tools-health OK; R22 fleet clean extract-all 212/212 +
check-all 213/213. Metrics: main REAL 886→839, LINKED 1,040→1,150, VERBATIM 85→29, stubs 29
(unchanged); game-code weighted 91.1% (40,895/44,870) — both terms lost the 3,667 SDK ins;
the remainder is still exactly the 3,975-ins open-stub sum. Verbatim manifest --update
200→33 rows (subtractive). Docs: cookbook §489 (+index), psyq-worklist rows + "S78 task #4",
SETUP S79 R21 table, decision-log S79 addendum, accelerators S79, CURRENT_PHASE S79 FINAL 🛑.
2026-09-04 17:19:29 -06:00
Drew T a85733a487 feat(phase-31): S78 #3 — 13 "game code" subsegs were PsyQ objects: wired LINKED (libgte 70/30, libgs 33/7, snd 62/11); main's game-code metric corrected to 91.8%
- exact tiles, 0 tokens: libgte23-26 (MSC01/02/05/09, SMP_00, FGO_01-06, PATCHGTE), libgte9 re-derived
  as SMP_05 NormalClip (SMP_06 NormalClipS = nested sub-pattern; psyq_integrate now drops nested
  placements), libgte27-30 (the libgs-gap MTX_05/07/11, REG03+REG11), libgs7 (2D_BG0+2D_BG1), snd10
  (VM_NO1), snd11 (VM_NOWON carved off sgap_8). LINKED 959->1040, REAL 912->886 (SDK inline-asm wrappers
  re-provenanced), VERBATIM 146->85, 13 TUs deleted; splat re-emits the stub records.
- main 143dbb89 WITH and WITHOUT the SDK objects. The no-SDK fallback had been red since S7x
  (CdReadyCallback called by its SDK name while the libcd stub carried func_800435B4) — curated
  CdReadyCallback = 0x800435B4, refs unified. R22 clean fleet 213/213; tools-health OK.
- METRIC CORRECTION (R35): progress.py's "MAIN game-code weighted" sig never excluded the LINKED
  objects (its comment said it did) — ~31k linked-SDK ins sat in the denominator as unmatched game
  code. Exclusion now derived LIVE from the Makefile stub lists + yaml ranges: 91.8% (44,562/48,537),
  not 59.8%; the 3,975-ins remainder equals the open-stub sum exactly.
- VM_F.o probed SPLITTABLE at .bss 0x50c (SYS.o's class -> task #4). cookbook §488; worklist S78 #3;
  decision-log + accelerators; SETUP rows.
2026-09-04 16:26:12 -06:00
Drew T b212f40f19 chore(psyq): bank the PsyQ 4.6 library zip + 4.5 toolkit zip (R20 hard-to-source SDK material; sha256 in CHECKSUMS); lib46/ is derived (ignored); progress.md regenerated 2026-09-04 15:58:09 -06:00
Drew T a7394f44dc feat(phase-31): S78 #12 — the 800c3 "wall" band is LIBPAD 4.2.1 + LIBAPI 4.2: 46 names applied; integrate wired by subseg range; renames via ApplySymbols
- provenance: the psx loader's per-version PsyQ signature sets place PADENTRY/PADCMD/PADPORTD/
  PADSEQD (4.2), WAITRC2 (4.3), COUNTER/C114/FIRST/PAD/PATCH/CHCLRPAD (libapi 4.2) byte-exact in
  0x8005CE48-0x8005FC68 / 800c2 -> 12 of main's 29 stubs incl. all four §332 walls are Sony's
  DualShock library in reorder mode. 46 names -> symbols.us.txt (count 1081), band TUs, verbatim
  manifest, wave_exclude; firstfile/firstfile2 (4.2 naming); CdGetToc @0x800430B8 (was the Phase-21
  xdedup mislabel DecDCToutCallback). SETUP §5.1 corrected; psyq-worklist S78; cookbook §487;
  decision-log + accelerators S78; CHECKSUMS +Psy-Q_46.zip +PSYQ_SDevTC_v4.5.zip.
- psyq_integrate: --yaml maps stub<->objects by SUBSEG RANGE with an exact-tiling check and PRINTS
  the located-but-unwired residue (libgte: 13 objs / 1,264 ins) — main's LINKED build had been RED
  at HEAD since the S77 psyq_identify fix (22 libgte blocks merged to 3; gate worktrees take the
  stub fallback so it never showed); a library object's exported symbol whose recovered address the
  curated file names differently is --redefine-sym'd (R15; A66 firstfile->firstfile2).
- Ghidra: 47 MCP renames did NOT persist through the sentinel stop (R9 caught it) -> NEW
  tools/ghidra_scripts/ApplySymbols.java + tools/ghidra_apply_symbols.sh mirror the curated file
  headless with a real save: 73 renamed, R9-verified x4. SETUP inventory rows (R21).
- lint_symbol_refs: scans verbatim __asm__ bodies (`.ent\tfunc_X` is invisible to \b and to the
  string-masked scan); negative-controlled (red on the pre-fix TUs, green on the passing tree).
- R22: clean extract-all 212/212 + check-all green on the final config; main rebuilt byte-identical
  143dbb89 after the last src-only fix -> 213/213; tools-health OK.
2026-09-04 15:57:06 -06:00
Drew T c9454db4a4 docs: refresh progress.md from the tools-health report run 2026-09-03 22:57:49 -06:00
Drew T f55fd10dca docs: regenerate the cookbook index for §486 2026-09-03 22:51:35 -06:00
Drew T 375507834c docs(progress): main's R34 caveat is retired — its boundaries are independently verified now
The fleet report still printed 'caveat is R34: no independent second oracle for
a PS-X EXE'. That was true until this session; make sig-main-oracle +
audit-corpus now cover main at 0 phantom / 0 truncated / 1 explained pad-tail.
A stale caveat is the same class of false statement as a stale wall verdict.
2026-09-03 22:50:43 -06:00
Drew T 65c831b1cc docs(accelerators): S77 — three accelerators, all 'make the tool state its own denominator' 2026-09-03 22:49:18 -06:00
Drew T ddbe7f455c docs(R31): S77 decision-log — the frontier is wall-proof work now, and R61's twelve defects
Also: cookbook §486 (the main -O0 island carve, five coupled pieces), SETUP rows
for psyq_bss_probe and make sig-main-oracle (R21).
2026-09-03 22:48:58 -06:00
Drew T 09de46fef3 docs: regenerate the cookbook index for §481-§485 2026-09-03 22:45:35 -06:00
Drew T b05085b67a docs(cookbook): §485 the placement map was parsing a pretty-printer — 25 objects invisible, not absent 2026-09-03 22:37:18 -06:00
Drew T 5399845172 feat(psyq_bss_probe): a Phase-8 link exclusion re-derived from the bytes — 3 of 4 objects are not blocked as recorded
The yaml has excluded SYS.o/GS_001.o/2D_BG0.o/VM_NO1.o from the LINKED build
since Phase 8 for 'scattered-.bss commons ... no single NOLOAD base reproduces
it'. Every word of that is true, and it does not imply unlinkable.

psyq_bss_probe derives each object's .bss bases FROM THE BYTES (for each
HI16/LO16 pair against the bare .bss section, the object's immediates give the
addend and the game's give the resolved address, so base = resolved - addend)
and then asks the unasked question: are the offset ranges DISJOINT?

  SYS.o     3,109 ins  2 bases  0x0000-0x0044 @ 0x80078830
                                0x0148-0x0150 @ 0x800c53cc  -> SPLITTABLE at 0x148
  GS_001.o    384 ins  5 bases  interleaved                 -> the genuine wall
  2D_BG0.o    526 ins  NO .bss                              -> reason cannot apply
  VM_NO1.o    305 ins  NO .bss                              -> reason cannot apply

§9.2's escape (weaken the .bss symbol, --defsym it) really cannot reach these —
a relocation against the bare SECTION has no name to defsym — and that is what
made 'unlinkable' look like the conclusion. But a section reference only needs
the section PLACED, and a section can be split.

Completeness checked before believing it (R32): the probe counts .bss refs from
EVERY section; SYS.o's .data has zero, so the two-way split covers every
reference. Placement is derived, not configured — the object is located by
masking relocated fields and requiring a UNIQUE match, which independently
reproduced SYS.o @ 0x80059234 / 3,109 ins, agreeing with both the yaml subseg
bounds and the manifest's psyq_identify count.

Incidental: src/800c.c is 100% SYS.o (its span is exactly the object's .text
size), despite the subseg comment calling it '-O2 game code'.

Cookbook §484; yaml comment corrected in the same change.
2026-09-03 22:07:31 -06:00
Drew T 867f09221c feat(oracle): main gets its independent second oracle — contract §1.3 closed
The roadmap's completion contract requires both audit oracles green before any
100% claim on main, and main had none: audit-corpus covered overlays and
resident only, and R34 is explicit that the byte gate is a perfect CORRECTNESS
oracle and a NULL COVERAGE oracle — green whether a function was sliced right
or invented, because the .s pieces paste back either way.

sig_image gains multi-range signing, closing all three blockers
docs/second-oracle.md scoped:
  * the 0x800 PS-X EXE header -> --vram-base 0x8000F800 puts file offset 0 at
    vram, so the header falls below the first range
  * interleaved data + linked islands -> --segments derives 28 game-code ranges
    from the splat yaml's SEGMENT rows
  * one text range -> the signer loops ranges, bootstrapping INSIDE each, which
    is what stops the linear partition running through a data island and minting
    functions out of it (the detector manufacturing the class it detects)

INDEPENDENCE IS PRESERVED, NOT WORKED AROUND. Ranges come from segment TYPES,
never from splat's function boundaries; entries are still found by byte-derived
jal-closure. Seeding from splat's symbols would make every phantom look real —
the trap the design doc names. .run/sig.main.jsonl (the splat-SEEDED atlas sig)
is a different file and corpus.ORACLE_SIG keeps the audit off it.

RESULT: 986 functions signed. main audit = 0 PHANTOM, 0 TRUNCATED, 1 PAD-TAIL.
Fleet audit-corpus = 0 + 0, unchanged for resident and overlays.

NEW AUDIT CLASS, from the first real finding. func_80062144: splat .s 65 ins,
oracle 64 — the extra line is a nop one line BELOW endlabel. That is an
alignment pad the matching side already emits from C (§295; two S77 wave agents
did it on func_8005E13C and func_8005D538), not a mis-slice. Lumping it with
TRUNCATED would make the oracle's first finding look like a defect and bury the
class that is one.

COVERAGE ASSERTED both ways before trusting it (R32): all 30 game-code stubs
fall inside a range, and 0 of 199 addr-parseable LINKED stubs do.
2026-09-03 21:58:17 -06:00
Drew T 4a0f9a3049 docs: regenerate the cookbook index for §477-§483
tools-health caught this red: seven sections added this session without
regenerating the index. Exactly the sibling-update the health gate exists to
enforce.
2026-09-03 21:16:24 -06:00
Drew T 46097c2339 feat(permuter_sweep): hand a wave's NEARs to the permuter, and correct §479 a second time
THE GAP: a drafting agent is briefed to STOP at a plateaued permuter-class
residual — right, since an agent grinding a register permutation burns tokens
for nothing — so every SCHEDULE-REORDER/DELAY-SLOT/REGALLOC-PERM residual lands
unattempted while the local permuter costs no tokens. In S77 the hand-off
happened only when I remembered.

THE CORRECTION THIS TOOL FORCED. §479 v2 claimed the predictor of a permuter win
was 'prior-attempt history: all 3 winners were drafts nobody had worked'.
Building the selector on that claim refuted it immediately: journal_notes
reports prior attempts for ALL EIGHT known runs, winners included (2, 3, 3).
What I had eyeballed was the DRAFT HEADER narrative, a different corpus — the
winners came from a recovery pile whose files carry no header journal. That is
provenance, not evidence.

So the tool selects on the two NECESSARY conditions only (small residual, a
match_one class the permuter can search), prints prior-attempt counts as
information, and puts the unvalidated filter behind --skip-ground, off by
default so it cannot silently discard good work (R39).

AND A BUG IN THE NEW TOOL, caught by cross-checking against known-true numbers:
wave_results globbed journals across EVERY session and did last-write-wins on a
bare function name, so an older wave's row won and carried its stale
draft_path — the sweep reported func_8002AC98 at closeness 73 and func_80015608
at 65 while both drafts measure 1 and 3. R48 inside a brand-new tool. Journals
are now read newest-last and rows are kept only when the draft lives under this
wave's directory. After the fix all seven cross-checkable residuals agree with
what the agents independently reported (9, 8, 7, 3, 3, 1, 1).

§479 now states the honest position: ~3 in 8 at <=4, no validated predictor, and
a note that a yield table is evidence while a story about why is a hypothesis
needing its own negative control before it goes in the cookbook.
2026-09-03 21:09:59 -06:00
Drew T ec258ff75a feat(recover_route): route a gate DROP to the tool that applies, and wire it into gate_main
gate_main printed ONE recovery chain for every dropped draft, and it was the
SELF chain (fix_arity_callers --any-proto + cast_self_callers) regardless of
what the clashing symbol actually was. Two of the three classes are not that
chain:

  CALLEE — §378 does not transfer; cast_self_callers reads the return type off
           the draft and cannot cast a callee, so --any-proto runs unprotected
           over every call site. S69 measured 60 decls no-protoed, binary RED.
  DATA   — neither tool in the printed chain touches a data extern at all.

Measured cost of the wrong route THIS session: func_8006252C was dropped on a
clash with itself; following the shape of the printed chain I reached for
scope_demote_drafts first, which aliased D_80078D08 through __asm__ and BROKE
the build. The real blocker was one --sync-decls away. Three tools, wrong
order, one destructive — because the report named a chain instead of a route.

A route is an ORDERED LADDER, not a prediction: for a DATA clash the choice
between adopting the TU's spelling and demoting to block scope depends on
whether the draft can live with the TU's type, which no classifier can know.
The byte gate remains the sole arbiter (G3/P9). Refusals come first (R43/R61a):
a verbatim draft and a NEAR are not declaration problems.

NEGATIVE CONTROL (R39): all 7 S77 drops whose winning tool was already known
route correctly — 2 SELF (cast_self_callers), 1 CALLEE (sync_tu_decls via a
definition header), 4 DATA — and the DATA ladder's order matches which rung
actually won in each case (sync for D_80072978, demote for D_80072960 and
D_80074818). Verbatim draft refused; real-C draft not refused.

Playbook §4b and SETUP updated in the same change.
2026-09-03 21:05:50 -06:00
Drew T bfc0f43c92 docs(phase-31): S77 CLOSE — 30 banked, main 57.1%->59.4%, ten instrument defects, R61
S77w wave: 30 workflows, 30/30 reported, 9 banked, 21 NEAR, 0 errors.
R22 clean-fleet 213/213 (fourth run this session). Cookbook §477-§483.
2026-09-03 20:52:15 -06:00
Drew T 984b50215f docs(cookbook): §483 the S77w wave harvest — six levers, four from banked bodies 2026-09-03 20:46:54 -06:00
Drew T 3b959596f6 docs(cookbook): correct §479's yield curve — the permuter is 3/8 at <=4, not 3/3
The first version of §479, written earlier this session on 3 data points, said
the permuter is a one-shot at <=4 mismatched. Five more runs make it 3 of 8,
and the failures are not marginal: a residual of 1 failed while a residual of 4
banked, so mismatch count predicts nothing.

The real predictor is prior-attempt history. All three winners were drafts
nobody had worked. Every failure was a body an agent or prior wave had already
optimised (5, 6 and 4 prior levers respectively). A draft a competent search has
plateaued is plateaued for the permuter too — its wins come from unexplored
neighbourhoods, not from small numbers.

Same predictor as §479's triage paragraph, reached from the opposite direction.
2026-09-03 20:43:32 -06:00
Drew T f7702eac69 docs(cookbook): §482 two independent re-ties, ordered — a re-tie is a scheduling barrier with a position 2026-09-03 20:31:47 -06:00
Drew T 9df0cd29dd docs(cookbook): §481 conflicting types is a SAME-SCOPE error; across scopes it degrades to a warning
The escape hatch for the declaration-conflict class the reconcile/sync ladder
cannot reach — two anonymous struct typedefs in one TU are never compatible in
C89, so no duplicate spelling works, but block scope turns the error into the
warning the build already emits elsewhere. From main:func_8001FC08 (400 ins),
whose body was solved in S76 and had never banked because nobody asked why.
2026-09-03 20:17:57 -06:00
Drew T f9f446449e feat(claude_wave_packs): wire neighbor_ref into every pack, and resolve its names to the source spelling
playbook §2b has called neighbor_ref the biggest measured cost lever in the
wave since S68 (~20x token swing) and documented it as a MANUAL per-card
command wired into nothing — so it ran for approximately zero cards. Packs now
carry an ALREADY-MATCHED NEIGHBOURS block, same additive never-fail contract as
the past-attempt notes. First run: 30/30 targets had a matched neighbour.

It also shipped with a defect that would have silently un-done it:
neighbor_ref reports the SYMBOL-TABLE name, and for an unnamed function that is
Ghidra's FUN_8003a0e4 — which appears nowhere in src/*.c, where the function is
func_8003A0E4. An agent sent to read FUN_8003a0e4 finds nothing and concludes
there is no neighbour. _src_name resolves against the destination TU's own text,
falls back to the address, and shows the symbol-table spelling in parentheses.
Measured: 150 of 150 neighbour names needed resolving; 0 primary names remain
Ghidra-style. Checked against known-true cases first (resolves FUN_8003a0e4,
leaves func_8003A0E4 alone, leaves an unknown name untouched).

R61(b): the pack was asserting a name true of the symbol table and false of the
world the agent works in.
2026-09-03 20:08:27 -06:00
Drew T 9d15598b5a docs(phase-31): S77 FINAL checkpoint — 21 banked, self_decl_tu closed, the permuter yield curve, eight instrument defects 2026-09-03 19:51:02 -06:00
Drew T be966bf095 docs(cookbook): §479 the permuter's measured yield curve (one-shot at <=4, plateau above ~10); §480 a static blocker class the real pipeline removes is a phantom 2026-09-03 19:45:55 -06:00
Drew T b5751c7c1e docs(phase-31): S77 checkpoint — 17 banked, the self_decl_tu lane closed, six instrument defects
T11 4/7, T12 13 banked of a 34-draft pool, T13 R22 213/213 twice (a green
baseline before the overlay banks and again after all 17).

main REAL 895 -> 899, stubs 46 -> 42. Fleet stubs 82 -> 65, distinct-code
99.3% -> 99.4%, MAIN game-code 57.1% -> 57.3%.
2026-09-03 19:25:02 -06:00
Drew T c61c7ed93f docs(cookbook): §477 the self_decl_tu lane is mechanical (16/16 banked); §478 a verbatim draft is the strongest false signal a scoper can emit 2026-09-03 19:19:29 -06:00
Drew T e0229af908 docs: restore §462/§463, record S76 tooling in SETUP, add the gate-triage step to the playbook
Three gaps found by auditing instead of asserting.

§462 and §463 were MISSING from the cookbook although their commits are
ancestors of HEAD and added 37 and 34 lines. Same silent loss as §464, which
I caught only because I happened to re-check the three sections I had just
written. Both restored from their own commits; all of §460-§476 now verified
present one by one.

SETUP.md had no record of either new tool (R21). Added gate_main_parallel and
sync_tu_decls, plus the oracle corrections a reader needs in order to
re-judge older verdicts: the REORDER_TUS routing in match_one/rtu_match, the
draw_waves --main no-op, the verbatim-draft refusals at three points, and the
§179-C conversion guard.

The playbook had nothing on what to do when a gate banks far less than it
staged — which is exactly what happened this session. Added the triage step:
probe first (CC1-FAIL 16 / DIFF 18 / MATCH 6 on main's 40), sync declarations
for the plumbing class, hand self_decl_tu to cast_self_callers, and expect a
cascade because every bank changes the declaration environment for the drafts
that follow it.
2026-09-03 17:41:43 -06:00
Drew T 920f8bac35 docs(cookbook): §476 — a hard-register pin strips nonzero_bits and reg_n_sets==1
From the S76 Fable agent on func_800226C0 — 670 instructions, the largest
function in the project, matched at closeness 0.

Explains WHY pins so often hurt, completing the arc of §461/§462/§471:

  (a) A pinned hard register carries no nonzero_bits, so combine cannot fold
      sext(HImode t) into a copy — which is exactly what the target's 228E4
      addu/beqz/addu chain is, with cse2 reusing it as the loop multiplier.
      The $18 pin that looked obvious was what prevented the fold; one plain
      uninitialised s16 t (mul left an unpinned pseudo) unlocked it.
  (b) A pin makes reg_n_sets != 1, so birthing_insn_p refuses the §199-A
      boost and the value is placed first — a whole-block schedule shift.
      Unpinning o/col/sh23/abr fixed the prologue order and two ties.

Rule: if a residual involves a sign/zero-extend fold or a first-in-block
placement, REMOVE pins before adding them.
2026-09-03 16:29:55 -06:00
Drew T 3db8b2b117 docs(cookbook): §475 — the "memory" fence as a cse invalidator; (b*3)<<3 over b*24
From the S76 func_8002FF0C agent (166 ins -> MATCH, verified in-TU with a
spliced src/800_b.c compiling rc=0 and all 63 relocs matching).

__asm__ __volatile__("" ::: "memory") is a CSE MEMORY-TABLE invalidator, not
only a scheduling fence, and the colon-less __asm__("") does NOT substitute:
it forces D_800A46D2 to be re-read rather than folded to sign_extend(r), and
without it the function is exactly two instructions short. Pairs with §464
lever 4 — same two spellings, register half there, memory half here.

Write (b*3)<<3, not b*24: expand_mult never honours its target, so b*24
leaves a move copy that survives into the join block and costs a sixth
callee-saved register plus a 0x30 frame. A top-level LSHIFT_EXPR expands into
the variable's own pseudo. General for any constant multiply factoring as
odd<<n.

Independently confirms §470's 'two distinct locals for the same b*24' on a
different function via a different agent — treat as established.

And the house array spelling can be the defect: D_800A46D2 must be scalar at
block scope; extern s16 D_800A46D2[] forces la for both accesses and costs 12
mismatches. A fleet-consensus declaration is a prior, not a law.
2026-09-03 16:21:35 -06:00