mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-02 16:00:27 -04:00
curate: Migration: memories routed
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# Memory Index
|
||||
|
||||
- [Generation legacy memories](genlegacy.md) — 83 entries
|
||||
File diff suppressed because it is too large
Load Diff
+47
-13
@@ -5,23 +5,57 @@
|
||||
"installed_at": "2026-09-30T00:53:41Z",
|
||||
"lifetime_since": null,
|
||||
"phase_ends_dir": "phase-ends",
|
||||
"handoff_ctx": { "expert": 350000, "coder": 300000 },
|
||||
"handoff_ctx": {
|
||||
"expert": 350000,
|
||||
"coder": 300000
|
||||
},
|
||||
"toast": "waiting",
|
||||
"warmer": "on",
|
||||
"follow_agents": "off",
|
||||
"discord_webhook": null,
|
||||
"rhythm": "autonomous",
|
||||
"tier": "max5",
|
||||
"legacy": { "phase_naming": "dotted" },
|
||||
"credit": { "spill_chars": 20000, "note_max_age_s": 3600 },
|
||||
"audit": { "file_chars_flag": 500000, "growth_flag": 0.2,
|
||||
"noise_patterns": ["warning: in the working copy of", "CRLF will be replaced",
|
||||
"usage: ", "No such file or directory"],
|
||||
"router_ctx_flag": 300000 },
|
||||
"install": { "source": "https://github.com/Druthulu/ProjectArchitect.git", "clone_dir": "pa3-src",
|
||||
"update_check_hours": 24, "fetch_timeout_s": 8 },
|
||||
"card": { "max_chars": 7000 },
|
||||
"guard": { "spilled_read": true, "whole_plan_roles": ["review", "critic"], "tool_source_roles": ["expert"],
|
||||
"whole_read_chars": 20000 },
|
||||
"bench": { "window_max_pct": 80 }
|
||||
"preset": "max20",
|
||||
"legacy": {
|
||||
"phase_naming": "dotted"
|
||||
},
|
||||
"credit": {
|
||||
"spill_chars": 20000,
|
||||
"note_max_age_s": 3600
|
||||
},
|
||||
"audit": {
|
||||
"file_chars_flag": 500000,
|
||||
"growth_flag": 0.2,
|
||||
"noise_patterns": [
|
||||
"warning: in the working copy of",
|
||||
"CRLF will be replaced",
|
||||
"usage: ",
|
||||
"No such file or directory"
|
||||
],
|
||||
"router_ctx_flag": 300000
|
||||
},
|
||||
"install": {
|
||||
"source": "https://github.com/Druthulu/ProjectArchitect.git",
|
||||
"clone_dir": "pa3-src",
|
||||
"update_check_hours": 24,
|
||||
"fetch_timeout_s": 8
|
||||
},
|
||||
"card": {
|
||||
"max_chars": 7000
|
||||
},
|
||||
"guard": {
|
||||
"spilled_read": true,
|
||||
"whole_plan_roles": [
|
||||
"review",
|
||||
"critic"
|
||||
],
|
||||
"tool_source_roles": [
|
||||
"expert"
|
||||
],
|
||||
"whole_read_chars": 20000
|
||||
},
|
||||
"bench": {
|
||||
"window_max_pct": 80
|
||||
},
|
||||
"memory_routed": "3.14"
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ Who: <!-- TODO DEVELOPER_NAME: no source found -->. Experience: <!-- TODO DEVELO
|
||||
Preferences: recommendations, not questions. Plain-English recaps at phase end. A notification
|
||||
whenever anything waits on them. Autonomy: <!-- TODO AUTONOMY_POSTURE: no source found -->. Notification channel: <!-- TODO NOTIFY_CHANNEL: no source found -->.
|
||||
The developer pushes; agents never do. They ratify rules at the next planner session.
|
||||
- drew-working-preferences: Drew's working style on BFM-decomp — autonomous-within-phases, ultracode effort, accepts recommended options, wants WSL/tooling decisions surfaced plainly
|
||||
|
||||
## Rhythm <!-- roles: router planner review discuss auditor curator -->
|
||||
autonomous <!-- autonomous: the router runs the phase end to end, stopping only at the two gates.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# C0509 — fleet-tool-parallelism-defaults
|
||||
tags: legacy,memory · date: 2026-09-29 · phase/task: - · origin: legacy memory fleet-tool-parallelism-defaults.md
|
||||
|
||||
Drew (2026-08-07): "if these work successfully I want a new memory and defaults created so we forever
|
||||
use these speedup techniques." Measured on `dedup_propagate` (S46): **24 min → 11.4 min, same 29
|
||||
functions, +62 MORE member instances** (R22 213/213 both ways).
|
||||
|
||||
**The four defaults for any fleet-wide tool in this repo:**
|
||||
|
||||
1. **Return EVERY verdict a sweep already computed.** `gate_all` byte-gated all 141 overlays and
|
||||
returned only the first failure, so the recovery loop paid a full sweep to rediscover each of the
|
||||
next 137. Batching them took convergence from ~138 rounds to 1–3. Same builds, same determinism.
|
||||
2. **PROCESSES for CPU-bound work; threads ONLY for subprocess waits.** A `ThreadPoolExecutor` over
|
||||
138 "independent" searches kept **0–4 builds alive at load 3** — the work was regex over 15k-line
|
||||
files, so every thread queued on the GIL. The same code in a `ProcessPoolExecutor`: **14–29 builds,
|
||||
load 34.75** on 32 cores. Threads are right for the byte-gate (each is a `subprocess.run`), wrong
|
||||
for anything that parses or rewrites source.
|
||||
3. **Longest-first scheduling.** `ex.map` starts work in list order, so the giant overlays landing last
|
||||
left 31 cores watching one build for ~25 s of every 56 s sweep. Sort by source size descending;
|
||||
re-sort results into the caller's order so the verdict stays bit-identical.
|
||||
4. **Per-item search beats lock-step sweeps** when items are independent — and *say why they are*.
|
||||
Here: the shared header carries every macro regardless, so writing it once up front leaves each
|
||||
overlay owning only its own `.c` files and `build/<bin>/`. That cuts BUILDS, not just overlap.
|
||||
|
||||
**Two traps this exposed, both worth checking in any tool about to run parallel:**
|
||||
- **A fixed temp path** (`.run/dpcc/t.c`) is a correctness bug the day something runs concurrently —
|
||||
the same fake-isolation class as `match_one`'s shared `--work` dir. Make it per-call.
|
||||
- **A pool submitted all at once shares no learning.** Every worker got an empty suspect list and paid
|
||||
a full bisection. Seed with one item in-process first, then fan out with the result.
|
||||
|
||||
**Prove it, don't assume it:** the acceptance test was a *regression*, not a stopwatch — revert to the
|
||||
pre-run state, re-run the identical command, and require the same functions and a byte-verified fleet
|
||||
(R22). It came back faster AND with 62 more instances banked, which is how the over-exclusion in the
|
||||
old path was found at all. See [[decomp-accelerator-ledger]] (A8) and `docs/accelerators.md`.
|
||||
@@ -958,3 +958,4 @@
|
||||
- **§498** — ★★★ — A CARVE THAT DROPS THE BINARY'S `--pre` CLAUSE, AND A GATE THAT IGNORED THE EXTRACT'S EXIT CODE: HOW A BYTE-CORRECT DRAFT WAS BOOKED "DIFF" (P32 T1a; resident `func_800D128C` BANKED 243 ins after two instrument fixes) <sub>L36728</sub>
|
||||
- **§499** — ★★★ — A NEVER-ONBOARDED PAYLOAD PINS ITS OWN BASE STATICALLY, AND THE FIRST BUILD CANNOT (P32 T2a/T2b: the parked five onboarded, 213 → 218 binaries, 0 UNCLAIMED) <sub>L36758</sub>
|
||||
- **§500** — ★★★ — THE T3 WAVE HARVEST (P32 T3, 2026-09-05): 31 one-agent-per-function drafters → 20 MATCH / 9 NEAR / 2 FAIL, every closer, two NEW named gcc mechanisms, and the wave-process defects <sub>L36799</sub>
|
||||
C0509 | fleet-tool-parallelism-defaults | legacy,memory | 2026-09-29 | - | legacy memory fleet-tool-parallelism-defaults.md
|
||||
|
||||
@@ -45,3 +45,9 @@ p37-s106-2026-09-12-the-type-census-and-the-struct-map-phase-37-t1.md | §P37 S1
|
||||
p37-s106-2026-09-12-the-probe-and-the-rewrite-engines-first-form-phase-37-t2.md | §P37 S106 — 2026-09-12: the probe and the rewrite engine's first form (Phase 37 T2) | 24
|
||||
p37-s107-2026-09-12-the-rewrite-engines-full-form-the-layout-library-and-the-linked-oracle-phase-37-t3.md | §P37 S107 — 2026-09-12: the rewrite engine's full form, the layout library and the linked oracle (Phase 37 T3) | 51
|
||||
retired-tools-toolssunset-phase-335.md | Retired tools (`tools/sunset/`, Phase 33.5) | 198
|
||||
SETUP.preamble.md | SETUP.md — Environment Setup & Daily Operations Reference | 8
|
||||
disc-dump-location.md | disc-dump-location | 9
|
||||
gate-main-only-with-gate-main.md | gate-main-only-with-gate-main | 71
|
||||
mcp-renames-dont-persist-use-applysymbols.md | mcp-renames-dont-persist-use-applysymbols | 21
|
||||
ops-setup-decomp.md | extract the medium and verify against the committed manifest | 68
|
||||
wsl-disk-capped-75gb.md | wsl-disk-capped-75gb | 34
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# disc-dump-location
|
||||
|
||||
The legally-owned BFM USA BIN/CUE dump is at `/mnt/z/Storage/git/BFM-decomp/Brave Fencer Musashi (USA)/` (Windows `Z:\Storage\git\BFM-decomp\Brave Fencer Musashi (USA)`). Drew corrected me here on 2026-06-13 after I guessed a wrong `/mnt/z/Games/Emu/...` copy.
|
||||
|
||||
- **Track 1** `...(Track 1).bin` = 364,846,944 B — the MODE2/2352 data track holding the ISO9660 volume + every `.CD` file.
|
||||
- Tracks 2–4 are CD-DA AUDIO (each `(Track N).bin` = 150-sector INDEX 00→01 pregap + audio). The 3 `.DA` ISO files (ST01_13A.DA=Track2, ST01_13B.DA=Track3, DUMMY_DA.DA=Track4) point into them.
|
||||
- **Scope change 2026-06-13 (Drew):** stage ALL 4 tracks + the `.cue` to ext4 `disks/`, and extract the `.DA` files too. `extract.py` extracts them as raw 2352-byte/sector audio (sizes differ from the 2048-based ISO entry). Supersedes the earlier "Track 1 only / .DA out of scope" plan.
|
||||
- Per H2 the dump is read once, **not built against** — copied to ext4 `disks/` (gitignored) for fast iteration instead of reading repeatedly over the slow 9P `/mnt` bridge.
|
||||
- The raw dump is never committed (gitignore firewall, survives even the H1 relaxation in [[rom-content-git-policy]]).
|
||||
@@ -0,0 +1,71 @@
|
||||
# gate-main-only-with-gate-main
|
||||
|
||||
**`main` is gated ONLY by `tools/gate_main.py`** — baseline assert → substitute the whole slate →
|
||||
`make extract` → `make build` → compare SHA1, with a bisect when the batch fails. `parallel_gate` now
|
||||
REFUSES `binary == 'main'` in code, so this cannot be re-learned by accident.
|
||||
|
||||
**Why:** main's `make extract` runs the EXE-only `psyq_integrate` + `ld_interleave` steps, which
|
||||
REWRITE the linker script. `gate_stage` (and therefore `parallel_gate`, whose worker *is*
|
||||
`gate_stage`) builds incrementally, so it re-runs that on an already-rewritten `.ld`. S58 recorded the
|
||||
false-DIFF direction (105 competent main drafts thrown away). S71 hit the **false-PASS** direction,
|
||||
which is worse: `parallel_gate` reported "11 banked" on main, the merge was committed, and R22 came
|
||||
back 212/213 — the tree did not compile from clean, and once the declarations were reconciled it was
|
||||
still not byte-identical. All 11 re-gated individually: **11 of 11 REJECTED**.
|
||||
|
||||
**How to apply:**
|
||||
* Any main draft → `gate_main.py`. Run `--assert-baseline` first; it is cheap and it separates "my
|
||||
draft is wrong" from "the tree was already red".
|
||||
* **Count banks from the SOURCE** (the `INCLUDE_ASM` stub is gone), never from the tool's slate.
|
||||
`gate_main` printed "BANKED 5 of 6" when 4 had applied — `len(good)` is *what we decided to keep*,
|
||||
not *what was substituted*. Fixed, but the principle is general: this was the 4th tool in one
|
||||
session reporting a derived number as a measured one.
|
||||
* A draft that **contains its own `INCLUDE_ASM`** is a silent no-op — substituting it restores the
|
||||
stub, the build is trivially byte-identical, and it counts as a bank. `gate_main` refuses these now.
|
||||
* **A tool that wraps another tool inherits its refusals.** Every constraint documented on
|
||||
`gate_stage` binds `parallel_gate`, `harvest_verify`, and anything else that shells it — encode it
|
||||
as a refusal in the WRAPPER, not a paragraph in the callee.
|
||||
|
||||
**CORRECTED S72 (2026-09-02) — that "11 PROVEN gate-rejects" line was WRONG; NONE of them is a body
|
||||
reject.** The S71 re-gate ran through an ad-hoc script (`.run/S71_main_bisect.py`), not `gate_main.py`,
|
||||
so the decl pre-check never ran — and **all 11 are switch functions**. main had carried exactly ONE
|
||||
`.rodata` carve since Phase 7, so a drafted switch DOUBLE-EMITS its jump table, the image grows
|
||||
(+28/+52/+76/+84 measured) and ~332 symbols shift. Extending the carve to the contiguous span
|
||||
`0x80072A38-0x80072C70` banked `func_8001A114`, `func_8001AAD0`, `func_8001AF34` **byte-identical in
|
||||
14 s**; the other 8 sit in uncarved spans B/C and need `src/800.c` split. Cookbook §426/§427.
|
||||
|
||||
**S75 CORRECTION (2026-09-02) — THAT VERDICT LINE HAD A CLASS THAT COULD NOT FIRE.**
|
||||
`main_diff_locate.classify()` gained a `TABLE REJECT` case in S72 precisely because BODY/PLUMBING had
|
||||
mislabelled a table failure. On main it was **unreachable by construction**: it summed bytes whose
|
||||
object string contains `(.rodata)`, but main's `section_order` is `[.rodata, .text, .data, .bss]` — its
|
||||
rodata sits BELOW `.text` and its jump tables live in **`.data`** objects
|
||||
(`build/asm/data/63C4C.data.o(.data)`). It also demanded PURITY (`ro == outside`), so a few bytes of
|
||||
perturbed code dropped the verdict through to PLUMBING anyway.
|
||||
|
||||
Cost: **`SaveLoadRoutine` (1,165 ins — the largest open function in the project, 9.2% of all remaining
|
||||
work, carried as the §434 WALL) has a BYTE-IDENTICAL body.** Gated alone, twice, the tool said
|
||||
"PLUMBING REJECT … route to fix_arity_callers -> cast_self_callers"; the chain was run twice and fixed
|
||||
nothing, because the real split is **3,787 of 3,989 bytes (94.9%) in `.data` jump tables vs 202 (5.1%)
|
||||
in `.text`**, and the built image is **4 bytes SHORTER than retail** (§446's first diagnostic).
|
||||
It is a CARVE — and it sits in `src/800_b.c`, i.e. **span B, exactly where the S72 note above predicted
|
||||
the remaining 8 would sit.** Fixed: table bytes counted in `(.data)` OR `(.rodata)`, and the test is
|
||||
DOMINANCE (>=60%) not purity, naming which part is carve and which is declaration. NC: 5 of 6
|
||||
pre-existing verdict shapes unchanged. Cookbook §447.
|
||||
|
||||
**THE LAW, and it generalizes past this tool: a verdict class that CANNOT FIRE is worse than one that
|
||||
does not exist** — it converts "I don't know" into confident, specific, wrong advice that then
|
||||
consumes sessions. When a verdict names a subsystem, check that subsystem owns the MAJORITY OF THE
|
||||
BYTES before acting on it.
|
||||
|
||||
**ALSO S75: gate main with `--no-propagate`.** `gate_stage`'s tail runs
|
||||
`dedup_propagate --auto-from <bin>`, which sweeps the WHOLE binary rather than the function just
|
||||
banked; a binary with an unswept pile stalls the gate 30+ minutes (`ov_SC01_005` held 557). Drew's
|
||||
decision 2026-09-02: leave the ~12,000-copy hygiene backlog (all already matched, orthogonal to
|
||||
completion %) and gate `--no-propagate` by default. See [[dedup-backlog-leave-it]].
|
||||
|
||||
**A main gate now says WHERE, not just that.** `gate_main` preserves the red image + map under
|
||||
`.run/gate_main_fail/` BEFORE the R40 baseline control rebuilds over them (that ordering bug is why
|
||||
nobody could ever localize a main failure), then prints **BODY REJECT / PLUMBING REJECT / MIXED** via
|
||||
`tools/main_diff_locate.py`. **Read that line before recording any main verdict.**
|
||||
|
||||
Related: [[standalone-match-is-not-bankable]] · [[verify-blast-radius-not-just-defect]] ·
|
||||
[[silently-narrowed-tool-scope]] · [[check-against-a-known-true-case]] (cookbook §414)
|
||||
@@ -0,0 +1,21 @@
|
||||
# mcp-renames-dont-persist-use-applysymbols
|
||||
|
||||
**Fact (2026-09-04, P31 S78):** 47 renames made through the headless GhidrAssistMCP server
|
||||
(`batch_rename`/`rename_symbol`, all reported success) were GONE after `tools/ghidra_mcp_stop.sh`
|
||||
("Save succeeded", DB grew 9.9→10.4 MB). R9's read-only re-open caught it. Cause not isolated (single
|
||||
instance, normal stop sequence; Phase 3 had verified the same flow). The fix that worked first time:
|
||||
`tools/ghidra_apply_symbols.sh [PROG] [symbols…]` → `tools/ghidra_scripts/ApplySymbols.java`, a headless
|
||||
postScript that mirrors `config/symbols.us.txt` into the program with a real save (73 renamed,
|
||||
R9-verified ×4). Also: gate worktrees carry no `.run/obj40`, so main's LINKED (SDK-object) build path is
|
||||
only ever checked by an in-tree `make build BINARY=main` — it had been red at HEAD for a day unnoticed.
|
||||
|
||||
**Why:** the curated text file is the source of truth (R15); an MCP write that never persisted looks
|
||||
identical to one that did until a fresh open reads the DB (R9). A gate that always takes the fallback
|
||||
path is blind to the path the contract cares about (R34).
|
||||
|
||||
**How to apply:** for symbol renames, edit `config/symbols.us.txt` (no `name:` tokens in comments —
|
||||
splat parses them as attributes), run `lint_symbol_refs.py` and read its WHOLE output (verbatim
|
||||
`__asm__` bodies spell `\tfunc_X`), then `ghidra_mcp_stop.sh` → `ghidra_apply_symbols.sh` →
|
||||
`ghidra_mcp_verify.sh <addr> <name>`. After any change to `psyq_identify`/`psyq_integrate`/the splat
|
||||
yaml: in-tree `make build BINARY=main` WITH `.run/obj40`, then the fresh-extract fallback WITHOUT it.
|
||||
See [[exonerate-the-instrument]], [[check-against-a-known-true-case]].
|
||||
@@ -0,0 +1,34 @@
|
||||
# wsl-disk-capped-75gb
|
||||
|
||||
The WSL2 disk (`/dev/sdd`, `ext4.vhdx`) was resized from WSL's 1 TB default down to
|
||||
**75 GB (73 GiB usable)** on 2026-08-29. As of then: 38 GB live, ~32 GB free.
|
||||
This is a HARD ceiling — ext4 cannot grow past it.
|
||||
|
||||
**Why it was done:** the vhdx had bloated to 111.6 GiB while holding only 38 GB of
|
||||
live data, leaving C: with 11 GB free. Root cause: WSL creates a 1 TB ext4 filesystem
|
||||
inside a dynamically-growing vhdx, and ext4's Orlov allocator deliberately places each
|
||||
new *directory* in a block group with above-average free space. The `.run/wave_*`
|
||||
pattern (hundreds of new top-level dirs) scattered data across 8192 block groups —
|
||||
live data was smeared over 820 GiB of address space in 1363 groups. A dynamic vhdx
|
||||
can only release whole 32 MB blocks, and nearly every touched block still held some
|
||||
live data, so `compact vdisk` reclaimed ~7 GB of a possible 66. Zero-fill and sparse
|
||||
VHD both fail or are unsafe here. `wsl --manage <distro> --resize` was the fix:
|
||||
resize2fs relocated 33 GB down from above the boundary and packed data into 553 groups.
|
||||
Result: vhdx 111.6 -> 53.3 GiB, C: 11.2 -> 69.9 GB free.
|
||||
|
||||
**Why it matters:** `.run/` is ~20 GB and grows every wave. With only ~32 GB of
|
||||
headroom, a big fleet run can now fail with ENOSPC instead of the disk silently
|
||||
growing. That failure will look like a mysterious mid-wave build error.
|
||||
|
||||
**How to apply:**
|
||||
- Watch `df -h /` before launching large waves; prune old `.run/wave_*` when tight.
|
||||
- The vhdx will still drift 53 -> 75 GiB over time (spreading is confined, not fixed).
|
||||
That is expected, not a new problem.
|
||||
- Reclaim recipe (works now that data is packed): `sudo fstrim -av` -> `wsl --shutdown`
|
||||
-> diskpart `compact vdisk`. Do NOT bother with zero-fill.
|
||||
- Need more room? GROWING is the supported direction and is safe:
|
||||
`wsl --shutdown` then `wsl --manage Ubuntu-24.04 --resize 150GB`.
|
||||
- Sparse VHD (`--set-sparse`) is gated behind `--allow-unsafe` by Microsoft for
|
||||
data-corruption risk — do not use it.
|
||||
|
||||
Related: [[no-tmp-project-local-data]] (.run/ is the gitignored runtime scratch dir).
|
||||
@@ -119,3 +119,11 @@
|
||||
<!-- G63 | Outward text is written by a person | | active | | | source: decomp-architect -->
|
||||
<!-- G64 | No automated traffic against community infrastructure | | active | | | source: decomp-architect -->
|
||||
<!-- G65 | Agents assist; a person owns | | active | | | source: decomp-architect -->
|
||||
|
||||
L1 | offline-tooling-first | legacy,memory | active | legacy memory offline-tooling-first.md
|
||||
|
||||
L2 | lever-removal-is-a-tracked-series | legacy,memory | active | legacy memory lever-removal-is-a-tracked-series.md
|
||||
|
||||
L3 | decomp-accelerator-ledger | legacy,memory | active | legacy memory decomp-accelerator-ledger.md
|
||||
|
||||
L4 | verify-blast-radius-not-just-defect | legacy,memory | active | legacy memory verify-blast-radius-not-just-defect.md
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# L1 — offline-tooling-first
|
||||
id: L1 · group: - · status: active · tags: legacy,memory · origin: legacy memory offline-tooling-first.md · added: 2026-09-29
|
||||
|
||||
**Standing goal (Drew, 2026-07-21): get as much as possible working as offline tooling.** When a
|
||||
recovery, diagnosis, or integration step is *computable*, it belongs in a deterministic tool that runs
|
||||
with zero tokens on every future draft — not in an agent prompt, and not in a search.
|
||||
|
||||
**Why:** the measured economics keep pointing the same way. Phase 15: a 50-agent wave added +0.36% while
|
||||
deterministic recovery added +2.67% for ~0 agent tokens. Phase 29 (2026-07-21): the permuter's problem was
|
||||
*targeting*, not a missing transform — ~92% of its CPU was aimed at residuals a search provably cannot
|
||||
close, fixed for free by a deterministic classifier ([[matching-is-solved-integration-is-the-bottleneck]]).
|
||||
Every hour of agent drafting is spent once; every ladder stage is spent once and paid forever.
|
||||
|
||||
**The two engines — keep them separate:**
|
||||
1. **Deterministic recovery** (`tools/gate_stage.py`'s ladder): computable fixes — decl/arity/cast
|
||||
reconciliation, type-lift, jtbl isolate+re-carve. Applied always, free, byte-gate arbitrated.
|
||||
2. **Search** (decomp-permuter / ILS): only for residuals that are NOT computable — regalloc and
|
||||
schedule permutations where the answer must be explored.
|
||||
Putting a computable fix into the search is a category error: it burns CPU rediscovering a derivable
|
||||
answer. And per cookbook §60b, raising a search-closer's yield is at least as often about *refusing it
|
||||
unreachable work* as widening its mutation set.
|
||||
|
||||
**How to apply:** when a draft fails to bank, ask "is this residual computable?" before reaching for
|
||||
agents or the permuter. If yes → a ladder stage (and check whether the logic already exists elsewhere —
|
||||
`normalize_self_decls` and jtbl auto-isolate both existed in `family_sweep`/`jtbl_family_bank` while
|
||||
`gate_stage` lacked them; R33 says one implementation, two callers). Any ladder stage that mutates SHARED
|
||||
state must undo by snapshot-restore, never an inverse transform, and be verified fleet-wide (R22) — a
|
||||
single-binary gate cannot validate a fleet-wide edit (cookbook §61; it cost 138 broken binaries once).
|
||||
Track the LLM-free fraction and make raising it the objective (`docs/hindsight-study.md` §7,
|
||||
`tools/burndown.py`).
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# L2 — lever-removal-is-a-tracked-series
|
||||
id: L2 · group: - · status: active · tags: legacy,memory · origin: legacy memory lever-removal-is-a-tracked-series.md · added: 2026-09-29
|
||||
|
||||
Drew (2026-09-09, mid-Phase-36): the pins and compiler hints are not just work to finish — **their count over time is a
|
||||
deliverable**. Keep `docs/levers.md` current after **every task that changes the count**, with
|
||||
`tools/lever_progress.py --snapshot "<task>"` (appends a milestone row to `docs/lever-progress.tsv` and re-renders the
|
||||
document's generated block; `--check` refuses a stale series). Mirror the story-relevant numbers into
|
||||
`phase-ends/CURRENT_PHASE.md` as the phase goes, so the retrospective is built from the record and not from memory.
|
||||
|
||||
Four audiences, all named by Drew: the **post-100% chart**, the **project story**, the **wiki** (a Levers page), and the
|
||||
**`decomp-architect/` package** — which needs the taxonomy plus an answer to *"what should we have done from day one to stop
|
||||
this creeping up on us post-100%, or is leaving it to a post-100% cleanup actually optimal?"*
|
||||
|
||||
**Why:** the only phase that ever counts the levers is the phase that removes them, so if the series is not captured while
|
||||
the work happens it cannot be reconstructed afterwards — a census is a moment. The measured answer so far (P36): **38% of
|
||||
the class A/B population came off with no understanding at all** (strip, compile, compare), which is the evidence for the
|
||||
day-one rule *ban the silence, not the lever* — a lever is allowed but is a marked, ledgered, published debt from the first
|
||||
bank, with a one-compile bank-time trial that would have refused a third of them where the context was still hot.
|
||||
|
||||
**How to apply:** at every task close run the census then `lever_progress --snapshot`; keep §5 of `docs/levers.md` (the
|
||||
prevent-vs-defer argument) written from the generated numbers, never typed; feed each new rung/recipe and each measured
|
||||
yield into §4. Related: [[matching-cookbook]] (§454 carries the mechanism), [[decomp-accelerator-ledger]],
|
||||
[[phaseend-verbosity-for-the-retrospective]], [[project-endgame-deliverables]].
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
# L3 — decomp-accelerator-ledger
|
||||
id: L3 · group: - · status: active · tags: legacy,memory · origin: legacy memory decomp-accelerator-ledger.md · added: 2026-09-29
|
||||
|
||||
Drew (2026-08-07): we are building a **Claude Code decomp workflow** to reuse after BFM ships. So
|
||||
whenever something is found that would have made a lot of *previous* work much faster had we known it
|
||||
sooner, record it — what it is, when we found it, when we *could* have, and what it would have saved —
|
||||
in `docs/accelerators.md`. A new decomp project should get that wisdom on day one instead of at phase 23.
|
||||
|
||||
**Why:** this project repeatedly found its biggest levers late (the byte-gate harvest at phase 12, dedup
|
||||
propagation at 11–15, the gcc codegen map at 23, the tracker's addressing blind spot at 30). The
|
||||
per-phase PhaseEnds record *what happened*; they do not answer "what should phase 1 of the NEXT game
|
||||
do differently." That is a separate, deliberately-maintained artifact.
|
||||
|
||||
**How to apply:** when a discovery lands, ask "would this have changed earlier work?" If yes, add an
|
||||
entry the same session (R30 timing). Distinguish honestly between a lever that was *available* earlier
|
||||
and one that structurally could not exist yet (needed the fleet onboarded, the compiler pinned, etc.) —
|
||||
the second kind belongs in the ledger too, marked, because its *prerequisite* is the real advice.
|
||||
|
||||
Feeds [[project-endgame-deliverables]] (the public "how to AI-decomp" wiki) alongside
|
||||
`docs/decision-log.md` (R31, the why-behind-pivots).
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# L4 — verify-blast-radius-not-just-defect
|
||||
id: L4 · group: - · status: active · tags: legacy,memory · origin: legacy memory verify-blast-radius-not-just-defect.md · added: 2026-09-29
|
||||
|
||||
**Verify the BLAST RADIUS, not just the DEFECT.** (Phase 26, 2026-07-14 — I got this wrong in front of Drew.)
|
||||
|
||||
A coverage audit reported that `progress.py` under-counted ~243k instructions because `classify()` reads a K&R
|
||||
definition as a forward declaration. I did the R14 thing — reproduced the mechanism against the bytes, confirmed
|
||||
it was real, measured 400 banked instances in that shape — and then told Drew our headline numbers had been
|
||||
under-reporting our progress.
|
||||
|
||||
**Wrong.** The headline metrics come from `weighted_metrics()`, which never calls `classify()` at all: it tests
|
||||
"is this function still an `INCLUDE_ASM` stub?", so it is structurally immune to the bug. The published
|
||||
instruction-weighted and distinct-code numbers were correct all along; only a secondary function-count report was
|
||||
wrong.
|
||||
|
||||
**Why:** *"this tool is broken"* and *"this number is wrong"* are different claims requiring different evidence.
|
||||
A confirmed mechanism proves nothing about consequence. Before reporting impact, trace the defect to the actual
|
||||
consumer and check whether that consumer is even on the affected path.
|
||||
|
||||
**How to apply:**
|
||||
- After confirming a defect, ask *"who consumes this, and does the consumer use this code path?"* — then verify
|
||||
THAT, not the defect, before quoting an impact number to the owner.
|
||||
- **A null result where you predicted a large effect is a refutation — chase it, do not wave it off.** The fix
|
||||
moved the numbers by +376 instructions when I had predicted +190,000. That gap was the whole story and it
|
||||
would have been trivially easy to dismiss as noise (or worse, to report as "the fix worked, the numbers moved").
|
||||
- Do not amplify a sub-agent's impact claim (R14) — the auditor conflated "classify() is blind" with "the metrics
|
||||
are wrong", and I propagated it as fact while lecturing about unverified oracles.
|
||||
|
||||
Related: [[derive-from-invariants-not-reparsing]].
|
||||
Reference in New Issue
Block a user