diff --git a/phase-ends/logs/Phase11.md b/phase-ends/logs/Phase11.md index 93dd656..0ab8ab6 100644 --- a/phase-ends/logs/Phase11.md +++ b/phase-ends/logs/Phase11.md @@ -156,3 +156,72 @@ on it, exactly as the maspsx `#nop` fix did. merely *READS* a callee-saved register neither written nor saved earlier finds 11 more rows (8 above the ceiling), but the control fires on **2 of 493 registered regions**, so it is **not** disjoint and was **not** implemented. Recorded as a candidate requiring refinement, not applied. + +## Cycle 1 — the ceiling breaks three times, and a content-free frame lever + +**494 distinct bodies / 503 regions** (from the 484 / 493 baseline). **Three bodies now sit above the old +244 B ceiling**, from two independent workers: `0x8009F6A0` (248 B, worker D), `0x80036134` (248 B, +worker C), `0x800308C4` (264 B, worker D — the new corpus maximum). The dispatch-artefact verdict is +settled **by result rather than by inference**. + +### The lever that broke it, and its extension + +**Finding 59, instance 1** (`0x8009F6A0`): the local buffer had to be `int t[3][4]`, only columns 0..2 +used — **not** `int t[9]`. The **4-word row stride is byte-load-bearing**: it moves the 2nd and 3rd +triples to `0x10`/`0x20`, makes the frame **48 B instead of 40 B**, and leaves the unused `0x0C`/`0x1C` +slots the original shows. Four spellings: nine `short` locals (100 B, cc1 drops the sign extension), nine +`int` locals (100 B, right signedness, still no frame), `int t[9]` (248 B, **19 differing bytes, the +first at the frame adjustment itself**), then `int t[3][4]` → MATCH. + +**Finding 59, instance 2** (`0x800308C4`, 264 B): **8 words from a match and all eight were the frame** — +the `addiu sp,sp,-96` prologue and its mirror epilogue, with **56 of 64 words already byte-identical** +including every call site, delay slot and register. The missing 8 bytes are an **unreferenced array +local**, and the mechanism is measured across five spellings: + +| trailing declaration | vars | frame | result | +|---|---|---|---| +| (none) | 56 | 88 | DIFF, 8 words | +| `int pad0, pad1;` (2 unreferenced **scalars**) | 56 | 88 | DIFF — **cc1 gives unreferenced scalars no home** | +| `short t[12]` (one 24-byte array) | 56 | 88 | DIFF | +| `int pad[2]` (unreferenced 8-byte **array**) | 64 | **96** | **MATCH** | +| `short pad[4]` (unreferenced 8-byte **array**) | 64 | **96** | **MATCH** | + +**cc1 allocates stack space for an unreferenced ARRAY local but not for an unreferenced SCALAR local.** +The 8 bytes are **size-load-bearing and content-free** — any 8-byte array reproduces them. Recorded as a +**limit of the reconstruction, not a recovered fact**, and marked as such in the file header. + +**AMENDED RULE (cookbook 59): when the residual IS the frame, vary the local aggregate's declaration in +THREE directions — element type, row stride, AND total size.** Two instances, two different directions, +one diagnostic: *correct length + right instruction multiset and order + residual concentrated on the +frame adjustment and every sp-relative offset ⇒ suspect a local aggregate's shape, not the control flow.* + +### Cost above the ceiling, measured by two workers + +| band | worker C | worker D | +|---|---|---| +| >244 B | 1 row attempted, 1 matched, **11 compile attempts** | 2 rows attempted, 2 matched, **4 and 6 spellings** | +| ≤244 B | 2 attempts, 2 attempts, ~6 attempts (3 rows) | paired control pending | + +Neither of D's matches was scheduler-bound, allocation-bound or harness-bound — both failed in exactly one +place and both were closed by a **declaration change**. That is the "how tractable" answer at n=3: **the +band is tractable, and the cost is real but not a grind.** + +### Fail-fast fixes to `sf3_merge`, both triggered by real worker files + +- A claim row with an unknown override key (`md5=...`) used to **merge silently** and only fail later at + the gate with `unknown override key 'md5'`. `sf3_merge` now **validates override keys at merge time** + and rejects the row with a message naming the valid keys and pointing at `report.tsv`. Generalised as + cookbook 62: **validate at the earliest stage that can see the error**, because a late failure is + diagnosed as a gate problem rather than a claim problem. +- A bare header row is now rejected with *"looks like a column HEADER"* rather than a confusing + `not a hex address: 'start'`. +- A lone `-` in the override column is accepted as "no overrides", matching the absent-value convention + the other tracked tables use. + +Suite 237 → 246 tests. The candidate gate caught the bad row; the tracked registry was never touched. + +### Operational note broadcast to all workers + +**Ranks are not stable — key dispatch by address.** Worker D's row moved from rank 592 to 578 mid-session +because the worklist regenerates and the partitions refilter after every merge. **Addresses are stable; +ranks are not**, and rank-keyed scratch tooling drifts silently onto a different row.