queue move ID in-review posts the review request as a Gitea comment and review record reads verdicts back, so reviews stop being files in docs/plans/reviews/. On a comment round, in-review to waiting-on-jason now needs every listed reviewer's approval for the current round, the same as in-review to done (Filbert r1 C1). scripts/gitea-api.sh reads the raw per-seat token files (lead decisions 37 to 39): config built and checked before curl starts, export attribute cleared, fixed base URL. test-queue.sh skips its live checks outside the canonical root. Darkwing authored. Filbert approved D r2 (cf1d3fd0) after r1 (a2dc2302) and corrected the plan (293747cd). Rocko reviewed the helper (e896192f, 2096b0a3), and Sage's lead check passed under decision 38. Manifest b402fb38, 19 files. Co-Authored-By: Claude Opus 5.5 <[email protected]>
4.7 KiB
Queue Piece D review, round 2 (#1508, row 12)
Filbert, 2026-09-27. Round 1: queue-d-review-r1-2026-09-27.md
(sha256 a2dc2302…). This round checks C1 only, per Sage's ruling to fix it
in D.
Verdict
Approved. The review covers build.patch sha256
8a19f7fa03e2ee6c3bd9ce7b2e296acb21655471c4cc56ba19f25464c8129209 (base
8ffbd73b, applied at cdcedb27), with build-manifest.sha256 647d0170…
and build.md e77c8c5e…. The C1 fix is correct. One mutant of mine
survives: an approval from an earlier round counted in the current one.
The code handles that case correctly; the tests just don't check it. n1
gives a four-line test that kills the mutant. I'd add it before the
commit, and it doesn't need a round 3. I checked it myself (below).
What I checked
All of this ran in a scratch clone, /tmp/fqd2, at cdcedb27 with push
disabled, on frozen 0444 copies of the three inputs.
-
Manifest and suites. The manifest checks 10/10.
node --test packages/queue/tests/passes 142/142, and the ledger tests pass 51/51 (Darkwing's 58 includes the helper patch, which I didn't apply).scripts/test-queue.shreports 27/0 with the "outside the canonical root" skip line. -
What changed. I compared all ten manifest files with round 1's tree. Only
queue.mjs,README.mdandreview.test.mjsdiffer, as Darkwing said. -
The fix in
queue.mjs.requireApprovalsis the round-1 inline check moved into a helper. in-review→done's messages are unchanged.- in-review→in-progress still checks only
ownerOrPriv, which is right for the changes path. - in-review→waiting-on-jason runs
ownerOrPriv, thenrefuseUnresolved, thenrequireApprovalswhen the last round is a comment round.unresolvedAttemptsskips rounds that aren't comment rounds, and v1 entries can't open one. So v1 replay is unaffected. - There's no exemption for jason or sage, as agreed.
-
The tests. The new test runs my round-1 reproduction and now refuses at the step that used to pass. It covers a reviewer who asked for changes, a second round, and reviewers cleared after the round opened. The rewritten unresolved test keeps waiting-on-jason→done covered through a late post that turns an abandoned attempt into a conflict. That's a better route than the old one.
-
The README matches the code.
-
Mutations. I wrote eight mutants of my own for this round. The suite kills seven:
- G1: sage bypasses the approval check on waiting-on-jason;
- G2: a
changesverdict counts as an approval; - G3: the check reads the first round, not the last;
- G4: one approval is enough;
- G5: the owner-or-privileged check dropped from waiting-on-jason;
- G6: the unresolved check dropped from waiting-on-jason→done;
- G7: the approval check dropped from in-review→done.
G8 survives: approvals are collected from every round's receipts instead of the current round's. See n1.
-
My plan. Table line 1470 and 8.9's Receipts paragraph (plan sha256 293747cd…) describe the code as built.
Non-blocking
-
n1. Add a test that an earlier round's approval doesn't count (kills G8). In the new test, filbert approves round 1 and rocko asks for changes. In round 2 both approve before anything checks, so an old approval counting in round 2 goes unnoticed. In
packages/queue/tests/review.test.mjs, replace the round-2forloop (three lines) with:ok(s.run(["review", "record", "9", "--verdict", "approve", "--comment", "91", "--candidate", head, "--op", "record-9-rock02"], "rocko")); // Filbert's round 1 approval doesn't carry into round 2. no(s.run(["move", "9", "waiting-on-jason", "--op", "wait-9-000001"], "darkwing"), 2, /row 9 round 2 has no approval recorded by filbert$/m); ok(s.run(["review", "record", "9", "--verdict", "approve", "--comment", "90", "--candidate", head, "--op", "record-9-filb02"], "filbert"));I checked it in a copy of the scratch clone:
review.test.mjspasses 20/20 on the candidate and fails 1 under G8. -
n2. An owner who is also a listed reviewer blocks the row.
set reviewersandassigndon't stop the owner from being on the list.recordrefuses the owner, butrequireApprovalsstill waits for the owner's approval. The row then can't reach done or waiting-on-jason until a privileged actor runsset reviewers. That fails closed, and it was already true of done in round 1. The refusal names the owner as missing, which could confuse. Don't fix it by dropping the owner from the required list: with reviewers[owner], that list would be empty and the row would pass with no review. A later fix could refuse the owner atset reviewersandassign. That's a follow-up, not D.