## Filbert review, row 156 round 2: approve Candidate manifest `build-manifest-r2.sha256`, sha256 `72a5c1b62ed0cb7be43015f23aca835ccec001081ff332d8d8c4fd28bd2bb700` (14 paths, the same as round 1). Patch `build-r2.patch`, sha256 `a9fa9b75c3f7c0d91ad2b410f681c7e5b8258ecfc07cc646f3393ccfe5d98e48`. I applied it with `--index` to `70c9131f0`. All 14 manifest lines matched, `git diff --cached --check` is clean, and the diff is +925 -92 over 14 files. ### What changed since round 1 I built the round 1 tree (`build.patch` on `d88613bac`) and compared it with this one file by file. Eight files differ: - `broker.mjs`, `launcher.mjs` (one comment), `cli/README.md`; - the tests `land.test.mjs`, `launcher.test.mjs`, `thread-launch.test.mjs` and `runner.test.mjs`; - `docs/TOOLS.md`, where the only difference is row 154's landed `:443` hunk from the base (`d88613bac..70c9131f0`), not this row. The other six files are byte-identical to round 1, so my round 1 "checked and fine" items carry over. ### F1: resolved - `broker.mjs:180` adds `#received`, keyed `business:run`. - `message.receive` adds the run after `#agent(s)` passes (`:1844-1846`), so humans and testers are never added. - `landRelease` answers `{released:false, landing:true}` for a run not in the set (`:1016`). That check comes after the run, holder and decision checks and before the unread count, so a refusal still names its code. - The runner takes every landing turn (`runner.mjs:378-400`) before its first `message.receive` (`:404`), and nothing between `role.claim` and that loop calls `message.receive`. So a run in a landing turn is never released. - The `cli/README.md` text now says this. Its "only between turns" sentence and TOOLS.md's "stopped between turns first" now hold as written. The test is the one I asked for. The runner.test "a run in a landing turn isn't released..." test uses a real runner and broker: - the adapter holds landing turn 1 open on a file; - d2 is raised and resolved during that turn, and `landHolders` lists both decisions; - two `landRelease` calls 300 ms apart answer `landing: true`, and the claim stays; - after the go file, it releases by `land-relaunch` only once both DECISION messages are read, and the runner exits `not-holder`. launcher.test `:489-497` shows that a tick given `landing: true` stops nothing and logs no `land-relaunch`. Dewey's "tick mapping" splits that coverage honestly between the two tests. I accept the split: the runner test calls `landRelease` with the arguments the tick uses. ### F2: resolved thread-launch.test `:306-321` answers `landHolders` with an entry for the thread instance, launches a thread run, and asserts `session.json` has no `landing` key. The BUILD.md:56 equivalence claim is struck and corrected under "Equivalent mutants". ### F3: resolved land.test `:454-475` ends the raising run, binds and claims a new run (`merge-gate-land`), and checks two things before any `message.receive`: - `landRelease` answers `landing: true`; - `checkLand` returns a ticket naming the decision, commit, verdict and choice, and `recordLand` records the merge with `actor_run` merge-gate-land. Afterwards `landHolders` is empty, and no `op='delivered'` row exists for the run. Dewey's run 4 correction says why the assert counts `delivered` and not every row: the claim writes `routed` rows. That matches the release test's filter at `:445`. The call is made directly as the run, not through a runner's `land_work`, which sage-0942's F3 ruling allows. ### Each new test kills its mutant I read the mutant logs in `run4/mutants/`. Each failure is the new assert, not a crash: - **B13 (drop the `#received` check).** Fails 3 tests. The land.test release test and the F3 test fail at their `landing: true` asserts. The runner test fails at `runner.test.mjs:739`: `released: true` while the landing turn is open, which is round 1's defect. - **B14 (drop the add on receive).** Fails 2 tests. The land.test release test fails, and the runner test times out at `:746` waiting for a release that never comes. - **LA14 (a thread launch asks landHolders).** The thread-launch test fails at `:320`, and the failure prints the session file with `"landing":[{"decision":"d9",...}]`. `run4.out`: killed 36, survived 0, timeout 0, `mutants.sh rc=0`, and the manifest matched at the end. My awk sums over Dewey's logs agree: - `run4/touched` (4 logs): tests 84, pass 84, fail 0, skipped 0; - `run4/singles` (26 logs): tests 290, pass 290, fail 0, skipped 0. thread-launch's log shows `skipped 0`, so its `{ skip }` option didn't skip the F2 test. ### Other checks - **Hash pins.** Only `thread-migration.test.mjs:46` has a 64-hex pin in a file that names a non-test manifest path, and it pins a DDL string, not `broker.mjs`. - **Base drift.** From `70c9131f0` to HEAD `c3cd27345`, no manifest path changed, and `build-r2.patch` passes `git apply --cached --check` on HEAD in a temporary index. ### Notes (not blocking) 1. A run that never reaches its first `message.receive` (a hung landing turn) keeps the release closed. So does a run whose broker restarted, until its next receive, because `#received` is in memory. BUILD.md records sage-0944's fallback for the first case: row 149's path, where the chief ends the run and launches the holder. The second case clears at the run's next poll. Neither is in `cli/README.md` yet. Doc-only, follow-up. 2. `#received` is never pruned. It grows by one entry per role run that receives, the same as `#ended`. That's fine at this scale. ### Ran by me Nothing that needed the slot. I applied both rounds' patches in two worktrees, ran `sha256sum -c` (14/14), compared the files, ran the temporary-index apply check on HEAD, awk-summed Dewey's logs and read the mutant logs, and ran greps. ### Not mine Dewey's run 4 rerun on Sage's slot (22:53:04Z to 23:08:35Z, sage-0947): touched 84/84/0, singles 290/290/0, and 36 of 36 mutants killed. I read and summed the logs but did not rerun them. The red run 4 (land.test 1 fail) is in `run4-red/`, as Dewey recorded it. The full gate on the new base is Sage's at landing.