diff --git a/docs/MATCHING_COOKBOOK.md b/docs/MATCHING_COOKBOOK.md index cdc917e..2651393 100644 --- a/docs/MATCHING_COOKBOOK.md +++ b/docs/MATCHING_COOKBOOK.md @@ -1800,11 +1800,28 @@ signal is: Worker A scanned its 256 rows and got 11 first-instruction hits, of which **only `0x800C3490`** trips the real rule. -**Implemented as `./tools/sf3_rank --fragments`, which scans any partition set.** Measured across -all four partitions it finds **5 suspects**; measured against the **555 registered regions it flags -2** (`0x800923E8`, `0x80099DC4`), so it is **advisory, not an exclusion** — sufficient-but-not-complete -in exactly the way the trapping check is. **A hit means "read this before spending a spelling", never -"skip it".** +**Implemented as `./tools/sf3_rank --fragments`, which scans any partition set.** + +**WORKER B THEN ADJUDICATED ITS OWN HIT AND MADE THE CHECK DISJOINT.** The first version fired on +any nonzero `sp` offset and flagged **2 of the 555 registered regions**. Worker B read `0x800B704C` +before committing and showed it is a **legal frameless leaf with EIGHT arguments**: in o32 the +callee's `sp` is unchanged at entry, so **`sp+16..sp+28` IS the caller's outgoing area — arguments +4–7** — and reading it before any `addiu sp,sp,-N` is exactly what a frameless >4-argument leaf looks +like. Its evidence: exactly one `jr ra`, zero `jal`, zero `addiu sp,sp,-N`, zero `sw ra`/`lw ra` +across all 324 bytes, and no callee-saved register touched. + +**So the incoming argument area (`sp+0..sp+31`) is excluded**, and only a **negative** offset or an +offset **beyond** the 8-argument area is a real fragment. With that qualification: + +| | before | after | +|---|---|---| +| registered regions flagged | 2 of 555 | **0 of 555** | +| suspects across four partitions | 5 | **1** | + +**The check is now disjoint from the corpus** and the one remaining suspect is worker A's +`0x800C3490`. This is the cleanest example in the phase of a *worker adjudicating a tool's output +rather than obeying it* — B was told "advisory, do not skip", read the row anyway, and its +adjudication is what turned a noisy heuristic into a precise one.** **The value is the reading phase, not the match:** a fragment costs a full structural derivation and can never close, so flagging it saves a worker's whole reading budget. diff --git a/tools/sf3_rank b/tools/sf3_rank index 8a6b4cc..5aeec03 100755 --- a/tools/sf3_rank +++ b/tools/sf3_rank @@ -90,10 +90,17 @@ def fragment_reason(insns: list[int]) -> str: 0x800C3470. It is a shared/jump-target block Ghidra promoted to a function, so it is inside no region and nobody can match it standalone. - ADVISORY, NOT AN EXCLUSION: measured against the 555 registered regions this flags - **2** of them (`0x800923E8`, `0x80099DC4`, both "first insn touches sp+16"), so it is - sufficient-but-not-complete in exactly the way the trapping check is. Treat a hit as - "read this before spending a spelling", never as "skip". + QUALIFIED BY WORKER B, WHICH MADE IT DISJOINT. The first version fired on any nonzero + `sp` offset and flagged 2 of the 555 registered regions (`0x800923E8`, `0x80099DC4`). + Worker B adjudicated its own hit `0x800B704C` and showed it is a **legal frameless leaf + with eight arguments**: in o32 the callee's `sp` is unchanged at entry, so `sp+16..sp+28` + IS the caller's outgoing area -- arguments 4-7. Reading it before any `addiu sp,sp,-N` is + exactly what a frameless >4-argument leaf looks like. + + So the incoming argument area (`sp+0..sp+31`) is excluded, and only a **negative** offset + (a frame slot below an unmoved `sp`) or an offset **beyond** the 8-argument area is a real + fragment. With that qualification the check is **disjoint from the corpus: 0 of 555 + registered regions**, and the suspects across all four partitions drop from 5 to 1. """ if not insns: return "empty" @@ -104,7 +111,16 @@ def fragment_reason(insns: list[int]) -> str: immediate = word & 0xFFFF if opcode in (0x23, 0x2B, 0x0F, 0x20, 0x24, 0x25, 0x28, 0x29, 0x2C, 0x2D, 0x2E, 0x3F): if (rs == 29 or rt == 29) and immediate != 0: - return f"first instruction touches sp+{immediate}" + offset = immediate - 0x10000 if immediate >= 0x8000 else immediate + # In o32 the callee's `sp` is unchanged at entry, so the incoming argument + # area sits at sp+0..sp+28 (args 0-3 live in a0-a3 but their home slots are + # there; args 4-7 are passed at sp+16..sp+28). Worker B adjudicated + # 0x800B704C as a legal frameless leaf with EIGHT arguments whose first + # instruction is `lw t0,16(sp)` -- so reading that area at entry is legal + # and must not fire. Only a NEGATIVE offset (a frame slot below an unmoved + # sp) or an offset beyond the 8-argument incoming area is a real fragment. + if offset < 0 or offset >= 32: + return f"first instruction touches sp{offset:+d} (outside the incoming arg area)" used = {rs, rt} if opcode == 0: used.add((word >> 11) & 0x1F)