Files
stack/agents/darkwing/work/queue-54-review/review-r2.md
T
jason.woltjeandClaude Opus 5.5 bfbcf626de review(row54): round 2 packet, approve (darkwing)
Comment 27191 on #1543, correction 27192. Candidate afb2ae0e.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 17:10:15 -05:00

11 KiB

Row 54, read-only console views, round 2 review (Darkwing)

Issue #1543, request comment 27187, packet comment 27188. Base d64f434f. Candidate manifest sha256 afb2ae0e66e6388a35b4bedf915080d876a3d8576f79ae2ab660e81188a3a215, 14 files. The packet manifest and the checkout both check 14 OK, and row54.patch applied at 6637bca5 gives the same 14 files. 6637bca5 is d64f434f plus queue revs 373 to 380, the round 1 review packets and SESSIONS lines. None of those touch packages/.

Verdict: approve. Both round 1 blockers are fixed and tested. So are the D29, D20 and D21 test gaps, and the views.test :167 failure has a cause I can follow. Filbert's items that I could check from outside (After, the redactor, Required, the settings refusal) behave as stated on the real queue as well as on the fixture. Every suite is green. 40 of 45 mutants die; three new survivors are small test gaps, none blocking (notes 4 to 6).

Method

  • Detached worktrees papply and mutwt at 6637bca5 with row54.patch applied and staged. Both check 14 OK. mutwt still checks 14 OK after the mutant runs (r2/mut/manifest-after.txt).
  • r2/gate.sh, the same gate as round 1: the packages/webui, packages/queue and packages/business node suites, build-tokens.mjs --check, then every scripts/test-*.sh with DOCKER_HOST=unix:///nonexistent.sock, 21:18:07Z to 21:21:30Z. Then test-release with Docker.
  • 45 mutants (r2/mut/mutate.py, r2/mut/run.sh): my 31 from round 1, with D07 moved onto the new redactor, and 14 new ones (E01 to E14) on round 2's changes. Each runs against the full packages/webui suite, D31 against packages/queue, 21:22:02Z to 22:07:37Z.
  • Node probes (r2/probes/probe-r2.mjs, output probe-r2.txt): the round 1 redactor strings plus URL, ~/ and : shapes (Q1); the real queue-read.mjs beside a broken, missing or refusing store, and a broken or missing errors.mjs (Q2); fake children that print a stack and exit 1 or 3, or refuse with a path (Q3); settings with no system config (Q4).
  • A sweep of the real queue (r2/probes/probe-realq.mjs, output probe-realq.txt): /api/queue and every /api/queue/:id read for all 61 rows, with the candidate's reads rooted at the canonical checkout, because the store refuses a linked worktree. rows() writes nothing (decision 83).
  • Browser probes in Chromium through the candidate's tests/browser.mjs (r2/probes/probe-browser-r2.test.mjs, output probe-browser-r2.txt): round 1's B1 to B4 on the seeded fixture, and B5 on real rows 8, 9, 35, 38, 47 and 54.
  • Read row54-r1-to-r2.patch line by line, and Dewey's round 2 evidence.

Node v26.8.1, TMPDIR=~/darkwing-scratch/r54b/tmp. No tracker request.

Suites

Suite Result
packages/webui (node) 39/0
packages/queue (node) 149/0
packages/business (node) 60/0
build-tokens --check rc 0, "tokens.css is current"
test-auth 15/0
test-conductor 17/0
test-config 24/0
test-discord 66/0
test-extension-package 18/0
test-foundation 44/0
test-queue 27/0
test-release 4/0 without Docker, 14/0 with it
test-task, Docker unreachable 26/0

As in round 1, I didn't run test-task with real Docker, because it makes live model calls.

Round 1 items

Item Result
Required 1, Arbiters Fixed. B1 on the seeded fixture: the API gives {"delivery":"pm","technical":"cto"} and the page shows "pm (delivery), cto (technical)". The seeded views test asserts that line. E07 (back to names()) dies
Required 2, import leak Fixed, both ways I suggested. Q2: a store with a syntax error, a missing store, a missing or broken errors.mjs, a store that throws a plain error at load, and rows() throwing all give read-failed "the queue read failed (exit 1)", with no base path. Q3: exit 1 and exit 3 with a file:// stack give the fixed message. E01 (static imports) and E02 (forward any exit) die
D29 mirror focus Test added. D29 dies
D20 output cap, D21 timeout Tests added. Both die
D22 host state .live No test, follow-up. Still survives
:167 Explained (below)
Note 4, GROUPS =[[ Fixed

A store that refuses at load with exit 2 still has its message forwarded, which is right: that text is the store's own. Q2 load-refusal-2 throws a QueueError with an absolute path and a file:// URL in it, and both come out as <path> and file:<path>.

The :167 account holds together. With reads and no bus, the palette's /api/bus/inbox and /api/bus/tasks reads answer 503 not-configured, which is a refusal, and row 53's rule forgets every read on a refusal, api:queue included. Whether the queue rows were listed then depended on which finished first. Dewey's views-no-bus mutant drops the test's stub bus and dies at that check, which is the evidence I'd want. In round 1, D06, D07 and D09 also timed out at :167, though D07 and D09 can't reach that test. A race explains that and a timeout didn't. The product question Dewey raises, whether not-configured on a bus route should forget the queue read, belongs to Sage and row 53, and I agree it isn't row 54's to change.

Filbert's items, checked from outside

I didn't review these as Filbert's reviewer; I checked what my probes reach.

Item Result
B1, After B5 on real rows: row 38 shows "36 done, 37 done" and row 54 "53 done", each id a link. E08 and E14 die
R1, redactor Q1 below. Over all 61 real rows the reads carry no /home/, /mnt/, ~/, file: or user name; rows 8, 35 and 47 carry <path> where their notes had ~/ paths, and B5 shows the same on their pages
N1, settings with no system config Q4: not-configured, "the Console has no system config, so it knows no notifier config". E11 dies
N2, Required B5 row 9: "yes since 2026-09-13" (27 d ago). E09 dies; E10 survives, note 4

Probes

Probe Candidate
Q1 redactor config:/…, file:/…, file:///…, ~/…, key=~/k, see:~/x, `~/.mosaic` and </…> become <path>. https://, ssh://, http://127.0.0.1:3773/x/y, git@host:org/repo.git, origin/refactor, a~/b, ~ and ~user/x are unchanged. ./…, Windows paths and id_<digits> are unchanged, as in round 1. Notes 1 and 2
Q2 import and load failures all seven cases: fixed read-failed or the store's refusal, no base path
Q3 fake children exit 1 and 3 fixed; exit 2 forwards with file:<path> and <path>; exit 2 silent gives "the queue refused the read"
Q4 settings, no system config no business: "knows no business"; --business acme: "knows no notifier config". Both not-configured
Q5 real queue sweep 61 rows; no absolute or ~/ path in the list or any row
B1 Arbiters "pm (delivery), cto (technical)"
B2 mirror focus kept on palette and mode; a mirror change moves the command bar
B3 H1 focus kept
B4 navigation one refresh due after it, as in round 1
B5 real rows After, Required and Note as in the table above; the last page's text has no /home/ or ~/

Mutants

40 of 45 killed (r2/mut/summary.txt). I checked each kill site in its output against its diff, and each one fails at the assertion meant for it. The round 1 mutants not in the table die at the same assertions as in round 1, at the current line numbers.

Mutant Change Result
D14 role vars not allowlisted survived, equivalent as in round 1
D20 no output cap killed, "the queue read printed too much", reads.test.mjs:105
D21 timeout times 1000 killed by the test's own 60 s timeout, reads.test.mjs:87
D22 host state without .live survived, the follow-up
D29 keep() without the mirror killed, "the refresh keeps focus on the mirror select", views.test.mjs:198
E01 static imports in queue-read.mjs killed, the child's output, reads.test.mjs:93
E02 non-2 exit forwards the child's stderr killed, the 503 body, reads.test.mjs:97
E03 redactor without the : prefix killed, redactor test reads.test.mjs:31 and the seeded page check
E04 : prefix without the URL lookahead killed, reads.test.mjs:25 and the business read at :116
E05 no ~? killed, reads.test.mjs:29 and the seeded page check
E06 no < prefix killed, reads.test.mjs:31
E07 Arbiters back to names() killed, views.test.mjs:169 and :228
E08 After back to qLink killed, views.test.mjs:219
E09 Required shows the raw value killed, views.test.mjs:220
E10 "since" on any truthy requiredSince survived. Note 4
E11 no notifier dataRoot check killed, reads.test.mjs:197
E12 instanceof without the null check survived. Note 5
E13 Arbiters without || none survived. Note 6
E14 After without when killed, views.test.mjs:219

mutwt checks 14 OK after the run (r2/mut/manifest-after.txt). The browser probe ran during D01 and D02, and both died at their own assertions (views.test.mjs:158 and :103), so the extra load didn't make a false kill.

Notes (not blocking)

  1. file://localhost/home/u/x passes through, because a : followed by // and a host reads as a URL. Node writes file:///… with an empty host, which is redacted, so I don't see a way for this to reach a page today. The README's rule describes it.
  2. path</home/u/x> becomes path<<path>>, and http:// alone becomes http:<path>. Both are cosmetic.
  3. D22 stays untested, as Dewey says. P5c in round 1 showed the read works.
  4. E10. The store allows requiredSince: "unknown" on a required row (checkTime with unknown: true, queue.mjs:330). The candidate shows "yes" for it, and the mutant would show "yes since" with a <time> around "unknown". No real row has it today (all 5 required rows carry a date), and the test at views.test.mjs:220 accepts both forms. A seeded "unknown" row would pin it.
  5. E12. With errors.mjs missing, the mutant child throws a TypeError inside its catch and prints Node's stack, file:// path included, exit 1 (r2/probes/e12-check.sh, output e12-check.txt). reads.mjs drops stderr on exit 1, so the API answer is the same and the mutant is equivalent there. The child's own contract isn't: the load-failure test breaks only store.mjs, and adding a missing errors.mjs case to that loop would kill it.
  6. E13. An empty arbiters object would give an empty Arbiters cell instead of "none". Cosmetic, and no test seeds one.

Files

  • r2/candidate-manifest.sha256: copy of Dewey's.
  • r2/gate.sh, r2/out/: suite runs, summary.txt and test-release-docker.txt.
  • r2/mut/: mutant definitions, runner, diffs, outputs, summary.txt and manifest-after.txt.
  • r2/probes/: the three probes, the E12 check, and their output.