mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-04 16:28:11 -04:00
9564314095d5c12304aba7ece47573863ffbfd39
127 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
11f79c1b0a | docs(phase-32): T3 checkpoint — the 31 agents' FULL final reports saved to .run/P32/t3/reports/ (tools/agent_reports.py, NEW) + tools/transcript_dump.py (NEW, the dead-session reader); SETUP rows, playbook addendum-2, 🛑 block §3/§6 point at them | ||
|
|
42ff6116ea |
docs(phase-32): session-start protocol → phase-ends/DIGEST.md + last 3 PhaseEnds (~100k tokens), checkpoint replayed VERBATIM (R64 candidate); the T3 checkpoint refreshed to the verbatim-replay standard
- phase-ends/DIGEST.md (NEW, Drew-directed 2026-09-05): every phase's synopsis (P1–P32), every rule R1–R64 in full, the corrections that supersede parts of PROJECT_CONTEXT.md (P8→R19, commit cadence→R42, H1→R1, headless Ghidra, roadmap v2, effort doctrine, the pinned triple), and the doc map. Maintained at every PhaseEnd (CLAUDE.md Phase Boundary step 3b, P7). - CLAUDE.md Session Start Protocol rewritten: PROJECT_CONTEXT → DIGEST → the THREE most recent PhaseEnds → CURRENT_PHASE (+ cookbook head/newest § + SETUP §5.4 for matching phases); rules transcribed in full from the digest; the 🛑 SESSION CHECKPOINT block reproduced VERBATIM in chat as the session's only in-phase seed. Measured load order ≈55k tokens (was ~150k reading all 32 PhaseEnds). phase-ends/README.md + SETUP §7 pointer updated (R21). - CURRENT_PHASE.md: the T3 🛑 block REFRESHED and SUPERSEDING the 09:30 one — written to be replayed: what happened in the dead session (times, hashes, the overflow, the swept dir), what the successor did, the 44-stub census with every row's state/draft path, the 10 banked with hashes+shas, the 9-step resume order with exact invocations, the file/tool inventory and gotchas, carried context for T4/T5, environment, the plain-English recap; Log entry for the protocol change. - .run/P32/t3/PROMPT_TEMPLATE.md (tracked): the verbatim agent prompts (Haiku / Haiku+twin / Sonnet escalation / Opus / Sonnet) for launching the 17 queued rows under the amended output contract. - memories updated outside the repo: checkpoint-current-phase-before-pause (the verbatim-replay contract; a dead session's checkpoint is written by the successor from the transcripts) and session-start-list-rules-in-full (the ~100k protocol). |
||
|
|
9480c979a0 |
docs(phase-32): T3 CHECKPOINT — the launching coordinator overflowed after bank 9; 22 agent verdicts recovered (20 MATCH / 9 NEAR / 2 FAIL of 31), 11 swept Opus deliverables restored + re-verified, cookbook §500 harvest, playbook §S80 addendum-2, agent_drafts_restore.py
- verdict ledger .run/P32/t3/verdicts.jsonl rebuilt from the 31 T3 transcripts (agent_verdicts.py); every unbanked draft
re-verified with rtu_match in its real TU: 10 MATCH awaiting the gate (main func_80015B6C 120 + func_8002FDE8 73;
md_SC03_054 func_801EF6D8 604 + six jtbls; md_SC03_053 func_801EF734 44 + func_801EF7E4 72; md_MAIN_007
func_800CF148/2BC/EEFC/EF94/068) + func_800CF3B0 leaf-exact behind the TU's void/3-arg decl; 9 NEAR at exact length
(2/6/15/17/27/35/46/49/137), each with its class and inert-lever list
- R48 incident: one agent's `find .run/P32/t3/opus -maxdepth 1 -type f ! -name <mine> -exec mv {} _scratch/` swept 11
sibling deliverables (two MATCHes among them); found in _scratch/, restored to the contract paths, byte-verified;
tools/agent_drafts_restore.py (NEW: transcript replay) as the fallback; .gitignore allowlist for .run/P32/** so the
drafts, ledger and census files are committed (R20)
- harvest (R16/R30): cookbook §500 (10 banked closers, 10 MATCH closers, 9 NEAR classes, two NEW mechanisms — the
pinned-base-vs-pseudo-address alias basin and #line-equalised ASM_OPERANDS for cross_jump — and the wave-process
defects); wave-playbook §S80 addendum-2 (per-function work dirs, JSON-only final message, the 20-agent cap, the
recovery tools); accelerators P32 T3; decision-log P32 S82 (R31); SETUP tooling row (R21); cookbook-index
regenerated; .run/P32/t3/BRIEF.md output contract amended for the 17 queued launches
- CURRENT_PHASE: T3 row IN PROGRESS, Log entry, 🛑 SESSION CHECKPOINT (census 44 stubs / 5,313 ins with every row's
state and draft path, the 9-step resume order, the dead session's read-only T4 pre-read); harness task list rebuilt
- no src/ or config/ change in this commit; no fleet R22 has run since the 10 T3 banks — the resume order starts with one
|
||
|
|
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 | ||
|
|
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). |
||
|
|
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 |
||
|
|
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 |
||
|
|
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. |
||
|
|
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
|
||
|
|
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 | ||
|
|
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)
|
||
|
|
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) | ||
|
|
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). |
||
|
|
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. |
||
|
|
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).
|
||
|
|
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).
|
||
|
|
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 🛑. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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). |
||
|
|
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. |
||
|
|
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.
|
||
|
|
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. |
||
|
|
c05ea15cbe |
feat(tools): asm_in_c.py — 154 game functions are assembly wearing a .c extension
A .c file in src/ looks decompiled. 199 functions are not: they are the target
assembly pasted into a C string literal (§265), byte-identical BY CONSTRUCTION
and completely unexplained. 45 are PsyQ/CRT routines where that is defensible;
154 are GAME CODE, 171 of the 199 in main, the largest being SaveLoadRoutine at
1,165 instructions.
They were invisible because progress.py's classify() matched INCLUDE_ASM,
INCLUDE_RODATA and C definitions, and a file-scope __asm__ block is none of
those -- so each landed in NO bucket, either swallowed by a surrounding
construct or surfacing as the single `UNPLACED (parse hole)` line the tool has
been printing all along.
progress.py gains a VERBATIM __asm__ bodies line: counted byte-identical (it is,
by construction) but NEVER as REAL. main's headline moves 45.88% -> 42.15%.
Nothing regressed and no work was lost -- the denominator was missing 173
functions that are real remaining work.
THE COUNTING LESSON IS THE REUSABLE PART. Counting these by hand went
116 -> 112 -> 108 -> 178 -> 199 across five attempts in one session, every
intermediate number reported confidently. All five errors were one shape, a
pattern narrower than the claim it supported:
* the sources use BOTH ".ent\tNAME\n" and ".ent NAME\n" -- anchoring on either
silently drops every instance of the other;
* a bare ".ent\t" fragment yields a phantom function literally named `t`, six
times, which is the only reason the error was noticed;
* __asm__ appears in 3,182 of 4,224 sources, almost all the §3a barrier, so
counting files or counting __asm__ measures nothing;
* `.globl NAME` + `NAME:` proves EXPORT, not CODE -- the first real run
reported jtbl_80072ED4/EEC/F0C/F24 as four "functions";
* a hand-written SDK name list reported 170 game functions because it did not
know VectorNormalSS / SquareRoot12 / OuterProduct12 are libgte.
So the tool does not trust one regex: THREE independent detectors that must
agree with disagreement reported as a defect (R34 -- that is what caught the
jump tables); SDK-ness DERIVED from the 14 shipped PsyQ archives via nm (2,227
symbols) rather than a list (R33); coverage asserted so a definition-shaped
block no detector claims fails loudly (R32/R43); and --selftest carrying a
known-true case of every spelling plus the phantom `t` and the jtbl regression.
Cookbook §448, SETUP row. Law: when a count comes from a text pattern, the
pattern has a denominator too -- validate it against one known-true case of
every FORM the corpus contains before quoting the number.
|
||
|
|
cf7f837231 |
fix(gate): main's TABLE REJECT verdict was unreachable — SaveLoadRoutine is a CARVE, not plumbing
SaveLoadRoutine (1,165 ins) is the largest open function in the project, 9.2%
of all remaining work, and has been carried as the §434 WALL. Gated alone
through gate_main, with the §376/§378 chain already applied, the verdict layer
says: "SaveLoadRoutine is BYTE-IDENTICAL; all 3989 differing bytes are
ELSEWHERE". The body has been correct the whole time.
What rejects it is where its FOUR jump tables (jtbl_80072ED4/EEC/F0C/F24) land:
.data/.rodata (jump tables) 3,787 bytes 94.9%
.text (perturbed code) 202 bytes 5.1%
and the built image is 4 bytes SHORTER than retail (413,692 vs 413,696) --
§446's first diagnostic, firing on a function §446 was not written about.
main_diff_locate.classify() already HAD a TABLE REJECT class, added in S72 under
a docstring reading "THE THIRD CLASS EXISTS BECAUSE THE FIRST TWO MISLABELLED
IT". It could not fire here for two independent reasons:
* it keyed on the literal string `(.rodata)`, but main's section_order is
[.rodata, .text, .data, .bss] -- its rodata sits BELOW .text and its jump
tables live in `.data` objects, so TABLE REJECT was UNREACHABLE BY
CONSTRUCTION on the binary with the most jump-table functions left. A
section NAME is not a section ROLE.
* it demanded purity (ro == outside), so 5% perturbed code defeated an
all-or-nothing test and dropped the verdict through to PLUMBING REJECT --
whose advice (fix_arity_callers -> cast_self_callers) addresses the 5% and
cannot touch the 95% that is data. That chain was run on this function
TWICE today and fixed nothing, exactly as the evidence predicts.
Now: table bytes counted in (.data) OR (.rodata), and the test is DOMINANCE
(>=60%) rather than purity, reporting the split and naming which part is the
carve problem and which the declaration problem.
Negative control over all five pre-existing verdict shapes (pure BODY, pure
PLUMBING, pure TABLE, MIXED, NOT FOUND) plus the S75 shape: 5 of 6 verdicts
UNCHANGED, only the SaveLoadRoutine shape flips PLUMBING REJECT -> TABLE
REJECT (MIXED).
Cookbook §447. The law: a class that cannot fire is worse than a class that does
not exist -- it converts "I don't know" into confident, specific, wrong advice.
When a verdict names a subsystem, check that subsystem owns the MAJORITY OF THE
BYTES before acting on it.
|
||
|
|
cb948a6bbc |
feat(decomp): the ov_SC01 reloc-only cluster + its 5th latent victim — 5 fns, 1,301 ins
S74 handed this forward as "1,116 instructions behind one question": family_remap
on ov_SC01_004/005/006/008 gated DIFF 4/4 against the banked exemplar
ov_SC01_009:func_8017EB08, and the class had been carried as a codegen wall since
S70. The four bodies were byte-identical to the exemplar the entire time.
Word-level classification vs the exemplar, computed independently twice (a Fable
agent's script, then mine from scratch against the retail images), identical:
nins=279 EQ 213 · RELOC-HI16 23 · RELOC-LO16 24 · INTERNAL-J 19 · CODEGEN 0
Zero register-allocation, instruction-selection or scheduling differences.
ROOT CAUSE — tools/jtbl_carve.py reserved ONE WORD TOO MANY per table:
* spimdisasm runs an island's LAST `jtbl_` dlabel one word into the following
NON-ZERO data (string bytes 0x696F760A / 0x000013FF / 0x62647020), so the
zero-word trim cannot see it; and
* the over-span clamp that would have caught it was guarded by
`len(sltiu_bounds) == 1` -- but `sltiu` is ALSO how gcc emits an unsigned
range check ((u32)(x-lo) < n, I1). These four carry five distinct sltiu
immediates, so the guard silently disabled itself on precisely the functions
that needed it.
0x2C reserved for a 0x28 table => image 4 bytes short => ~850 %lo immediates
shift => whole-binary DIFF about a function whose own bytes are perfect.
Fixed with a PER-TABLE bound: gcc-2.7.2's dispatch is a fixed idiom, so the
`sltiu` nearest ABOVE that table's own %hi(jtbl_X) is unambiguous whatever else
the function tests. Second defect stacked behind it: a carve span whose
JTBL_PADS line lacks a `tables=` comment lost its existing table's start on
merge and refused "table starts do not fit the span" -- which harvest_verify
then "repaired" with a needless jr_isolate_all that walked back into the first.
THE NEGATIVE CONTROL IS THE STORY. Run over every other open table-bearing stub
fleet-wide, the fixed bound changed exactly one more table: ov_SC06_022/
func_80185B80 (185 ins), a FIFTH victim nobody had drafted against. A guard that
disables itself on a common idiom does not fail once -- it fails quietly across
the whole corpus.
Banked, each with its own byte-gate verdict (--no-propagate, clean re-gate):
func_8017EB30 ov_SC01_004 279
func_8017F2D4 ov_SC01_005 279
func_8017F2D4 ov_SC01_006 279
func_8017EC68 ov_SC01_008 279
func_80185B80 ov_SC06_022 185
Also here:
* dedup_propagate: memoize find_site's mask (lru_cache) -- 54 ms of masking
per call over the whole source, recomputed though it depends only on the
text. 2x on that loop (58.3 -> 33.0 ms/call), NC identical on 120 addrs.
Scoped honestly: that loop is ~2.4 min of a 30-min run; the profiler puts
43% in family_remap._alias_decl_for, which is NOT fixed here.
* Makefile: `clean` says out loud that BINARY= is ignored and it is fleet-wide
(cookbook §445) -- it silently deleted asm/ for all 213 binaries this session.
* Cookbook §446 (the carve law: when a standalone-MATCH jtbl draft gates DIFF,
diff the carve extent against 4 x sltiu before touching the body), §445, and
SETUP rows for both tools (R21).
* CURRENT_PHASE: the S75 log, incl. the measured fleet dedup-hygiene census
(~2,073 fns / ~12,116 items, all ALREADY MATCHED -- cleanup, not work) and
Drew's decision to leave it and gate --no-propagate from here.
|
||
|
|
0c2b37a287 |
fix(gate): overlays.mk carve-state snapshot was singular, so the revert half-restored
Found by running one reject to ground. After a gate that REJECTED
resident:func_800D06E8, config/overlays.mk had a 4th JTBL_PADS entry and had
LOST `--pre hdr.rodata.o` (the §440 resident leading-rodata sandwich). The
binary then would not build at all -- "consumed 3 rodata jump table(s) but 4 pad
spec(s) given -- table-count drift vs the carve" -- while src/ was perfectly
clean, which is the only place anyone looks before building.
Root cause is a silent narrowing in the classic shape. harvest_verify snapshots
ONLY the gating binary's own overlays.mk block on purpose (the file is shared by
every parallel gate; a whole-file restore resurrects other binaries' lines --
the S62 defect). But _mk_block_span was SINGULAR: the first `# --- <binary>`
header through the next `# --- `. A binary whose carve state spans more than one
block was half-snapshotted and silently half-restored. It returned a TRUE span
for a scope smaller than the caller believed, and nothing compared the two (R32).
Blast radius measured before costing (R37): 1 of the 142 binaries that have a
block -- resident, which has exactly two (§8e pad spec, §8f leading-rodata
sandwich) and still holds 587 instructions of open stubs.
_mk_block_spans (plural) snapshots a LIST, restores tail-first so earlier spans
stay valid, collapses to the snapshot when the header count changed rather than
leaving half-state, and RE-READS and compares the result -- the defect it
replaces was a reported success. _mk_block returns None (not []) for the 71
binaries with no block, so the caller's guard keeps its meaning.
Negative control, three ways:
* snapshot -> restore is a NO-OP on 142/142 binaries with a block;
* the real S75 damage is fully undone;
* the OLD single-block restore provably does NOT undo it -- the positive
control that proves the fix is load-bearing, not decorative.
Cookbook §444 also records the two other findings from the same reject: the
classified ledger stores the LADDER'S FINAL verdict (the recorded CC1-FAIL came
from a late sig_unify rung; the raw draft compiles and fails on BYTES), and
match_one MATCH + rtu_match MATCH is still not bankable -- func_800D06E8's real
blocker is a jump table (built binary 20 bytes longer, 0x800CEDFC holds a table,
69,571 words shift), because neither matcher LINKS.
|
||
|
|
cdd535e45b |
fix(tools): reconcile_tu's cc1 premise, the &-cast arms, and the worktree sig gap
The S74 checkpoint's "one unfixed defect that is actively costing banks"
(reconcile_tu manufacturing declaration conflicts), run to ground — plus the
harness gap that produced a false carve-corruption verdict.
reconcile_tu.py — three defects, measured against the real gcc-2.7.2 front end
(cdecl._cc1_accepts, the oracle cdecl.compatible was validated with; R33):
* The premise "a decl BELOW still conflicts" is TRUE at file scope and FALSE
at block scope. cc1 ACCEPTS a block-scope extern against a TU decl below it
(pedwarn "type mismatch with previous external decl"); conforming it is
destructive, because the TU's decl names the TU's TYPE and a type declared
below the splice point is not in scope AT it -- the emitted result gets
"syntax error before 'D_x'". Byte-witnessed on resident:func_800D06E8 (344
ins), whose block-scoped `extern Blk80078E78` became `extern
Struct80078E78`, typedef 388 lines lower. That construct is what this
ladder's OWN scope_demote_drafts (§8d) rung emits on purpose, and three
already-banked functions in that TU use it: one rung undoing another.
* The cast pass rewrote COMMENT PROSE -- 8 rewrites inside one header comment,
including inside a quoted cc1 diagnostic. Now matches on cdecl._mask
(length-preserving, so a mask offset is a source offset) and splices into
the original.
* `&sym` emitted `&` applied to a cast: legal for the scalar arm, `invalid
lvalue in unary '&'` (measured) for the array/fnptr/fnptr_array arms. `&`
now selects a pointer form and consumes itself -- but ONLY with no trailing
subscript, because `&sym[i]` is the address of ELEMENT i and the old code
had that case right. That last clause exists because the R39 negative
control caught the fold as a regression in the first cut of this fix.
gate_stage.py — `--skip-stages` / `GATE_SKIP_STAGES` (loud when used). Stage 0
gates raw drafts first, so a broken rung can only cost a RECOVERY, which is
exactly what makes it invisible: the function it destroys was already failing,
so its DIFF reads as a fact about the function.
verify_worktree.py / jr_isolate_all.py / parallel_gate.py — provision() now
symlinks every .run/sig.*.jsonl (main clone 259, provisioned worktree 0), the
third member of the class holding extracted/ and .run/obj40. parallel_gate was
fixed for this identical bug in S69: two provisioners, no shared list, found
twice; they now cross-reference each other. jr_isolate_all no longer swallows
the resulting FileNotFoundError into `except: continue` -- that turned a missing
index into a confident carve-CORRUPTION verdict over 2,603 of 2,603 functions
(R54). Adds _assert_scan_covered: attempted == raised means the scan measured
nothing, so its zero is an artifact, not a finding (R32).
Verification:
* 4 cc1 probes (the table above), each run on the pinned front end.
* R39 negative control over the stored-draft corpus: 661 adjudicated, 652
IDENTICAL, 9 CHANGED and every one an intended class. 4,173 of 4,864 drafts
unadjudicable (filenames that are not func_<ADDR>) -- stated, not hidden.
* jr_isolate_all ov_SC03_105 --dry-run: unchanged in the main tree.
* make clean/extract/build BINARY=resident -> 8e17e02f... BYTE-IDENTICAL.
Docs ship with the change (R21): cookbook §442/§443, index regenerated (1,112
sections), 3 docs/SETUP.md rows, CURRENT_PHASE S75 log.
|
||
|
|
eb0329b3a4 |
docs: the five agent-authored tool changes that shipped with a commit message and no docs
I answered Drew's yes/no honestly — NO — and this closes it. Every gap had the same shape: a tool
change that came from a SUBAGENT arrived as a report, I merged the code and wrote it up in the
commit message, and a commit message is not the knowledge base. The six changes I made myself were
documented inline; these five were not.
SETUP.md tooling ledger:
* `ld_interleave` — the row still said "interleave linker inputs" and predated BOTH --order
(S72, main's 7-piece island) and --pre (S74, the resident's leading-rodata header).
* `harvest_verify` — the typedef strip-set is computed SCOPED (`above=fn`) now, and why.
* `jtbl_rodata_pads` — a new row for the three S74 measurement corrections, each of which ACCUSES
THE CARVE when it fires, plus why the trailing-.align one stayed latent (zero_gap self-corrects
an undershoot when the next item is an anchor, and a C jump table has no anchor).
* NEW row `jtbl_carve` — the `covered` / `covered-tpad` verdicts.
* NEW row `jr_isolate_all` — `_region_emit_start` and the empty-closing-region skip.
Cookbook:
* §440 — a carve piece binds to a SUBSEG, not a function, so §8b's "non-adjacent => ISOLATE" is
over-strict: EXTEND the carve across still-stubbed material instead. Four byte-proven
corollaries (migrated tables self-align by SPAN-RELATIVE offset; JTBL_PADS counts cc1 tables
only so a mixed span's spec grows as siblings bank; the zero-word rule is invalid across a
migrated boundary; a covered table at 4-mod-8 gains 4 bytes when it banks). Plus the resident's
rodata->text->data->rodata->data layout and why it needed --pre.
* §441 — three more instrument defects that each produced a confident, precise, WRONG verdict
about a correct draft, with the habit they share: when a gate rejects a body you have
byte-verified standalone, the first suspect is the gate.
Playbook: new step 2a-0 — the same-address lead is size-filtered now; read the `⚠ IGNORE` line, and
regenerate any pack built before S74 rather than trusting a bare address lead.
|
||
|
|
3a886b9652 |
fix(tu-split): a block comment a construct OPENS MID-LINE and WRAPS defeated every peeler
FIVE independently-MATCHed ov_SC06_029 bodies were rejected by a `parse error before '#'` in a file
the GATE ITSELF generates, at a line no draft contains. The isolation emitted, into the §8b carried
decl layer:
extern #define CALL_80185C6C ((void *(*)(s32, s32))func_80185C6C) extern void func_8012C218();
CAUSE. Every peeler in the TU-split chain asked `line.strip().startswith("/*")`, which is blind to a
comment a construct opens MID-LINE and wraps. The declaration ends at its `;` BEFORE the `/*`, so
the caller resumed on the comment's PROSE with in_block=False — and the prose is hostile: `(s32,s32)`
closes a depth-0 paren, `seen_header` latches, and every later `;` reads as a K&R parameter
declaration, so one "construct" swallowed the whole preamble. `parse_overlay_c` then anchored a
`def` on a pure declaration run and `def_proto` rendered it as that definition's implied prototype.
A SECOND defect rode along: `_file_scope_decls` hoisted such a col-0 line VERBATIM, unterminated
`/*` included, so the carried layer opened a comment that silently ate the next two declarations —
a dropped file-scope decl is a silent byte-changer. Building the guard exposed a THIRD: `_strip`
tested for `/*` before stripping `//`, so `// … src/*/*.c` (7 lines in 5 sources) opened a phantom
block comment and blanked everything to the next `*/`.
FIX: one derived comment-state oracle, `comment_open_at()` (R33) — per line, does it BEGIN inside a
block comment — consulted by parse_overlay_c, def_proto, split_src_region.parse and
jr_isolate_all._file_scope_decls (which also truncates a hoisted decl at an unterminated `/*`).
`_strip` now lexes left to right. `parse_overlay_c` RAISES (R43) when a wrapped comment closes with
code after the `*/`, because that construct could never anchor — 0 occurrences fleet-wide.
MEASURED, not assumed:
* the shape occurs 238 times across 193 tracked .c files; 153 are col-0 hoistable declarations in
150 files — every one a binary whose next isolation would have carried a broken decl layer.
* A/B over all 4,188 tracked sources, old parser vs new: round-trip identity 4188/4188 both ways;
exactly 2 files' item lists change, each losing one PHANTOM def and gaining nothing; malformed
implied prototypes 999 -> 984; 0 refusals.
* negative control BEFORE any edit: ov_SC06_029 extract+build -j+check BYTE-IDENTICAL b7b0d4ae.
* with the fix, gate_stage banked 5 of 6 drafts, counted from the SOURCE; the 6th
(func_80184084) is the separate CARVE-REFUSED class.
The 984 residual malformed prototypes are a DIFFERENT pre-existing trigger (col-0 lines gluing
declarations to DEFINE_func_*() invocations); 4 still carry a `#` and survive only because it lands
in a dropped segment. Named in §437, deliberately not fixed here.
Cookbook §437 + a SETUP.md tooling-ledger row for comment_open_at (parse_overlay_c may now raise).
The banks themselves are NOT in this commit: the agent's worktree predated func_8017F9C0's bank, so
adopting its TU verbatim would have destroyed one. They get re-gated against HEAD with these tools.
|
||
|
|
95c7b7fe0f |
fix(tools): two tools read a source of truth describing a different world (+ hard-gate the third)
Three independent split agents hit both defects in one session, on the tools that CERTIFY and UNDO
the work they were doing. Each is fixed, negative-controlled against the exact failing case, wired
into its siblings, and documented in the same change (cookbook §436).
1. split_indicator attributed a jump table by the STUB'S DIRECTORY PATH. `make extract` does not
prune a re-homed subseg's `nonmatchings/<old>/` dir, so after a correct, byte-green §431 split
both the old and new dirs hold the moved stub — and the tool printed NEEDS SPLIT for a split that
was already correct. owners() now derives the owner from the CONFIG by address (R33), exactly as
jtbl_carve.func_subseg already does for the identical §8b hazard, and NAMES any leftover stub in
a `note:` line. Notes now print on an OK verdict too: hiding one behind `st != OK` is the same
defect in the other direction — a true verdict about a narrower world than the reader believes.
PROVEN by planting a stale stub for func_80182A00 under its old subseg: OK + the note, where the
old code would have seen one subseg owning two spans. --self-test still PASSes both directions.
2. jtbl_carve --revert did `git checkout --` on the WHOLE splat yaml. The carve owns only the
trailing data/.rodata region; the `c` pieces are source configuration it never writes. The blunt
form cannot tell "carve state I just added" from "the §431 split someone added to the same
uncommitted file", so --revert after a carve PROBE silently un-split the overlay — each agent
recovered only because they had backed the yaml up by hand. It now splices back only its own
region (parse_config gained an optional `lines=` so the SAME region derivation runs over the
committed text — one derivation, two callers), refuses loudly if the committed region carves onto
a subseg the current config no longer defines, and reports how many uncommitted `c` pieces it
preserved. PROVEN in the ov_SC01_084 worktree: carve → revert → the uncommitted split survived
("PRESERVED 30 uncommitted `c` piece(s)"), carve lines gone, diff back to the 6 split lines.
SIBLING: jtbl_family_bank.revert carried the same blunt checkout for the isolation's code pieces.
It now keeps whatever pre-dated the attempt (the `keep_regions` signal it already trusts for
src/) and NAMES anything it drops — an isolation region and a §431 split piece are both
`<ov>_jr_<addr>`, so no name test can tell them apart and only that signal can.
3. NOT A DEFECT, and recorded as such: a speculative carve fails the build with `jtbl_rodata_pads:
consumed 3 rodata jump table(s) but 9 pad spec(s) given`. That is R43 working — the pad spec is a
CONSEQUENCE of banking, not a prediction of it — and it reproduces identically on the pristine
unsplit config, so it is never evidence about a split.
make tools-health: split_indicator is a HARD GATE now, as its own comment promised it would become
once the last violation was split. 213 OK of 213; a new one fails the build instead of being echoed
past.
Cookbook §435 (an overlay TU split is near-free — 0/3,074, 1/2,679, 2/3,254 names crossed, because
the §8b carried decl layer re-emits externs per region so only typedefs can cross; and the gap test
between two rodata runs is "is this word a valid code address", not "is it zero") + §436 (the two
defects and the shape they share). Playbook + SETUP.md carry the emptied CARVE-BLOCKED class.
|
||
|
|
0840c0991c |
docs(SETUP): fix four stale spots the tool-inventory update missed
I updated SETUP's tooling INVENTORY when each tool changed, but not the HUMAN-facing
procedure, and §6.6 is where a person learns the matching loop:
* :493 still said 'In src/800.c, replace the INCLUDE_ASM line with the C function body.'
main's game code is THREE TUs since S72, and WHICH one is load-bearing for any switch
function — one code object contributes exactly ONE contiguous .rodata run, so the TU
decides which jump-table span the body's table lands in. Following that line for a
span-B/C function re-creates the exact §426 double-emit this session existed to remove.
Replaced with the vram -> TU -> asm-path -> span table.
* :759 listed main_diff_locate's verdicts as an exhaustive three — BODY / PLUMBING /
MIXED. There are FOUR, and the missing TABLE REJECT is checked FIRST and covers
precisely the case the PLUMBING clause claimed ('byte-identical, everything differs
elsewhere'), routing the reader into the one chain the tool forbids for that class.
* config/wave_exclude.txt was named nowhere in SETUP despite being tracked config that
draw_waves now requires. Added, with both entry classes and the WALL pin.
* :537 described ld_interleave as --front/--tail only; main uses --order since S72.
|
||
|
|
983df054f2 |
feat(draw): audit the exclude list as a PREREQUISITE — a stale one is refused
An exclude list records what the TOOLING could not do, then gets treated as a property of the FUNCTIONS. Nothing re-examined it, so every tool fix left behind a population that is now tractable and still marked impossible — invisible, because the draw filters it out before anything measures it. MEASURED one day after .run/S71_exclude.txt was written: 88 of its 107 entries were stale — 28 already banked, 14 linked PsyQ symbols that were never targets, and 46 whose blocker had since been fixed. Those 46 are 12,750 instructions of open, drawable work including main:SaveLoadRoutine (1,165), the largest function left in main. * tools/exclude_audit.py (NEW) — classifies each entry by its CURRENT blocker (BANKED / LINKED / RE-PROBE / CARVE-BLOCKED / WALL), regenerates keeping only the still-valid classes, and --assert-fresh exits 3 on staleness. * draw_waves --exclude-file — runs that audit and REFUSES to draw on a stale list, naming the counts and the regenerate command. --exclude-stale-ok still draws but prints what it ignores: skipping is possible, never silent. Also fixes the old --exclude parsing, which could not survive a '#' comment. * .run/S72_exclude.txt — the regenerated list: 19 entries (16 CARVE-BLOCKED + 3 WALL), each carrying its reason, down from 107. Verified in all three directions: stale refuses rc=1, fresh proceeds rc=0, override proceeds and announces. The parser's own report-don't-drop design caught a bug I introduced in it (comma-splitting before comment-stripping). |
||
|
|
8e8521da22 |
fix+docs: make every consumer aware of main's new TU layout (R36)
The split created two new TUs and a shared header; four consumers still described main's
game code as one file:
* tools/reconcile_slate.py — HARDCODED open('src/800.c'), so after the split it saw a
THIRD of main's typedefs while reporting success (silently-narrowed scope, R32).
Measured: 133 visible before the fix, 187 after, 0 lost. Now globs
corpus.src_files('main') + src/800_shared.h, so a future split is already handled.
* docs/wave-playbook.md 1c — still said spans B/C/D were NOT drawable and that drawing
one is an R45 violation. That is now false and would have STOPPED a future session
from drawing the very targets this work unlocked.
* cookbook §426 — its 'the remaining spans need src/800.c split' paragraph now records
that it was done the same session, and points at §431 for the method.
* config/dedup.us.yaml + src/shared/clearTbl40.h — both said dedup group I0 is
instantiated 'at both sites in src/800.c'; both sites are above 0x80035270 and are now
in src/800_c.c.
Byte-neutral: dedup.us.yaml parses, gate_main --assert-baseline BYTE-IDENTICAL.
SETUP.md gains a row describing the layout and the rule it implies: never hardcode
src/800.c, glob corpus.src_files('main').
|
||
|
|
e94bb20833 |
docs: bank the S72 main carve finding — cookbook §426/§427, playbook 1c, SETUP, decision log
§426 — main's switch functions were never a codegen wall: one .rodata carve had been missing since Phase 7, so a drafted switch double-emitted its jump table (+28/+52/+76/+84 image growth, 238 symbols shifted, first mover jtbl_80072A4C every time). Includes the derived name-address overlay that names a layout shift with no reference build, the span table, and why spans B-D need src/800.c split at the original TU boundaries the spans reveal. §427 — a hash is a correctness oracle with zero diagnostic content; preserve the red artifact before anything rebuilds over it, attribute per byte, and negative-control the localizer in both directions. playbook 1c — which main jtbl functions are drawable (R45), and the gate note: main is not in the parallel lane, read the BODY/PLUMBING/MIXED verdict before recording a main reject. |
||
|
|
6c904ebd0c |
docs: close the S71 documentation gaps - SETUP tools table, playbook steps, decision log, gate ledger
Audit found real gaps rather than assumed coverage: * SETUP.md (R21) had NONE of the five tools written this session. Added a table for journal_notes / launch_check / gate_triage / restage_matching / weave_sweep, each with when you need it, plus the two gating rules now enforced in code (parallel_gate refuses main; gate_main refuses a no-op draft and counts banks from the source). * wave-playbook: launch_check as step 4c (payloads go stale while gates run - 3 of 27 wave-2 targets were already banked) and gate_triage as step 6b with the measured blocker census. * decision-log (R31) held only the §406 pivot. Added the two strategic entries this session actually turned on: gating main with a tool documented as unable to gate it (false PASS, caught only by R22), and the drafting pool running dry while the lever was an exclude list nobody re-probed after a tool fix. * CURRENT_PHASE: the per-gate ledger for all 14 cycles plus the carve/rebase/main gates. * Two memories: gate-main-only-with-gate-main, reprobe-exclude-lists-after-tool-fixes. |
||
|
|
dff33f66d9 | docs(setup): WSL memory cap lowered 48GB -> 32GB (Drew, 2026-09-02); applies on next wsl --shutdown | ||
|
|
8f87334399 |
docs(setup): WSL2 memory reclaim — autoMemoryReclaim=gradual + the interim cache dropper
Task Manager showed WSL holding 30 GB while Linux was using 4 GB and ~22 GB was reclaimable page cache (a gate wave reads the 450 MB asm/ tree plus every build object). .wslconfig had a memory cap but no reclaim policy, so WSL2 never handed freed pages back to Windows. Added autoMemoryReclaim=gradual (needs wsl --shutdown), recorded the no-restart manual reclaim, and .run/memkeeper.sh as the interim automatic form. R21. |
||
|
|
20f80fd933 |
docs: §400 + SETUP + carve-state memory for the new-file adoption fix; correct a stale docstring
§400 — a baseline check that conflates "absent everywhere" with "changed under
us" silently drops new files. The general law: when a comparison uses two
different sentinels for "nothing" ("" from a failed command, None from a missing
file), it reports a difference that does not exist — and in a GUARD, a phantom
difference becomes a refusal, which looks exactly like the guard working.
Corollary recorded in both §400 and the carve-state memory: "never blanket-add"
covers SHARED carve state (overlays.mk, splat yamls). It does NOT cover a carve's
own new per-binary source file, which is named by a committed yaml and whose 31
siblings are tracked — that one must be adopted with the bank that created it.
Docstring correction: parallel_gate does NOT use `git add -u src/` (that is
gate_stage's form); it adds exactly the adopted paths. My first diagnosis of this
bug blamed `-u` on the strength of that stale line and was WRONG — the cause was
the baseline comparison. Noted in the docstring so the next reader is not
misdirected the same way.
|
||
|
|
8f171c6ce6 |
feat(tools): verify_binary + twin_rescan — put S69's two habits in the tooling, not in prose
Both rules were already written down (§384, §397) and both were violated anyway, which is the argument for a tool: a habit you must remember at the moment you are impatient is not a control. tools/verify_binary.py — ALWAYS re-extracts before building, because a carve rewrites splat inputs and a build over stale extract state produces a meaningless SHA. S69 read three binaries as red on build-only checks; all three were BYTE-IDENTICAL after extract+build, and two false reds cost legitimate work that had to be restored (a 96-line match, and 23 declaration edits). --all-touched sweeps everything with uncommitted src/ or config/ changes. tools/twin_rescan.py — the twin oracle answers "is there a BANKED body like this?", so an OPEN-OPEN cluster correctly reports "no banked twin" for every member and that verdict is stale the instant one banks. Diffs the scan against the previous snapshot so it reports what JUST became free, not the whole board, with the ready-to-run family_remap command per row. Baseline: 318 open stubs, 37 already carry a banked twin at d<=5. Memories added: rescan-twins-after-every-bank, check-against-a-known-true-case. |
||
|
|
860f866f6e |
docs: §322b/§332b/§378c + accelerator #19 + SETUP — the Fable-3 blocked-pile audit
§322b — the carve class is COMPLETABLE, and every worktree CARVE-REFUSED was an instrument verdict (.run/sig.<b>.jsonl is gitignored, absent from worktrees, so jr_inventory read every carve as UNOWNED). build_carve's refusal is EXACT, not conservative — one object emits one contiguous .rodata — and the real fix (isolate into its own subseg) already exists and harvest_verify already runs it. Live census: 71 non-contiguous of 123 jtbl stubs; 21 of those are twins of already-banked bodies (3,852 ins) free at ~25s each. End-to-end byte-proven in 23 seconds. Remaining blockers are 18 overlay_src_split plumbing defects (<=30 lines each) plus a jr_isolate_all port for main. §332b — the §332 "walls" are a per-OBJECT assembler mode, not a C limit. A 3-line maspsx reorder-passthrough + as -O2 is byte-INERT across the whole 800c3/800c2 objects and yields 0 diffs for SIX walls whose drafts already exist. That turns "permanently unbankable" into a per-object Makefile switch and retires oracle_reorder.py. Only 13 of the 15 listed walls are even reachable. §378c — a FIFTH decl-blocker variant: the DRAFT redeclares a type/data/callee the TU or a header already owns. Fix the draft to the TU's spelling (§367), never the reverse. Two "integration-blocked" rows were phantoms, one of them my own --any-proto pre-pass breaking a sibling TU (variant 4, second bite). accelerators #19 — a verdict recorded inside an isolated environment describes the ENVIRONMENT. Isolation exists so the worker sees less; every gitignored input is a difference it cannot distinguish from a genuine rejection, and it writes that difference down once per function. Negative-control the environment with a known-good item; assert the worker's inputs; report a missing input as MISSING, never as a verdict. |
||
|
|
f11bf13b4f |
feat(seed_ref): the CONTAINED tier + docs for the twin ladder (§390/§391, accelerator #18)
tools/seed_ref.py gains --contained/--contained-control: an open stub that is a banked body plus or minus WHOLE BLOCKS — the class edit distance ranks badly. Branch-offset masking was required (unmasked offsets veto exactly the target pairs) and a min-side-25 floor (89% of raw hits were prologue/epilogue vacuity). Ranks by (substitutions+regions, cover), not by d. Controls: planted-deletion positive 60/60, random-pair base rate 0/397, R32 population 346/346, and a post-refactor --near regression reproducing the stored slice exactly. Banked on first use: ov_SC01_077/func_80184D50 = banked ov_SC03_007/func_8018283C minus its trailing `&= 0x7FFFFFFF;` — MATCH, closeness 0, 98/98. * cookbook §390: minimum distance is not minimum work (rank by effort; a deletion is free, a substitution is thought), the lookalike filter r = d/min(nins) ~ 0.3 (17 of 30 "cousins" were boilerplate coincidence), and the three fleet-wide nulls that close the scanner question — 0 new / 9 / 2. Spend integration effort, not scanner effort. * cookbook §391: a byte-aligned struct copies in FOUR instructions (lwl/lwr/swl/ swr), a word-aligned one in TWO. Never invent an aggregate type to make a draft compile — an invented word-aligned Blk8 lost exactly 8 ins across two copies and read as a believable "near, closeness 70" codegen residual. * accelerators #18: a claim derived from BYTES is not a claim verified by a COMPILER. Every similarity/correctness claim must name the tier it reached (stream containment / compiled standalone / whole-binary gate / clean fleet); a report that says "verified" without one invites the strongest reading. Non-reproduction is a finding — say so rather than assuming your own setup. * playbook §2a-2: the twin ladder (exact -> RELOC-ONLY -> CONTAINED -> cousin -> cold), take the cheapest tier available, widen only when the tier above is empty. * SETUP inventory row; generic-decomp-package: rank by work, and stop building scanners once the well is dry. |
||
|
|
881dd5a37c |
docs: the NEAR-TWIN BAND — §389, accelerator #17, SETUP, playbook §2a, generic-decomp-package
The exact-hash twin tier found 22 of 352 reachable open stubs (6%). The edit-distance band added by `seed_ref --near` finds 75 of 352 (21%) — 3.4x — on a corpus we believed fully mined. 31 of the new rows were PURE reloc-only twins of already-banked bodies; 8 banked the same day at ~0 agent tokens, one 94-ins exemplar serving five open copies. * cookbook §389: the h_norm hole (norm_stream drops its pending lui-hi on an intervening R-type, so indexed-global reloc twins hash differently and vanish from seed_ref/twin_sweep/dedup/family-maps at once). Do NOT fix h_norm — every stored calibration keys on it; the near tier reads through it. * accelerators #17: the generalisable law. A similarity hash built for DEDUP under-matches by design, which is correct for dedup and silently lossy as a FRONTIER join — the two questions want opposite error directions, and the frontier failure looks exactly like "this function is unique". * generic-decomp-package §2b: build the near band at the same time as the exact tier, with the three verifications. It pays from the first bank for a new project, where we paid a session to recover the debt. * SETUP inventory row + playbook §2a (run it before believing any "no twin" verdict; never send a RELOC-ONLY row to a drafting agent). |
||
|
|
9fc27960e9 |
feat(integration): teach the rest of the toolkit about §378 (self-caller cast)
The lever existed but nothing downstream applied it. Proof it mattered: a wave agent this session diagnosed its own blocker as "§378 THE SELF-CALLER CAST, a TU-level fix (cast_self_callers.py) that requires editing src/, which I'm not permitted to touch" — the knowledge propagated, the automation did not. * recover_integration.py: NEW "self-cast" stage (tier=binary), so the driver can run the whole chain as --stages arity,self-cast. The docstring states WHY the order is not arbitrary: self-cast answers the error that "arity" CREATES. * residual_rules_b.py: both decl-conflict tiers now prescribe the full chain instead of "route to integration / budget for banking", and NOCOMPILE-UNDECLARED-FIXED now says outright NOT to gate the autodecl arm (it is a second conflicting declaration in the real TU). * wave-playbook §4b: replaced the stale two-step recipe with the three-step chain, the one-driver form, the callee variant, and the MANDATORY --undo-journal. * SETUP.md: full inventory row (R21) — it had zero mentions. Not wired, deliberately: gate_stage's ladder rewrites DRAFTS via _xform, while this edits the TU; a src-side edit inside the automatic gate needs revert-on-failure, which recover_integration already owns. Still open: a draft_prechecks rule to catch the self-decl conflict statically, before a build is spent. The new stage's plumbing is verified (CLI + candidate selection); its functional end-to-end run is NOT — gate12 held the tree. |
||
|
|
1dd15eda32 |
feat(triage): the triage ladder — built, wired, and acceptance-green
tools/triage_ladder.py — the zero-token pre-agent pass, split PRE (target-side: BANKED/WALL-332/PARKED, no build) from POST (residual_rules_b, needs a draft). --escalate refuses a walled or banked target; --acceptance is the R39/R32 harness. Refuses on a non-quiescent tree: a merging gate makes the stub oracle wrong in both directions (measured, ov_SC01_004:func_8017EB30). Acceptance, on the whole corpus: false-skip 0/1367 open stubs, recall 426/426 matched, wall tier fires on exactly the 10 enumerated walls (0 extra, 0 missing). The first wall control asked for evidence that CANNOT exist — it scanned banked functions' .s, which splat never writes — and printed '0 scanned / 0 tripped', indistinguishable from a pass. The R32 empty-denominator assertion caught it on its first run; replaced with a two-sided sweep over all open stubs. tools/cast_self_callers.py — the §378 lever + --sync-decls for the narrow-param case C89 forbids no-proto from reaching (§378a). Wiring: wave_args drops walled/parked targets at draw time via pre_classify (one implementation, R33); escalate_fable.js refuses any target without triage:'DRAFT'. Tool fixes found by measurement: * fix_arity_callers was blind to main entirely (globbed src/main/main*.c; main is src/*.c) — reported success over an empty file set through three gates. Now refuses when --binary selects no files. * parallel_gate records each worker's 'failed by class' line (was truncated out of the 200-char tail); gater_lane retries in-tree ONLY on the diagnostic-free blind-worktree signature — S69 ran 22 serial retries against real cc1 errors. docs: cookbook §376/§377/§378 (index 1033), SETUP.md, wave-playbook §4b. |
||
|
|
5c317dbe5f |
docs: wire the S68 tools into SETUP.md (R21) and the playbook (when to use them)
A tool nobody knows about is invisible work. Audit found neighbor_ref (built an
hour ago), residual_rules, lane_inflight and r22_verify in NEITHER doc, and
wall_sweep in the playbook but not the inventory.
SETUP.md gains a tooling-inventory row for all five with what each is FOR.
wave-playbook gains §2b: run neighbor_ref for EVERY card, placed right after the
seed_ref step because it answers the weaker and far more common question ('which
matched function should this agent READ?') that seed_ref structurally cannot. It
carries the measurement that justifies it -- a ~20x token swing on that single
variable -- and the failure it prevents: func_8017BEBC's card said 'no banked twin'
while a matched 755-instruction near-twin sat 3,700 lines up IN ITS OWN FILE.
Also states the two honest limits: an opt-level mismatch is PENALISED not merely
ranked low (§116 -- an -O2 example misleads an -O0 target), and a neighbour is a
worked example to READ, never a body to copy (§168 law 1, cousin-remap 0/26).
|
||
|
|
54c0624e49 |
docs: §371 the module-binary -O0 carve route + the spimdisasm rodata trap; SETUP.md S68 tooling rows (R21)
§371 ★★ carving a SINGLE-OBJECT module binary. One 'unaddressable content' message was THREE stacked causes (interior-YAML-comment symbol-list truncation, a trailing verbatim-asm chunk with no region, bare tag forward decls) -- fix one and the message does not change, which is why it read as an impassable wall. Then the reusable part: spimdisasm migrates single-referenced rodata into a function's .s ONLY within the same subseg, so a carve that moves the function silently DROPS it, and INCLUDE_RODATA cannot bring it back (splat marks it migrated segment-wide and emits nothing). Rename the .rodata subseg to the object its emitters moved to; the regenerated .s coming back byte-identical is the proof. Also recorded: the Makefile -O0 glob hunk is PART of the carve, not a follow-up; interleave_check's DRIFT on md_MAIN_003 is PRE-EXISTING and must not be 'fixed'; the still-open second-carve refusal (UNOWNED rodata 0x800cedf8); and the §126 plan for the remaining 8 -O0 stubs (three are ADJACENT so one region covers them). SETUP.md (R21): three tooling-inventory rows covering gater_lane/escalate_fable/ o0_boundary, the six overlay-layout fixes, and the module-binary carve route. |
||
|
|
5bcb322283 | docs: gating is fully parallel — no serial lane; jtbl unlocked via isolate_asm; launch detached with setsid | ||
|
|
00812fc62f |
docs(p31 s67): wave-playbook (the CURRENT pipeline) + seed_ref fix + harvest §333-§338
THE DOC GAP, and it cost tokens this session. `docs/automation-runbook.md` was titled "the
autonomous campaign, as it actually runs" while documenting the RETIRED OpenRouter/ox-alpha system
whose lanes are all deliberately DEAD. The current Claude-wave pipeline existed only as two dense
tooling-inventory rows in SETUP.md — reference, not procedure. Three of this session's costliest
mistakes were procedural and a playbook prevents each:
* hand-typed a refill target -> invented func_80184F60 (2nd instruction of a matched function), 58k
* hand-rolled a serial gate loop when parallel_gate existed -> ~1h for what took 103s
* re-derived a function banked verbatim in ~20 overlays -> 102k
NEW docs/wave-playbook.md — start to finish, each guard paired with the MEASUREMENT that produced it
(that pairing is the part a generic decomp guide cannot have, and the seed of the future template).
automation-runbook.md retitled HISTORICAL with a pointer; SETUP.md §6.9 links the playbook.
NEW tools/seed_ref.py — the cross-TU banked twin, joined on corpus signature hashes (no atlas knn,
~2s fleet-wide), wired into t5_cards.py. FLEET: 87 open stubs have a banked twin; 41 of them sit in
twin_sweep's refusal ledger, invisible to BOTH tools at once. Documents twin_sweep's two holes:
load_sigs covers 141/213 binaries (main, resident, all md_MAIN_* absent), and one curated symbol
name silently disables an entire binary via a bare `except Exception: pass`.
Schema note: seed_ref's binary/fn are the EXEMPLAR's, because api_agent greps src/{binary} for {fn};
naming them after the target would send every agent grepping for itself — caught pre-ship.
HARVEST §333-§338 from the s67o2_1/pool_1 waves:
§333 frame size is set by DECLARED aggregates, not used ones — an unreferenced trailing local is a
dial (3 instances; one worth 30 of 32 residual rows)
§334 a reload spill slot rounds to BIGGEST_ALIGNMENT for align AND size: one 4-byte pseudo grew a
frame by 16 (82->53)
§335 `extern u16 A[]` at a variable subscript allocates ~8B/access of dead stack temps that inflate
the frame with ZERO extra instructions — invisible in a body diff (141->20)
§336 the §5a barrier goes at the BOTTOM of the twin; find_cross_jump walks BACKWARD
§337 the CC1-ONLY blocker class: blocker_probe's static oracle says "none" and cc1 still fails
§338 _sltiu_bounds misreads a non-switch sltiu as a bounds check, over-spanning the table
gate_wave.py now STREAMS both lanes (R55) — it captured output and printed at the end, leaving a
zero-byte log indistinguishable from a hang.
|
||
|
|
41b259e528 | fix(wave): cards keyed by (binary,fn) — t5a received 48/48 ANOTHER binary's card (R48); t5_cards.py builds the target's OWN fuel (tu_ref 88% / decl_prior 98%) via wave_card_fuel.py extracted from build_wave_atlas (R33); t5_bank.sh recovers un-banked drafts via fix_tu_ret_decls (2/2 on t5a); distill workflow generalized (P31 S63 T5) |