Files
stack/agents/darkwing/work/queue-53-review/review-r3.md
T

8.3 KiB
Raw Blame History

Row 53, console tokens and shell restyle, round 3 review (Darkwing)

Issue #1542, request comment 27168, packet comment 27169, queue revs 367-369. Base ea080fd8. Candidate manifest sha256 2562c05d4a92f90096c0fe68ef8c2adfa7244fa547f3390155f5bee5cce64cba, the same 16 files under packages/webui. The packet manifest and my snapshot of the checkout both check 16 OK. round3.patch applied to my round 2 snapshot gives the round 3 files byte for byte, so the delta is README, app.js and shell.test.mjs and nothing else (r3/out/r2-to-r3.diff).

Verdict: approve. Both of my round 2 items are fixed, and the tests pin them. Every suite is green, all 14 new mutants die, and my probes on the real control-board show nothing from before a refusal. I have three notes, none blocking. The worst is a stale session picker that this row didn't introduce.

Method

  • Detached worktrees at ea080fd8, cand, mutwt and pwt, each with the 16 candidate files staged and checking 16 OK. mutwt still checks 16 OK after the mutant runs (r3/mut/manifest-after.txt).
  • r3/gate.sh: the packages/webui suite, build-tokens.mjs --check, then every scripts/test-*.sh with DOCKER_HOST=unix:///nonexistent.sock, 19:23:02Z to 19:26:06Z.
  • 14 mutants aimed at the round 3 code (r3/mut/mutate.py, r3/mut/run.sh), each against the full webui suite, 19:26:06Z to 19:38:50Z.
  • test-release with Docker, finished 19:39:38Z.
  • Probes in Chromium through the candidate's tests/browser.mjs (r3/probes/probe3.test.mjs, output r3/probes/probes-cand.txt). Test one is round 2's fake board and bus set (P1 to P9). Test two runs the real control-board from tests/history-fixture.mjs behind a proxy that can answer 403, fail the catalogue with a 500, or hold history pages (P10, P11, P13). Test three is a board whose first read is a 500 (P12). No tracker request.
  • Read the three changed files against my round 2 required list and Filbert's C4 (comment 27163).

Node v26.8.1, TMPDIR=~/darkwing-scratch/r53c/tmp.

Suites

Suite Result
packages/webui (node) 27/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 before, I didn't run test-task with real Docker because it makes live model calls.

Round 2 items

Item Result
Required 1, P9 and Filbert's C4 Fixed. With no scan held, error() empties #sessions, #waiting and #seen, puts "–" in the three counts, and says "the read failed" in the tree, the footer and #status. P9 (403 then 500) and P12 (first read 500) both show an empty board. The test runs a 403, then a 503, and asserts no rows, no cards, no History buttons and the dashes
Required 2, P10 Fixed. A 403 with a conversation open empties #conv-log and calls closeConversation(). P10 on the real control-board: #conversation hidden, no has-conversation, #conv-log empty, the form hidden
README wording Fixed. The refusal line now names the cards, the project filter, the empty board after a failed read and the closed conversation. Each claim matches what the probes show
M30 (counts kept on refusal) Now tested. R09 below drops the dashes and dies on #waiting-count

Dewey's test doesn't run a 500, only a 503. Both go through the same non-403 branch, and my P9 and P12 run the 500. That's enough.

Probes

Fixtures as in round 2. P10, P11 and P13 use the control-board fixture's session, whose history holds "Secret question from before the refusal" and "Secret answer from before the refusal".

Probe Candidate
P1 board 403 with the inspector open #board-view display:none, inspector hidden
P2 board 403 tree, footer, #status and #fresh-board say not read
P3, P4, P4b bus refusal the palette and section list show the four views only
P6, P7 banner ref then banner err, no task rows
P8 the toast before any copy 1×1, empty, in the tree
P9 good read, board 403, then a 500 #board-view shown but empty, 0 rows, #waiting and #sessions empty, tree, footer, #status and #fresh-board say "the read failed". Was the refused rows. Fixed
P9b then a good read 2 rows, footer "waiting 1 · working 1"
P10 History open, then every board request 403 #conversation hidden, #conv-log empty, form hidden, #board-refused shown. Was the full history on screen. Fixed
P11 refusal, recovery, History again with the catalogue failing #conv-pick shown with the earlier conversation's title. See note 1
P12 first read 500, no scan ever empty board, "the read failed" everywhere, banner "No board data loaded"
P13 a 403 while a history page is in flight, then the page answers #conv-log stays empty, #conversation stays hidden. The convGen bump in closeConversation() drops the late page

Mutants

14 of 14 killed (r3/mut/summary.txt). Every kill is an assertion or a wait timeout in the shell browser test, not a load error.

Mutant Change Killed at
R01 no close block on a refusal #conversation hidden, line 200
R02 close without clearing #conv-log #conv-log empty, line 202
R03 showConversation(false) instead of closeConversation() the keyboard focus wait, line 215
R04 if (!data) becomes if (refused) footer "the read failed", line 180
R05 no replaceChildren() loop no rows or cards, line 178
R06 the loop skips seen line 178
R07 the loop skips waiting line 178
R08 the loop skips sessions line 178
R09 no count dashes #waiting-count, line 170
R10 footer always "refused" line 180
R11 why always "refused" #status, line 182
R12 no inspect() in the no-data block inspector hidden, line 164
R13 a refusal keeps project "All projects" pressed after recovery, line 187
R14 a refusal keeps selected inspector hidden, line 164

R03 passes the conversation assertions, because they check only that the panel is hidden and the log empty. It dies at the keyboard step because conv stays set. The next Enter on a row runs closeConversation() first (line 347), which moves focus to the old History button before focusSnapshot(). Escape then returns focus to History, not to the row. A direct check that the conversation is closed would catch it sooner, but the kill is real.

Notes (not blocking)

  1. Stale session picker (P11), not from this row. openConversation() clears the title, the meta line and the log, but replaces the #conv-pick options only after a good catalogue read. When the catalogue fails, the picker keeps the previous conversation's titles, shown under "History unavailable". That can be a conversation from before a refusal or from another seat. Choosing one doesn't open the wrong session: the next catalogue read doesn't find it under this row and falls back. Base 03969219 has the same code. The fix is one line, $('conv-pick').replaceChildren() next to the conv-meta clear. It fits in row 54 or a later shell row.
  2. Focus after a refusal closes a conversation. In error(), closeConversation() runs before the no-data block. restore() puts focus back on the History button, which is still in the DOM at that point. The next lines empty #sessions, the button goes, and focus falls to <body> (P10 active: "BODY"). The $('main').focus() fallback in closeConversation() has already run by then. A keyboard user ends up at the top of the document after a refusal. Repeating the fallback at the end of error() fixes it.
  3. Round 2's note 2 (the hidden inspector keeps its text in the DOM) and Filbert's N4 to N7 still stand. M07 stays accepted. Round 2's note 3, the refresh timer race, is now in row 54 with Dewey's test, and I'll check it there.

Files

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