mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
docs(cookbook): §139 — a gate that greps for verdicts must assert 1:1 accounting
The wave-6 gate printed BANKED 5 / FAILED 1 over SIXTEEN drafts and nothing said so. Captured with
the three corollaries that outlive the bug (R30 — written in the session that produced them):
(a) the byte-gate is a perfect CORRECTNESS oracle and a NULL COVERAGE oracle (R34 again), so every
wave-level tally is a coverage claim and needs its own assertion;
(b) a pipeline's exit status is the LAST command's — "family_sweep ... | tail" hid a non-zero exit
in this same session; use pipefail/PIPESTATUS or the tail IS the error handler;
(c) a reverted CONFIG needs a re-extract before the next measurement means anything (the Phase-20
R22 corollary; skipping it made three genuinely-banked functions read as failures).
Plus the inverse-lookup trap: a just-banked head LEAVES its family's members list and becomes
exemplar.kind='matched', so a member-list lookup reports "no family" for exactly the heads you just
banked. Distinct from §138 rule 4, which governs target SELECTION.
Index regenerated: 393 sections, 3 new symptom keys.
This commit is contained in:
+11
-4
@@ -2,7 +2,7 @@
|
||||
|
||||
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
|
||||
>
|
||||
> `docs/matching-cookbook.md` is ~716 KB / 390 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
|
||||
> `docs/matching-cookbook.md` is ~716 KB / 393 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
|
||||
|
||||
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
- **§138** — The propagation lanes: a gate refusal is a DECLARATION, and which lever you owe depends on blast radius <sub>L9405</sub>
|
||||
- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is <sub>L9555</sub>
|
||||
|
||||
### jump tables & switches (25)
|
||||
### jump tables & switches (26)
|
||||
|
||||
- **§8** — rodata island (compiler jump tables) — the `.data→.rodata→.data` sandwich (Phase 7) <sub>L320</sub>
|
||||
- **§8a** — rodata island in a flat OVERLAY — the tail sandwich, per matched jr-function (Phase 26 — PoC PROVEN) <sub>L342</sub>
|
||||
@@ -254,6 +254,7 @@
|
||||
- **§131** — The jtbl OVER-SPAN: `sltiu N` is ground truth in BOTH directions, and the zero-word rule only guards one (P30 S28, `func_80191C50`) <sub>L8526</sub>
|
||||
- **§132** — The `JR-PAIR-IN-ONE-O0-OBJECT` "wall" was TWO instrument defects: a merged-double span the carve could not see, and a truncated object no rule deleted (P30 S29, `func_8013B83C` + `func_8013BD74`) <sub>L8563</sub>
|
||||
- **§132b** — When the span's already-matched owner is ITSELF multi-switch: `--span-rel` (P30 S1, `func_8014032C`) <sub>L8653</sub>
|
||||
- **§139** — A GATE THAT GREPS FOR VERDICTS MUST ASSERT 1:1 ACCOUNTING; and a `--src` filter must not survive a carve (P30 S38, wave 6: 10 of 16 drafts vanished) <sub>L9584</sub>
|
||||
|
||||
### optimisation level (-O0/-O2) (12)
|
||||
|
||||
@@ -379,7 +380,7 @@
|
||||
- **§3-The** — declaration surface (integration, not codegen) <sub>L8931</sub>
|
||||
- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is <sub>L9555</sub>
|
||||
|
||||
### build graph, splat & the harness (95)
|
||||
### build graph, splat & the harness (96)
|
||||
|
||||
- **§4** — Flag/toolchain gotchas <sub>L190</sub>
|
||||
- **Build** — mechanism — per-file opt override (splat resegmentation) <sub>L288</sub>
|
||||
@@ -476,6 +477,7 @@
|
||||
- **§138** — The propagation lanes: a gate refusal is a DECLARATION, and which lever you owe depends on blast radius <sub>L9405</sub>
|
||||
- **§134** — again, in a second tool — and the waiter rule corrected <sub>L9516</sub>
|
||||
- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is <sub>L9555</sub>
|
||||
- **§139** — A GATE THAT GREPS FOR VERDICTS MUST ASSERT 1:1 ACCOUNTING; and a `--src` filter must not survive a carve (P30 S38, wave 6: 10 of 16 drafts vanished) <sub>L9584</sub>
|
||||
|
||||
### process, measurement & doctrine (53)
|
||||
|
||||
@@ -533,7 +535,7 @@
|
||||
- **§136j** — The failure MIX flips with function size (measured across four bands, one session) <sub>L9292</sub>
|
||||
- **Rank** — the lane by measured concentration, not by class count <sub>L9471</sub>
|
||||
|
||||
### (unbucketed — title matched no symptom vocabulary) (110)
|
||||
### (unbucketed — title matched no symptom vocabulary) (112)
|
||||
|
||||
- **§3-How** — to use this <sub>L30</sub>
|
||||
- **§1** — Idiom catalog (asm pattern → C that produces it) <sub>L39</sub>
|
||||
@@ -645,6 +647,8 @@
|
||||
- **§3-The** — triage, cheapest first <sub>L9411</sub>
|
||||
- **THREE** — carry variants hide in one "CARRY-FIXABLE" bucket — and they need different fixes <sub>L9480</sub>
|
||||
- **STEP** — 0 of sibling-first: grep `src/` for a distinctive LITERAL from the `.s` <sub>L9536</sub>
|
||||
- **§3-The** — generalisation — three corollaries worth more than the bug <sub>L9616</sub>
|
||||
- **§3-And** — the inverse-lookup trap, same session <sub>L9633</sub>
|
||||
|
||||
|
||||
## All sections, in order
|
||||
@@ -1039,3 +1043,6 @@
|
||||
- **§134** — again, in a second tool — and the waiter rule corrected <sub>L9516</sub>
|
||||
- **STEP** — 0 of sibling-first: grep `src/` for a distinctive LITERAL from the `.s` <sub>L9536</sub>
|
||||
- **Reconciling** — a gate-refused draft: which way you edit depends on WHERE the TU's decl is <sub>L9555</sub>
|
||||
- **§139** — A GATE THAT GREPS FOR VERDICTS MUST ASSERT 1:1 ACCOUNTING; and a `--src` filter must not survive a carve (P30 S38, wave 6: 10 of 16 drafts vanished) <sub>L9584</sub>
|
||||
- **§3-The** — generalisation — three corollaries worth more than the bug <sub>L9616</sub>
|
||||
- **§3-And** — the inverse-lookup trap, same session <sub>L9633</sub>
|
||||
|
||||
@@ -9578,3 +9578,69 @@ source position (`\.[ch]:\d+`), minus the known SHB macro noise.
|
||||
Symptom line for the index: **"a propagation/extend lane plans N and banks 0"** — read each failure's
|
||||
compiler error, bucket by named symbol, and apply the lowest-radius byte-neutral alias; a `volatile`
|
||||
in the host TU and a fleet decl carrying a promoting param are the two that masquerade as codegen.
|
||||
|
||||
---
|
||||
|
||||
## §139 — A GATE THAT GREPS FOR VERDICTS MUST ASSERT 1:1 ACCOUNTING; and a `--src` filter must not survive a carve (P30 S38, wave 6: 10 of 16 drafts vanished)
|
||||
|
||||
**The symptom** was a gate run that looked ordinary: `BANKED 5 / FAILED 1` — printed over **16**
|
||||
drafts. Six verdicts for sixteen inputs, and nothing said so. Nine of the ten missing drafts were
|
||||
claiming MATCH.
|
||||
|
||||
**The chain, both ends of which were ours:**
|
||||
|
||||
1. `harvest_verify._reload_corpus()` exists, by its own docstring, to *"re-derive the stub map after
|
||||
an isolation moved a stub to a new TU."* It then re-applied the `--src` filter (`x.path == a.src`)
|
||||
to the reloaded map — **deleting the very stub it had just followed to its new home.** Line 136 of
|
||||
that same file already labels `--src` *"an optional filter, not a location oracle"*; `_reload_corpus`
|
||||
was the one place treating it as one. Downstream:
|
||||
`_stubs` loses `fn` → `render()` raises `KeyError` → **uncaught** → `_jtbl_restore(snap)` never
|
||||
runs → **the carve is stranded in `config/` + `src/`** → and every *later* group in the same gate
|
||||
run then builds against a tree the earlier crashes mutated.
|
||||
2. The gate driver (`.run/s6f_gate.py`) captured the child's output, grepped it for `VERIFIED:` and
|
||||
`FAILED :`, and **never looked at the returncode.** "Neither line present" was booked as nothing
|
||||
at all, and the tally printed clean.
|
||||
|
||||
**The fixes are both structural, not cosmetic:**
|
||||
- the filter never drops a draft under verification, wherever it now lives, plus an R32 loud report
|
||||
if a working stub vanishes across a reload (which also repairs `_touched`/`baseline` — a carved fn
|
||||
missing from `_stubs` left its new TU *unbaselined*, so the revert path could not have restored it
|
||||
either);
|
||||
- the gate asserts `banked + failed + no-verdict == drafts`, prints the child's rc and output tail for
|
||||
anything unaccounted, and **exits non-zero** — because a crashed child may have stranded a carve, so
|
||||
it must never look like success.
|
||||
|
||||
**Proof it was not cosmetic:** `func_8017EA84` (579 ins) carves and banks BYTE-IDENTICAL under the
|
||||
fixed path. The old tool reported it as *nothing*.
|
||||
|
||||
### The generalisation — three corollaries worth more than the bug
|
||||
|
||||
**(a) The byte-gate is a perfect CORRECTNESS oracle and a null COVERAGE oracle (R34, again).** It
|
||||
cannot tell you about work it was never asked to do. Every wave-level tally is a *coverage* claim,
|
||||
and coverage claims need their own assertion. **Any driver that classifies N inputs must prove it
|
||||
emitted N verdicts.**
|
||||
|
||||
**(b) A pipeline's exit status is the LAST command's.** In the same session `family_sweep … | tail -30`
|
||||
hid a non-zero exit (`--only` wants comma-separated; space-separated args were rejected). Use
|
||||
`set -o pipefail` and read `PIPESTATUS`, or the tail *is* the error handler.
|
||||
|
||||
**(c) A reverted CONFIG needs `make extract`, not just the revert.** After undoing the stranded
|
||||
carves I re-extracted one overlay of sixteen; the next gate run read three genuinely-banked functions
|
||||
as failures because they were building against asm/ still partitioned by the old carve. This is the
|
||||
Phase-20 R22 corollary, and it costs a whole gate cycle every time it is skipped. **A gate result
|
||||
measured against stale asm is not a measurement (R35).**
|
||||
|
||||
### And the inverse-lookup trap, same session
|
||||
|
||||
Propagating a **just-banked** head, `family_hseq.json` moves it **out of its family's `members` list
|
||||
and into `exemplar` with `kind: "matched"`.** A lookup that searches the member list for the head
|
||||
therefore returns *"no family"* for every head — while `family_sweep` enumerates those same families
|
||||
from the same file seconds earlier. Key on the `exemplar` **(ov, addr) pair** (two families can share
|
||||
an exemplar address in different overlays). This does **not** contradict §138 rule 4 ("never rank off
|
||||
the exemplar field"): that rule governs *target selection*, where an exemplar pointing at a banked
|
||||
instance HIDES a family; here the freshly-banked exemplar is precisely what you are looking the
|
||||
family up BY.
|
||||
|
||||
Symptom lines for the index: **"a gate reports fewer verdicts than it had drafts"** · **"a tool
|
||||
reports NO FAMILY for a head another tool just enumerated"** · **"a gate result got worse after a
|
||||
revert"** (→ re-extract, then re-measure).
|
||||
|
||||
Reference in New Issue
Block a user