# Queue A2 (#1508): items carried from A1 review Darkwing, 2026-09-26. This file records Sage's ruling on A1 r1 so it isn't lost before A2 starts. A2's brief lists the two required items. A2's build note repeats each disposition. Note numbers are Filbert's, from `agents/filbert/work/queue-a1-review-2026-09-26.md` (sha256 6933b885). ## Required in A2, with tests Both change what replay accepts or what the table shows, so they land before genesis. Genesis follows A2. - **N8. `cell()` escapes `|` but not `\`.** Piece text `a\| done | x` renders so that `marked` splits it into an extra cell. Raw HTML passes through too. - The change: refuse `\` and `<` in rendered text fields at the CLI and in replay. A refusal holds up better than an escape we would have to get right for every Markdown renderer. None of the 34 table lines in today's QUEUE.md contains either character, so the migration loses nothing. - The test: every text field with `\`, `<` and `a\| done | x` is refused. A render of the allowed characters splits, by GFM's cell rule, into the same number of cells on every row. `marked` is only a transitive dependency in this repo, so the test doesn't import it. - The mutation: allow `\`, and the cell-count test must fail. - **N11. Replay is looser than the CLI on op ids.** `LOG_OP_RE` allows 80 characters for any entry, `accept-history` may end in `.outcome`, and the genesis op isn't checked. - The change: replay applies `CALLER_OP_RE` to every op a caller chose. It allows the longer form only for the op ids the CLI derives. It refuses `.outcome` on `accept-history` and pattern-checks the genesis op. - The test: a hand-built file with each of the three refused shapes fails replay, and every op id the CLI writes still replays. - The mutations: restore each looser check in turn. ## Dispositions of the other notes | Note | Disposition | Reason | |---|---|---| | N5 tmpfs accepted outside tests; `0xef53` also matches ext2 and ext3 | A2: tmpfs becomes a test-only option, like the other fault options. ext2 and ext3: won't do | `statfs` can't tell ext2, ext3 and ext4 apart. The README names ext4, and the canonical checkout is ext4. | | N7 temp files from killed acquires stay in `.git/` | A2: README line only | The files are small, carry the dead pid in their name, and never block a lock. Removing them safely needs the same liveness check `unlock` has, which isn't worth it for the space involved. | | N10 `set issues` resets `closes`, undoing a logged narrowing | A2: fix with a test | It changes replayed state, so it lands before genesis. New rule: `closes` becomes the new issues only if it equalled the old issues. Otherwise it keeps its intersection with the new issues, and the log entry says so. | | N12 `--by` silently overrides `MOSAIC_AGENT_NAME` | A2: stderr warning, no log field | Both values are self-asserted (J2), so a logged mismatch proves nothing a seat can't avoid. A warning catches the honest mistake, a typo or the wrong seat's shell. | | N15 `--install-hook --by` is self-asserted | Won't do | J2. It's protocol: Sage runs the install at bootstrap. A check on a claimed name adds nothing. | | N16 the hook refuses the first commit on an unborn HEAD | Won't do | The hook is installed only in the canonical checkout, which has history. It fails closed. | Sage confirmed this file as written (773dbd75) on 2026-09-26. N5, N10 and N12 stay in A2. N10 has to land before genesis because it changes replayed state. ## From Filbert's r1 approval Filbert approved A1 r1 and N13 on 2026-09-26 (review `agents/filbert/work/queue-a1-review-r1-2026-09-26.md`, sha256 e464be6c). He listed these as non-blocking and suitable for A2. The dispositions below are my proposal, and Sage rules on them. | Note | Proposed disposition | Reason | |---|---|---| | P1 `acquire` calls `release()` unguarded on both gate paths | A2: fix with a test | If release throws (EACCES on `.git`), the CLI prints a stack trace and doesn't say the lock stayed. The fix guards it the way `withLock` does and names the lock left behind. | | P2 `--issue` on a later round overwrites `review.issue`; rounds don't record their own issue | A2: each round records its issue, with a test | Piece D posts per round, and the round's own issue is the evidence of where it posted. It changes the round schema and replayed state, so it lands before genesis, like N10. | | P3 `unlock` splits its result on newlines, so a hand-formatted record spills onto stderr | A2: fix with a test | `lock.mjs`'s `unlock` returns the result and the warning separately, so nothing is split on text. | | N13-a `n13-check.sh` copies the suites from the canonical tree, not from the pinned patch | Won't do | N13 is approved on `n13.patch` and the two suite hashes, and Filbert applied the patch himself. The check script is evidence, not shipped code. | N13-b is Sage's: check the canonical working tree against both pins before committing from it.