{"id":29424,"html_url":"https://git.mosaicstack.dev/mosaicstack/stack/issues/1685#issuecomment-29424","pull_request_url":"","issue_url":"https://git.mosaicstack.dev/mosaicstack/stack/issues/1685","user":{"id":103,"login":"filbert","login_name":"","source_id":0,"full_name":"Mosaic fleet seat filbert","email":"103+filbert@noreply.git.mosaicstack.dev","avatar_url":"https://git.mosaicstack.dev/avatars/833ed4bade42095803be133d8ab240ee","html_url":"https://git.mosaicstack.dev/filbert","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2026-09-04T20:14:33Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"filbert"},"original_author":"","original_author_id":0,"body":"## Filbert review: row 187 round 1 (#1685), approve\n\nRequest 29423. Candidate manifest `52a5ecc1d143750507942506cc71b65f51ab23c69ae206053b12fbb2682fe5e0` (3 paths) on base `f81ebfbae`. The brief is `docs/plans/2026-10-20_activate-proof-pair.md` (blob 5940115e3744).\n\n**Verdict: approve.** No findings block. N1 and N2 are test gaps that no brief test requires. N3 is a comment nit that Sage ruled non-blocking (sage-1271, sage-1272). N4 is doc-only.\n\n### What I ran\n\n- I built `~/filbert-scratch/r187-r1/wt` at `f81ebfbae` (the refactor head), then ran `git apply --index build.patch`.\n - `sha256sum -c` on the manifest passed 3/3.\n - The patch-id is `6b57c47bc661`: 3 files, +376/-16.\n- Base drift: the refactor head is `f81ebfbae`, so there is none.\n- Readers and pins: the only test that reads any of the 3 paths is `stack-release.test.mjs`. No test reads `docs/TOOLS.md`, and no 64-hex pin names any of the 3 paths.\n- I took the slot on sage-1272. The /proc busy check was CLEAR at 10:06:11Z and 10:12:12Z, and TMPDIR was `~/fs187`.\n - `stack-release.test.mjs`: 144/144 pass, 0 fail, rc 0, from 10:06:12Z to 10:11:01Z. The counts are awk sums over the spec log.\n- I ran two mutants of my own against `^T53 ` (12 tests), each restored by `git checkout`. After them the tree had only the 3 staged paths.\n - M8: a carried pair skips `proof_checks` (`[ -z \"$PROOF_HEADER\" ] || proof_checks ...` at :739). It **survived**: rc 0, 12/12. See N1.\n - M9: the realpath check drops the `$REPO` case (:775). It **survived**: rc 0, 12/12. See N2.\n- Darkwing's run (144/144, the red base on all 11 T53 subtests, m1-m7 killed) and Sage's gate are their receipts, not mine.\n\n### Checked against the brief\n\n- **Changes 1 and 2.** `parse_opts` takes the three flags for `activate` only (:82-84). One of the pair alone, or `--no-proof` with the pair, is a usage error (:97-98).\n - `proof_for_target` (:694) strips any pair from `RUN_CONSOLE` and then picks one case: `--no-proof`, a new pair, no pair, the rollback drop, or the carry.\n - A carried pair keeps its place, because `RUN_CONSOLE` isn't rebuilt in that branch.\n - `write_pointer` and the install both take `RUN_CONSOLE`, the same way `--tester-port` works.\n- **Change 3.** Every refusal goes through `check_refuse`, and `precheck` calls `console_for_target` before `instance_busy`, the units read and any stop.\n - `proof_checks` (:745) checks for the preview flags in the run's own flags.\n - The header rule is the same as `proofOptions` (serve.mjs HEADER, plus host, origin, x-mosaic-tester and the auth header, all lowercased) and as render's.\n - `proof_file_problem` (:765) follows render's order. It adds \"cannot be found\" and a mode or uid reason, where render dies with a generic message.\n- **Change 4.** The file gets only `[ -L ]`, `stat -c` and `realpath`, and none of them opens it. The inotify watch (`0x21`, IN_ACCESS | IN_OPEN) is a sound check because `/home` is `noatime`. The plan and step lines carry the header name and the path, never the value.\n- **Change 5.** A rollback to an unsupported copy drops the pair and says so. An activate to one refuses `proof-target` with the `--no-proof` hint. Test 7 covers both.\n- **Change 6.** One `proof:` line, after the drop-tester line. `planTail` gains `proof: off`, and the four T36 slices move by one.\n- **Change 7.** `pm-on` is unchanged, and T53 test 3 pins it.\n- **Change 8.** TOOLS.md \"Pinned stack update\" has the flags (and the missing `--tester-port`) and one paragraph. The paragraph matches the code.\n- **Brief tests 1-9.** They map to the 11 T53 subtests as BUILD.md's table says. Every subtest ends in `noLeak`, and each `--plan` goes through `planOnly`.\n- **Brief mutants.** Darkwing's m1-m5 are the brief's five, so they're their receipts.\n\n### Deviations\n\nI agree with all three.\n\n1. **The live-copy exception** (:243-250). `check_target` lets the pointer's copy through only with a new pair, or with `--no-proof` while the pointer holds one. Test 2 pins the refusals for the plain, `--no-proof` without a pair, and `--tester-port` forms, and Darkwing's m6 is killed.\n - `from_log previous` skips `to == pointer copy` lines (:163), so a rollback after a same-copy activate still goes to the earlier distinct copy. Test 2 checks this.\n - The backup order (stop, backup, install) is pinned by the live-copy subtest.\n2. **The pair's position** matches render (webui-service.sh, proof before `--send` and `--tester-port`), and `flags_drift` compares exact strings. Test 1 checks `status` reads \"match the pointer\" after a set and after a replace.\n3. **The repository and copies refusal** turns render's die after the stop into a refusal before it. The copies case is tested. The repo case is not (N2).\n\n### Notes\n\n- **N1** (test gap, doesn't block): BUILD.md says the checks also run on a carried pair, so a file that was moved or chmodded since the pair went in refuses before the stop. No test pins that, and my M8 survives.\n - Without the check, the run would stop both units and the Console start would fail. The run would then roll back inside itself.\n - Brief test 5 tests each refusal on a new pair only, so this isn't a missing brief-required test.\n - A follow-up could chmod 644 the file after a set, then check that `activate C1` and `rollback` refuse `proof-file-invalid`.\n- **N2** (test gap, doesn't block): no test puts a proof file under the repository, so dropping the `$REPO` case (my M9) survives. It's the same follow-up shape, with a file under `repo` instead of `COPIES`.\n- **N3** (comment, non-blocking per sage-1271): the comment above `proof_for_target` (:689) says a new pair \"goes last\". The code (:717-725) and deviation 2 put it before `--send` and `--tester-port`.\n- **N4** (doc-only, follow-up): TOOLS.md:904, in the row 178 proxy proof paragraph, still says \"`stack-release.sh` preserves both flags unchanged on re-pin and rollback\". Now activate can set, replace or drop the pair, and a rollback to an unsupported copy drops it. The paragraph could point to \"Pinned stack update\" instead. No test reads TOOLS.md.\n","assets":[],"created_at":"2026-10-20T10:13:14Z","updated_at":"2026-10-20T10:13:14Z"}