diff --git a/phase-ends/logs/Phase10.md b/phase-ends/logs/Phase10.md index fb4b4ff..f63d94d 100644 --- a/phase-ends/logs/Phase10.md +++ b/phase-ends/logs/Phase10.md @@ -405,3 +405,88 @@ remedy it then. `main`. The 13 untracked `src/*.c` files present at push time are workers' in-progress drafts and near-match negatives, which are deliberately not committed and therefore not published. + +## Cycle 1 — merges 16-18, the size-band experiment, and two worker self-audits (2026-09-24) + +**456 distinct bodies / 465 regions** (from 400 / 409) — +56 of the +75 milestone. + +### The size-band experiment (worker C) — the phase's cleanest measurement + +Worker C produced a controlled comparison: same worker, same levers, same day, with the size band as the +only variable. + +| band | attempts per row | +|---|---| +| ≤200 B | **1, 1, 1, 2** (four consecutive rows) | +| 200 B–800 B | **1-in-12** | + +That confirms the re-rank at the row level, after the corpus-level measurement (matched median 48 bytes, +454/459 ≤200 B) motivated it. It also caught a live misdirection: C had proposed continuing on "fresh P1 +rows where yield was ~90%", which under the old ranking meant known-callee rows — now P3, the 200B–800B +band where the tie-breaks live. The re-rank was right and the redirect was necessary. + +### New worklist exclusion class `restores_unsaved` (worker A) + +A body restoring a callee-saved register it never saves cannot be a whole function: the register was +established by an enclosing prologue the derived extent cut off. These are `jal` targets *inside* a real +function, so the walk began mid-body — distinct from `bad_extent_start`, which flags starts that are not +function entries at all. + +Verified disjoint before acting, as the project requires: **0 of 462 registered regions** trip the rule; +**11 worklist rows** do (A's partition 7, B's 1, C's 2 — so A's estimate that the class was undercounted +elsewhere was right, and the requested sweep found the rest). Implemented as +`restores_unsaved_callee_saved` with a counted reason; worklist 1265 → 1251; 5 new tests, suite 229 → 237. + +**Independent corroboration:** the rule re-derives `0x8010080C`, which worker C had reported earlier via a +completely different signal (first instruction reads a register the range never defines). Two workers, two +detectors, one defect class — and `bad_extent_start` is False for that row, so A's class is genuinely new +rather than a duplicate. A's suggestion to encode it as a counted reason rather than a Makefile `--exclude` +was the better engineering answer and was taken. + +### Worker A falsified the coordinator's register-field broadcast + +I had broadcast "a permuted register set = the commutative-operand lever". A showed the generality is +false: on `0x800A5180` it wrote `q[1]` where the original read `entry[1]` through the table-entry pointer — +right length, identical mnemonics and schedule, 11 differing bytes all in register fields, and **not** an +allocation tie-break. Amended standing rule: **when count and mnemonics match and only register fields +differ, verify the DATAFLOW before concluding tie-break** — two different pointers swapping registers are +indistinguishable from register names alone. A then re-verified its two earlier cases and they survive as +genuine tie-breaks, which is the right way to bound a retraction. This is the second coordinator +over-generalisation a worker has caught this phase (the first was the rare-epilogue class). + +### Two worker self-audits after declaring done + +- **Worker C** audited its `src/` against its claims during handoff cleanup and found **`0x800A6C34`** — a + row it matched in its first batch that came back DIFF and then fell out of staging entirely, because C + had reported it as a *finding* ("reads 0x80121B88 absolutely") without ever listing it as a claim. A + finding that is not also a claim is invisible to the merge flow. **Standing rule recorded: run the + `src/` cleanup audit BEFORE the final report, not after.** +- The coordinator then tested C's named lever for that row and **disproved it**: the `gp=-D_80121B88` + override gives an identical 16 bytes at `0x800A6C54`, so the encoding is not what holds the row open. + The tracked index records the *untried* lever (a source order that stops the hoist) and explicitly notes + the gp override was tested and disproven, so the next worker does not spend an attempt on it. A named + lever that has not been tested is a hypothesis. +- **Worker B** had earlier found a 1-byte residual that was its own arithmetic (a mis-converted + displacement, faithfully encoded by the name-keyed symbol mechanism). + +### Worker B2 recruited and productive + +B2 inherited B's checkpoint as its brief (15 levers, 6 deferrals) and matched its first row on the first +attempt. Two notable results: a **within-function signedness trap** (two constants in one function, one +needing `ori`/unsigned and one `addiu`/signed, same immediate bits, one differing byte), and a structural +result derived by elimination — the original's test order **1, 0, 2** with arm bodies in **case order +0, 1, 2** is decoupled, which rules out both an if/else chain and a `switch` (GCC 2.7 emits a balanced +decision tree with an `slti` range test, measured), leaving a goto chain with the default block after the +arms. + +B2 also **declined** to request a per-region `cc1=-fno-schedule-insns`, on the reasoning that "a per-region +flag is a build-consistency change, not a match lever". That distinction is correct and is now recorded: +`cc1=-G8` and `gp=-NAME` were granted because they are byte-required and each was verified with a failing +control; a flag that changes cc1's *scheduler* to force a match would mean the corpus is no longer all +built by one compiler configuration. + +### Session budget (quoted from `intercom list`) + +coordinator 39%, A 45%, B2 16%, C 53% (stopped at its own 68% measure). A fresh session for C's partition +is approved by the developer; C's `HANDOFF.md` (12 levers, 15-row negatives table, size-band measurement) +is its brief.