diff --git a/agents/darkwing/work/queue-53-review/r2/candidate-manifest.sha256 b/agents/darkwing/work/queue-53-review/r2/candidate-manifest.sha256
new file mode 100644
index 00000000..afc1bf3d
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/candidate-manifest.sha256
@@ -0,0 +1,16 @@
+2c1c65b477f03a9474ca13022eb511363ffef0b75b932d404a0098b7f838594a packages/webui/README.md
+02bbcb68335e80f8822aeea44bc8be49532cd702b325c1ea09ffe95b361a121c packages/webui/src/public/app.js
+a9cb1cd82332b23a47e3a1239d25d13c86d16c4220695e34b243effa999f45f2 packages/webui/src/public/assets/fonts/jetbrains-mono-400.woff2
+086c48dfbea9ddaff1320f7e09399b8e2924e88ce67453721255db3bdbb5a353 packages/webui/src/public/assets/fonts/jetbrains-mono-500.woff2
+c503cc5ec5f8b2c7666b7ecda1adf44bd45f2e6579b2eba0fc292150416588a2 packages/webui/src/public/assets/fonts/jetbrains-mono-700.woff2
+30f0c136e3c88e422d0791acd97238870f9054a9729bc34cf2ff0d4ed8cac4ad packages/webui/src/public/assets/fonts/jetbrains-mono-OFL.txt
+f6f89aaaa6a02e9a16020de26fb6a664f1da152e0b0413248da2d9f6b68395cc packages/webui/src/public/assets/fonts/jetbrains-mono-sources.txt
+d8bc0fc7ad10fa188a6f68b925449476af4ca56ba343b24b089fb48cca296295 packages/webui/src/public/bus.js
+01b456c1ca685e69e2974d66a615b7b8736abbd51aef7a3f014bca3783710430 packages/webui/src/public/icons.svg
+fbbb51e5669a1f559015e0fdebf6f450b63383070472d2461f0bce9b9723d890 packages/webui/src/public/index.html
+d7b4d0ca32f07a63265d89131847cbb72c7e532101e693b31b0f38839b22f7e6 packages/webui/src/public/shell.css
+4fdb72ec24c7245584c89280415e10113dba1c4cb03d98f5570ac745ba2e95cb packages/webui/src/public/tokens.css
+5a65fea95e6225f812c196b0199f3f6562a60e523da685b255f749f63b480c64 packages/webui/src/serve.mjs
+6f68f67e99d5e832c0ba219911201b8adf08505e234647f2d9eac7292d55f50f packages/webui/tests/browser.mjs
+713c86bd6b1d1b27949bbae071f1bdf1f7d744f84b723ad5a1bdbd1e8adc5fb6 packages/webui/tests/serve.test.mjs
+c68acea3c81c1ac67347bae8139632c13dbcfe91207645aa545caa848887be05 packages/webui/tests/shell.test.mjs
diff --git a/agents/darkwing/work/queue-53-review/r2/gate.sh b/agents/darkwing/work/queue-53-review/r2/gate.sh
new file mode 100755
index 00000000..15b079c6
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/gate.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# Row 53 gate: packages/webui node suite, build-tokens --check, then every scripts/test-*.sh with Docker unreachable.
+export TMPDIR=~/darkwing-scratch/r53b/tmp DOCKER_HOST=unix:///nonexistent.sock
+cd ~/darkwing-scratch/r53b/cand
+O=~/darkwing-scratch/r53b/out
+: > $O/summary.txt
+echo "start $(date -u +%FT%TZ)" >> $O/summary.txt
+(cd packages/webui && env -u NODE_TEST_CONTEXT node --test 'tests/*.test.mjs') > $O/node-webui.txt 2>&1; e=$?
+echo "node-webui exit=$e $(grep -E '^ℹ (pass|fail)' $O/node-webui.txt | tr '\n' ' ')" >> $O/summary.txt
+node docs/design/tools/build-tokens.mjs --check > $O/build-tokens.txt 2>&1; e=$?
+echo "build-tokens --check exit=$e $(tail -1 $O/build-tokens.txt)" >> $O/summary.txt
+for f in scripts/test-*.sh; do
+ s=$(basename $f .sh)
+ $f > $O/$s.txt 2>&1; e=$?
+ echo "$s exit=$e $(grep -E 'passed, [0-9]+ failed' $O/$s.txt | tail -1)" >> $O/summary.txt
+done
+echo "end $(date -u +%FT%TZ)" >> $O/summary.txt
+echo DONE >> $O/summary.txt
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M01.diff b/agents/darkwing/work/queue-53-review/r2/mut/M01.diff
new file mode 100644
index 00000000..d6f5cb5f
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M01.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..f0261468 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -368,7 +368,7 @@
+ }
+ const failTitle = err => err.status === 403 ? 'Bus refused the read' : ['not-configured', 'no-bus-host'].includes(err.code) ? 'No bus to read' : 'The read failed';
+ // A refusal fails closed: no kept data, the code in mono. Any other failure keeps the last read, labelled with its time.
+- const refusal = err => err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);
++ const refusal = err => err.status === 403;
+ // After a refusal nothing read before is shown anywhere: not in a view, the palette or the Inbox count.
+ function forget() { last.clear(); inboxCount = null; }
+ const failedView = err => `${head(failTitle(err))}
${refusal(err) ? `refused: ${txt(err.code)}. ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.
${retry}
${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M01.txt b/agents/darkwing/work/queue-53-review/r2/mut/M01.txt
new file mode 100644
index 00000000..766082c6
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M01.txt
@@ -0,0 +1,47 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5795.443344ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6268.860495ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8228.406461ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (1675.044775ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (122.850827ms)
+✔ bus refusals map to statuses and never carry a path or a stack (41.87758ms)
+✔ humanCall speaks the human transport protocol without blocking the server (1966.703581ms)
+✔ busReader takes --business, else the live bus host, else refuses (202.62174ms)
+✔ humanCall kills a transport that runs past its timeout (529.245643ms)
+✔ serve refuses a --business value that is not a business id (191.893201ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4996.198675ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3473.451013ms)
+✔ conversation view: a newer session with no readable history keeps the marker (2317.799437ms)
+✔ conversation view: seats without history say so and offer no reply (1821.002855ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5805.992267ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56174.229792ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4942.660505ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23675.677859ms)
+✔ loopback host and board origin fail closed (10.046586ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (124.822555ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (172.437494ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1879.898ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.519064ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.976932ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (4.470229ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7510.926876ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (7040.739548ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 56775.652439
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (7040.739548ms)
+ Error: Uncaught (in promise) Error: Condition timed out: !!document.querySelector("#bus-view .banner.ref"): undefined
+ at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/browser.mjs:44:35)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:378:9)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M02.diff b/agents/darkwing/work/queue-53-review/r2/mut/M02.diff
new file mode 100644
index 00000000..c4ce288b
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M02.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..836dfbc2 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -304,7 +304,7 @@
+ // everything drawn from it: the inspector, the project tree, the counts and the footer. Any other
+ // failure keeps the last data with its scan time.
+ function error(err) {
+- const refused = err.status === 403;
++ const refused = false;
+ failed = refused ? 'refused' : true; $('error').hidden = false;
+ if (refused) {
+ data = null; selected = null; project = null;
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M02.txt b/agents/darkwing/work/queue-53-review/r2/mut/M02.txt
new file mode 100644
index 00000000..a4896323
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M02.txt
@@ -0,0 +1,59 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5097.83917ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5306.446774ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7791.246228ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (398.914569ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (470.407043ms)
+✔ bus refusals map to statuses and never carry a path or a stack (175.165999ms)
+✔ humanCall speaks the human transport protocol without blocking the server (1816.384458ms)
+✔ busReader takes --business, else the live bus host, else refuses (186.59124ms)
+✔ humanCall kills a transport that runs past its timeout (528.932291ms)
+✔ serve refuses a --business value that is not a business id (174.235634ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5245.016323ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3422.707286ms)
+✔ conversation view: a newer session with no readable history keeps the marker (4796.44785ms)
+✔ conversation view: seats without history say so and offer no reply (5298.920714ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5290.556185ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55325.794121ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4859.496965ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (25971.502398ms)
+✔ loopback host and board origin fail closed (10.250345ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (134.111283ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (108.160287ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1137.333748ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.13576ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.175629ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.598383ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4929.714237ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3800.054159ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 55800.902436
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4929.714237ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ + actual - expected
+
+ + 'banner err'
+ - 'banner ref'
+ ^
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:148:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'banner err',
+ expected: 'banner ref',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M03.diff b/agents/darkwing/work/queue-53-review/r2/mut/M03.diff
new file mode 100644
index 00000000..46924d34
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M03.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..4f2b2625 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -315,7 +315,7 @@
+ inspect(); convForm();
+ }
+ $('error').className = refused ? 'banner ref' : 'banner err';
+- $('board-refused').hidden = !refused; document.body.classList.toggle('board-refused', refused);
++ $('board-refused').hidden = !refused;
+ $('error').innerHTML = refused
+ ? `
The board refused the read. refused: ${esc(err.message)} Board: ${esc(board)}. Console shows nothing rather than a guess. Use Refresh to try again.
`
+ : `
${esc(err.message)} Board: ${esc(board)}. ${data ? `Showing last known data.${data.generatedAt ? ` Scanned ${esc(data.generatedAt)}.` : ''}` : 'No board data loaded.'} Use Refresh to try again.
`;
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M03.txt b/agents/darkwing/work/queue-53-review/r2/mut/M03.txt
new file mode 100644
index 00000000..d4169108
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M03.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5712.8413ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6470.833098ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7936.181163ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (301.533225ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (494.643207ms)
+✔ bus refusals map to statuses and never carry a path or a stack (231.746191ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2469.733966ms)
+✔ busReader takes --business, else the live bus host, else refuses (652.021248ms)
+✔ humanCall kills a transport that runs past its timeout (530.392475ms)
+✔ serve refuses a --business value that is not a business id (165.143296ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (6095.538773ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2939.706831ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1245.419871ms)
+✔ conversation view: seats without history say so and offer no reply (1025.221336ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6516.684216ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56090.939503ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6486.190874ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23562.619035ms)
+✔ loopback host and board origin fail closed (9.883696ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (126.346727ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (111.624361ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1913.882882ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.422763ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.680236ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.722365ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6346.854574ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3733.402259ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 56623.460421
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6346.854574ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+
+ 'block' !== 'none'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:150:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'block',
+ expected: 'none',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M04.diff b/agents/darkwing/work/queue-53-review/r2/mut/M04.diff
new file mode 100644
index 00000000..df5eb969
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M04.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..9bd147b6 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -371,7 +371,7 @@
+ const refusal = err => err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);
+ // After a refusal nothing read before is shown anywhere: not in a view, the palette or the Inbox count.
+ function forget() { last.clear(); inboxCount = null; }
+- const failedView = err => `${head(failTitle(err))}
${refusal(err) ? `refused: ${txt(err.code)}. ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.
${retry}
${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
++ const failedView = err => `${head(failTitle(err))}
${refusal(err) ? `refused: ${txt(err.code)}. ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.
${retry}
${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
+ const staleBanner = err => `
The last read failed. ${why(err)} This is what was read before, ${when(readAt)}. Nothing was changed.
${retry}
`;
+ // Freshness line in the command bar for bus pages.
+ const stamp = iso => { const t = Date.parse(iso); return Number.isFinite(t) ? `${new Date(t).toISOString().slice(11, 19)} UTC` : 'unknown'; };
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M04.txt b/agents/darkwing/work/queue-53-review/r2/mut/M04.txt
new file mode 100644
index 00000000..c3cfb181
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M04.txt
@@ -0,0 +1,58 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5462.633703ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6016.227844ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7161.229825ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (459.662074ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (198.328355ms)
+✔ bus refusals map to statuses and never carry a path or a stack (128.375723ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2011.124303ms)
+✔ busReader takes --business, else the live bus host, else refuses (330.452814ms)
+✔ humanCall kills a transport that runs past its timeout (529.363963ms)
+✔ serve refuses a --business value that is not a business id (257.002802ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5921.250904ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2583.408385ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1776.121129ms)
+✔ conversation view: seats without history say so and offer no reply (842.197628ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5884.809548ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56135.561582ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4993.429078ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24999.455651ms)
+✔ loopback host and board origin fail closed (8.987038ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (151.065885ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (150.806081ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (858.291021ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.308606ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.824401ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.562959ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8401.194007ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (1483.639423ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 56554.628294
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (1483.639423ms)
+ AssertionError [ERR_ASSERTION]: #/inbox
+ + actual - expected
+
+ + '--business'
+ - 'no-bus-host'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:379:16)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: '--business',
+ expected: 'no-bus-host',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M05.diff b/agents/darkwing/work/queue-53-review/r2/mut/M05.diff
new file mode 100644
index 00000000..46127d5f
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M05.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..0737320a 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -377,7 +377,7 @@
+ const stamp = iso => { const t = Date.parse(iso); return Number.isFinite(t) ? `${new Date(t).toISOString().slice(11, 19)} UTC` : 'unknown'; };
+ function freshBus(state) {
+ $('fresh-bus').innerHTML = state === 'refused' ? 'Bus not read: refused' : state === 'failed' ? 'Bus not read: the read failed'
+- : `Bus read ${esc(stamp(readAt))}${readAt ? ` (${esc(ago(readAt))})` : ''}${state === 'stale' ? ' · stale: the last read failed' : ''}`;
++ : `Bus read ${esc(stamp(readAt))}${readAt ? ` (${esc(ago(readAt))})` : ''}`;
+ }
+
+ // ---------------------------------------------------------------- router
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M05.txt b/agents/darkwing/work/queue-53-review/r2/mut/M05.txt
new file mode 100644
index 00000000..f738fe3e
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M05.txt
@@ -0,0 +1,89 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (8079.031307ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (95685.374707ms)
+✖ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (39939.301906ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (399.29347ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (107.942253ms)
+✔ bus refusals map to statuses and never carry a path or a stack (183.540352ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2475.56703ms)
+✔ busReader takes --business, else the live bus host, else refuses (210.045959ms)
+✔ humanCall kills a transport that runs past its timeout (528.605198ms)
+✔ serve refuses a --business value that is not a business id (196.905686ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (64786.967758ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (27245.695481ms)
+✔ conversation view: a newer session with no readable history keeps the marker (6126.989522ms)
+✔ conversation view: seats without history say so and offer no reply (5118.460015ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (9195.480901ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (88101.20953ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (16229.53364ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (46498.641699ms)
+✔ loopback host and board origin fail closed (9.766364ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (204.824833ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (368.503988ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1135.758555ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.436508ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.838218ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.916424ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (25445.008415ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (12241.439812ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 24
+ℹ fail 3
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 103416.270276
+
+✖ failing tests:
+
+test at tests/bus-browser.test.mjs:68:1
+✖ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (39939.301906ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+
+ 'BODY' !== 'H1'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/bus-browser.test.mjs:124:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'BODY',
+ expected: 'H1',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (25445.008415ms)
+ AssertionError [ERR_ASSERTION]: The input did not match the regular expression /stale: the last read failed/. Input:
+
+ 'Bus read 18:29:18 UTC (1 s ago)'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:221:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'Bus read 18:29:18 UTC (1 s ago)',
+ expected: /stale: the last read failed/,
+ operator: 'match',
+ diff: 'simple'
+ }
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (12241.439812ms)
+ AssertionError [ERR_ASSERTION]: #/inbox
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:372:14)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 'Bus read 18:29:28 UTC (1 s ago)',
+ expected: /stale: the last read failed/,
+ operator: 'match',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M06.diff b/agents/darkwing/work/queue-53-review/r2/mut/M06.diff
new file mode 100644
index 00000000..1fe16936
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M06.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..7c8f15db 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -41,7 +41,7 @@
+ palette = p.id;
+ if (!['system', 'light', 'dim', 'dark'].includes(mode)) mode = 'system';
+ document.documentElement.dataset.palette = palette;
+- if (mode === 'system') delete document.documentElement.dataset.mode; else document.documentElement.dataset.mode = mode;
++ document.documentElement.dataset.mode = mode;
+ $('palette').value = palette; $('mode').value = mode;
+ try { localStorage.setItem('mosaic-console-appearance', JSON.stringify({ palette, mode })); } catch {}
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M06.txt b/agents/darkwing/work/queue-53-review/r2/mut/M06.txt
new file mode 100644
index 00000000..faafd41e
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M06.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (15272.623465ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (31722.087198ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (30330.451829ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (2416.562027ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (37.29549ms)
+✔ bus refusals map to statuses and never carry a path or a stack (18.416107ms)
+✔ humanCall speaks the human transport protocol without blocking the server (1676.411784ms)
+✔ busReader takes --business, else the live bus host, else refuses (250.959993ms)
+✔ humanCall kills a transport that runs past its timeout (527.099896ms)
+✔ serve refuses a --business value that is not a business id (180.793544ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (28900.406029ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4313.697934ms)
+✔ conversation view: a newer session with no readable history keeps the marker (2351.575056ms)
+✔ conversation view: seats without history say so and offer no reply (2446.325824ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (10421.525061ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (73032.592659ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (12366.957176ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (33923.140487ms)
+✔ loopback host and board origin fail closed (8.196194ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (445.360351ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (152.315148ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (923.203685ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.929341ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.043473ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.771135ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5708.723686ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (19111.162225ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 73383.749377
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5708.723686ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+
+ true !== false
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:108:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: true,
+ expected: false,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M07.diff b/agents/darkwing/work/queue-53-review/r2/mut/M07.diff
new file mode 100644
index 00000000..4044ff4a
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M07.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..c6273452 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -481,7 +481,7 @@
+ const t = $('toast'); clearTimeout(toastTimer);
+ if (text === null) { t.className = 'toast'; t.textContent = ''; return; }
+ t.className = `toast on${error ? ' err' : ''}`;
+- t.innerHTML = `${esc(text)}${error ? '' : ''}`;
++ t.innerHTML = `${text}${error ? '' : ''}`;
+ if (!error) toastTimer = setTimeout(() => toast(null), 2600);
+ }
+
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M07.txt b/agents/darkwing/work/queue-53-review/r2/mut/M07.txt
new file mode 100644
index 00000000..917705d6
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M07.txt
@@ -0,0 +1,36 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (9677.560125ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5238.868632ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (11020.061708ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (412.713989ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (210.605785ms)
+✔ bus refusals map to statuses and never carry a path or a stack (68.144102ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2938.448863ms)
+✔ busReader takes --business, else the live bus host, else refuses (506.983539ms)
+✔ humanCall kills a transport that runs past its timeout (567.330888ms)
+✔ serve refuses a --business value that is not a business id (810.105696ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (7229.729607ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (8811.289186ms)
+✔ conversation view: a newer session with no readable history keeps the marker (4399.608573ms)
+✔ conversation view: seats without history say so and offer no reply (1755.37456ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (7441.830627ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (58785.923958ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (9615.513932ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24892.390944ms)
+✔ loopback host and board origin fail closed (12.008815ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (182.542287ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (212.873578ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1994.917068ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.662111ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.799647ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (3.174412ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (13373.047364ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (6417.896432ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 27
+ℹ fail 0
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 59334.66732
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M08.diff b/agents/darkwing/work/queue-53-review/r2/mut/M08.diff
new file mode 100644
index 00000000..0bd2c5d4
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M08.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..846b6f36 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -500,7 +500,7 @@
+ const q = $('cmdk-input').value.trim().toLowerCase();
+ pkShown = pkAll.filter(i => !q || `${i.label} ${i.group}`.toLowerCase().includes(q)).slice(0, 50);
+ pkAt = Math.min(pkAt, Math.max(0, pkShown.length - 1));
+- $('cmdk-list').innerHTML = pkShown.length ? pkShown.map((i, n) => `
';
+ if (pkShown.length) { $('cmdk-input').setAttribute('aria-activedescendant', `cmdk-opt-${pkAt}`); $(`cmdk-opt-${pkAt}`)?.scrollIntoView({ block: 'nearest' }); }
+ else $('cmdk-input').removeAttribute('aria-activedescendant');
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M08.txt b/agents/darkwing/work/queue-53-review/r2/mut/M08.txt
new file mode 100644
index 00000000..f7aa7672
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M08.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (6262.461685ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (8323.877976ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (11564.402673ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (2264.208911ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (86.487989ms)
+✔ bus refusals map to statuses and never carry a path or a stack (69.631861ms)
+✔ humanCall speaks the human transport protocol without blocking the server (3169.117616ms)
+✔ busReader takes --business, else the live bus host, else refuses (343.785283ms)
+✔ humanCall kills a transport that runs past its timeout (532.902486ms)
+✔ serve refuses a --business value that is not a business id (400.71332ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (6321.331007ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4518.74495ms)
+✔ conversation view: a newer session with no readable history keeps the marker (2848.536998ms)
+✔ conversation view: seats without history say so and offer no reply (1705.987269ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6589.386693ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (60212.056998ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5627.527147ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24935.535973ms)
+✔ loopback host and board origin fail closed (10.838303ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (707.851249ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (335.465899ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1717.022266ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.259551ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.791564ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (3.433592ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (9944.951011ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (3695.850599ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 60869.027066
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (3695.850599ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+
+ 2 !== 0
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:413:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 2,
+ expected: 0,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M09.diff b/agents/darkwing/work/queue-53-review/r2/mut/M09.diff
new file mode 100644
index 00000000..08f8b7a0
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M09.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
+index ed6d2d96..099ad74c 100644
+--- a/packages/webui/src/public/shell.css
++++ b/packages/webui/src/public/shell.css
+@@ -18,7 +18,7 @@ body{font:400 14px/1.5 var(--font);color:var(--text);background:var(--canvas)}
+ code,kbd,pre,.mono{font-family:var(--mono);font-size:12.5px}
+ kbd{border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;padding:0 .35em;background:var(--surface);color:var(--strong);white-space:nowrap;font-size:11.5px}
+ .count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}
+-:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
++:focus-visible{outline:2px solid var(--focus);outline-offset:0}
+ table.sessions tbody tr:focus-visible,table.s1-table tbody tr:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
+ svg.i{width:18px;height:18px;flex:none;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
+
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M09.txt b/agents/darkwing/work/queue-53-review/r2/mut/M09.txt
new file mode 100644
index 00000000..9b19dade
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M09.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (7609.074415ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (11452.724025ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (12309.820512ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (2304.099495ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (94.109243ms)
+✔ bus refusals map to statuses and never carry a path or a stack (42.272421ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2371.801182ms)
+✔ busReader takes --business, else the live bus host, else refuses (410.928224ms)
+✔ humanCall kills a transport that runs past its timeout (531.203001ms)
+✔ serve refuses a --business value that is not a business id (306.449847ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (7788.383155ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4662.276458ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1912.219392ms)
+✔ conversation view: seats without history say so and offer no reply (1496.764289ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (8619.000837ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (59599.785751ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (7467.265369ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (25221.11973ms)
+✔ loopback host and board origin fail closed (11.544617ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (1719.852203ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (185.65663ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1065.79537ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (6.317784ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (14.868056ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (5.161292ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5535.667757ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (6509.811784ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 60160.369576
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5535.667757ms)
+ AssertionError [ERR_ASSERTION]: #cmdk outline offset
+
+ 0 !== 2
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:181:125)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 0,
+ expected: 2,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M10.diff b/agents/darkwing/work/queue-53-review/r2/mut/M10.diff
new file mode 100644
index 00000000..f4667afe
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M10.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
+index ed6d2d96..cc401c3b 100644
+--- a/packages/webui/src/public/shell.css
++++ b/packages/webui/src/public/shell.css
+@@ -18,7 +18,7 @@ body{font:400 14px/1.5 var(--font);color:var(--text);background:var(--canvas)}
+ code,kbd,pre,.mono{font-family:var(--mono);font-size:12.5px}
+ kbd{border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;padding:0 .35em;background:var(--surface);color:var(--strong);white-space:nowrap;font-size:11.5px}
+ .count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}
+-:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
++:focus-visible{outline:1px solid var(--focus);outline-offset:2px}
+ table.sessions tbody tr:focus-visible,table.s1-table tbody tr:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
+ svg.i{width:18px;height:18px;flex:none;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
+
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M10.txt b/agents/darkwing/work/queue-53-review/r2/mut/M10.txt
new file mode 100644
index 00000000..4cd24e41
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M10.txt
@@ -0,0 +1,53 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (10029.216ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (11567.747539ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (12394.616919ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (2135.731454ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (106.029912ms)
+✔ bus refusals map to statuses and never carry a path or a stack (43.317817ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2315.691295ms)
+✔ busReader takes --business, else the live bus host, else refuses (428.29625ms)
+✔ humanCall kills a transport that runs past its timeout (532.121068ms)
+✔ serve refuses a --business value that is not a business id (200.505373ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (10797.128621ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3575.186349ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1850.44415ms)
+✔ conversation view: seats without history say so and offer no reply (1664.190106ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (8184.327825ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (59155.373445ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (9016.166527ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (27198.316759ms)
+✔ loopback host and board origin fail closed (10.638221ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (1333.045642ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (516.069031ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1227.942831ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.552045ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.997839ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (3.263111ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8865.020042ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (5262.681363ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 59903.296319
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8865.020042ms)
+ AssertionError [ERR_ASSERTION]: #cmdk outline 1px
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:181:69)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: false,
+ expected: true,
+ operator: '==',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M11.diff b/agents/darkwing/work/queue-53-review/r2/mut/M11.diff
new file mode 100644
index 00000000..4f7eeb70
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M11.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
+index ed6d2d96..a07327e6 100644
+--- a/packages/webui/src/public/shell.css
++++ b/packages/webui/src/public/shell.css
+@@ -166,7 +166,7 @@ body.on-bus #board-refused{display:none}
+ .cmd-right label{flex:1 1 0;min-width:0}
+ .cmd-right .btn{flex:none}
+ /* The section list is one strip that scrolls inside itself (IMPLEMENTING.md), so more sections never add rows. */
+- .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;flex-basis:100%;min-width:0;max-width:100%;gap:2px;padding-bottom:2px;scrollbar-width:thin}
++ .s1-sections{display:flex;flex-wrap:wrap;overflow-x:visible;flex-basis:100%;min-width:0;max-width:100%;gap:2px;padding-bottom:2px;scrollbar-width:thin}
+ .s1-sections>li{flex:none}
+ .s1-section{border-radius:var(--r);padding:5px 8px;white-space:nowrap;flex:none}
+ .inspector{inset:0;top:0;width:100%;z-index:40;box-shadow:none}
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M11.txt b/agents/darkwing/work/queue-53-review/r2/mut/M11.txt
new file mode 100644
index 00000000..9270080f
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M11.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (6072.849226ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (7648.73759ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (10575.99292ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (2314.72617ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (71.737636ms)
+✔ bus refusals map to statuses and never carry a path or a stack (26.592189ms)
+✔ humanCall speaks the human transport protocol without blocking the server (1969.155253ms)
+✔ busReader takes --business, else the live bus host, else refuses (346.614032ms)
+✔ humanCall kills a transport that runs past its timeout (529.001693ms)
+✔ serve refuses a --business value that is not a business id (204.313294ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5650.641432ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4927.264395ms)
+✔ conversation view: a newer session with no readable history keeps the marker (3456.642762ms)
+✔ conversation view: seats without history say so and offer no reply (3245.69597ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6179.814923ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56099.101119ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6232.410476ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24265.087834ms)
+✔ loopback host and board origin fail closed (11.345162ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (383.542915ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (858.113627ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (926.123488ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.490977ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.558934ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (4.898223ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6025.485868ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (5394.399273ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 56657.087449
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6025.485868ms)
+ AssertionError [ERR_ASSERTION]: one row at 360px
+
+ 2 !== 1
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:204:14)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 2,
+ expected: 1,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M12.diff b/agents/darkwing/work/queue-53-review/r2/mut/M12.diff
new file mode 100644
index 00000000..47605e35
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M12.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..046ff49e 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -209,7 +209,7 @@
+ const items = [['/', 'Board', '', 'board'], ['/inbox', 'Inbox', inboxCount ? `${inboxCount.open}${inboxCount.blocking ? ` ${blockChip(`${inboxCount.blocking} blocking`)}` : ''}` : '', 'inbox'], ['/tasks', 'Tasks', '', 'tasks'], ['/agents', 'Agents', '', 'agents']];
+ $('sections').innerHTML = items.map(([h, l, extra, icon]) => {
+ const cur = h === '/' ? route === '/' : route.startsWith(h) || (h === '/tasks' && route.startsWith('/trail/task')) || (h === '/inbox' && route.startsWith('/trail/decision'));
+- return `
`;
+ }).join('');
+ }
+ function countInbox(rows) { inboxCount = { open: rows.length, blocking: rows.filter(d => d.blocking).length }; }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M12.txt b/agents/darkwing/work/queue-53-review/r2/mut/M12.txt
new file mode 100644
index 00000000..b9f697ef
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M12.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5401.316742ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5276.112592ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8044.16258ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (1584.166767ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (105.247657ms)
+✔ bus refusals map to statuses and never carry a path or a stack (53.793812ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2250.629516ms)
+✔ busReader takes --business, else the live bus host, else refuses (269.127594ms)
+✔ humanCall kills a transport that runs past its timeout (530.269905ms)
+✔ serve refuses a --business value that is not a business id (219.283891ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4958.475554ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3630.443988ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1294.07507ms)
+✔ conversation view: seats without history say so and offer no reply (1115.599978ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5574.722064ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56570.885372ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5176.575671ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23510.05973ms)
+✔ loopback host and board origin fail closed (10.17656ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (137.753736ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (88.553236ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1859.386694ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.686138ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.846105ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (4.440777ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5245.349397ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3503.212069ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 57151.799923
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5245.349397ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+
+ 0 !== 4
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:196:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 0,
+ expected: 4,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M13.diff b/agents/darkwing/work/queue-53-review/r2/mut/M13.diff
new file mode 100644
index 00000000..a3389152
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M13.diff
@@ -0,0 +1,12 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..39477043 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -296,7 +296,6 @@
+ function accept(value) {
+ if (!value || !Array.isArray(value.sessions) || value.sessions.some(r => !r || typeof r.project !== 'string' || typeof r.agent !== 'string')) throw new Error('Invalid board session data');
+ data = value; failed = false; $('error').hidden = true; $('error').className = 'banner err';
+- $('board-refused').hidden = true; document.body.classList.remove('board-refused');
+ for (const id of awaiting.keys()) { const r = row(id); if (r && !pending(r)) awaiting.delete(id); }
+ render();
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M13.txt b/agents/darkwing/work/queue-53-review/r2/mut/M13.txt
new file mode 100644
index 00000000..b1b05b2e
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M13.txt
@@ -0,0 +1,55 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5471.314194ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (7878.85227ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8907.311012ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (944.751298ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (84.28557ms)
+✔ bus refusals map to statuses and never carry a path or a stack (63.12128ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2026.814322ms)
+✔ busReader takes --business, else the live bus host, else refuses (240.833469ms)
+✔ humanCall kills a transport that runs past its timeout (527.244614ms)
+✔ serve refuses a --business value that is not a business id (169.201231ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5690.430019ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3845.901684ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1522.881981ms)
+✔ conversation view: seats without history say so and offer no reply (957.590092ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5842.696786ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56214.274595ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5702.561978ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (26371.006181ms)
+✔ loopback host and board origin fail closed (7.080199ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (125.853509ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (99.128202ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (957.323889ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.322481ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.617784ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.454045ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5828.413235ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (5116.480007ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 56613.263322
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5828.413235ms)
+ AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
+
+ 'none'
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:161:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'none',
+ expected: 'none',
+ operator: 'notStrictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M14.diff b/agents/darkwing/work/queue-53-review/r2/mut/M14.diff
new file mode 100644
index 00000000..1ec5e1bf
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M14.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..4eb91e82 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -532,7 +532,7 @@
+ const a = e.target.closest?.('#bus-view table.s1-table td.s1-title a');
+ if (!a || (e.key !== 'ArrowDown' && e.key !== 'ArrowUp')) return;
+ const links = [...a.closest('table').querySelectorAll('td.s1-title a')], i = links.indexOf(a);
+- e.preventDefault(); links[i + (e.key === 'ArrowDown' ? 1 : -1)]?.focus();
++ e.preventDefault(); links[i + (e.key === 'ArrowDown' ? -1 : 1)]?.focus();
+ });
+ window.addEventListener('hashchange', () => render(true));
+ $('refresh').addEventListener('click', () => render(false));
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M14.txt b/agents/darkwing/work/queue-53-review/r2/mut/M14.txt
new file mode 100644
index 00000000..e114542e
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M14.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (6928.118795ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (8209.259569ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (12049.913654ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (2984.527328ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (45.725005ms)
+✔ bus refusals map to statuses and never carry a path or a stack (25.241585ms)
+✔ humanCall speaks the human transport protocol without blocking the server (1825.996919ms)
+✔ busReader takes --business, else the live bus host, else refuses (694.772009ms)
+✔ humanCall kills a transport that runs past its timeout (528.374368ms)
+✔ serve refuses a --business value that is not a business id (184.930858ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (7523.995068ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4770.585661ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1243.339041ms)
+✔ conversation view: seats without history say so and offer no reply (1088.351142ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (7949.559455ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56700.906036ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (7259.807748ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23891.089464ms)
+✔ loopback host and board origin fail closed (7.728754ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (866.179772ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (126.918795ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (575.777593ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.024718ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.983577ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.447936ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7103.550163ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (5312.733709ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 57103.536658
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7103.550163ms)
+ AssertionError [ERR_ASSERTION]: The input did not match the regular expression /Second task/. Input:
+
+ '#7 Kept task'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:224:38)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: '#7 Kept task',
+ expected: /Second task/,
+ operator: 'match',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M15.diff b/agents/darkwing/work/queue-53-review/r2/mut/M15.diff
new file mode 100644
index 00000000..e145410e
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M15.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/serve.mjs b/packages/webui/src/serve.mjs
+index 280a228f..93a1958f 100644
+--- a/packages/webui/src/serve.mjs
++++ b/packages/webui/src/serve.mjs
+@@ -22,7 +22,7 @@ const files = new Map([
+ ['/', ['index.html', 'text/html; charset=utf-8']],
+ ...['app.js', 'brand.js', 'bus.js'].map(f => ['/' + f, [f, 'text/javascript; charset=utf-8']]),
+ ...['shared/app.css', 'tokens.css', 'console.css', 'live.css', 'bus.css', 'shell.css'].map(f => ['/' + f, [f, 'text/css; charset=utf-8']]),
+- ['/icons.svg', ['icons.svg', 'image/svg+xml']],
++ ['/icons.svg', ['icons.svg', 'text/plain']],
+ ...[400, 500, 600, 700].map(w => [`/assets/fonts/manrope-${w}.woff2`, [`assets/fonts/manrope-${w}.woff2`, 'font/woff2']]),
+ ...[400, 500, 700].map(w => [`/assets/fonts/jetbrains-mono-${w}.woff2`, [`assets/fonts/jetbrains-mono-${w}.woff2`, 'font/woff2']]),
+ ]);
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M15.txt b/agents/darkwing/work/queue-53-review/r2/mut/M15.txt
new file mode 100644
index 00000000..68b9bf41
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M15.txt
@@ -0,0 +1,53 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5776.919786ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5899.647375ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7817.95423ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (304.00469ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (92.68169ms)
+✔ bus refusals map to statuses and never carry a path or a stack (59.725948ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2162.640231ms)
+✔ busReader takes --business, else the live bus host, else refuses (417.956067ms)
+✔ humanCall kills a transport that runs past its timeout (529.93184ms)
+✔ serve refuses a --business value that is not a business id (154.497633ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5253.517004ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3024.904581ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1715.174597ms)
+✔ conversation view: seats without history say so and offer no reply (1329.071054ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5838.646156ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56097.068788ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5288.871253ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24117.940082ms)
+✔ loopback host and board origin fail closed (9.101418ms)
+✖ real board fixture passes through WebUI; assets and isolated seen/reply work (100.398615ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (96.109877ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (879.497882ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.300521ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.702869ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.21885ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8260.236526ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3414.935311ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 56499.507114
+
+✖ failing tests:
+
+test at tests/serve.test.mjs:22:1
+✖ real board fixture passes through WebUI; assets and isolated seen/reply work (100.398615ms)
+ AssertionError [ERR_ASSERTION]: /icons.svg
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/serve.test.mjs:41:101)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: false,
+ expected: true,
+ operator: '==',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M16.diff b/agents/darkwing/work/queue-53-review/r2/mut/M16.diff
new file mode 100644
index 00000000..7ac1ec1a
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M16.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
+index ed6d2d96..7fb39c59 100644
+--- a/packages/webui/src/public/shell.css
++++ b/packages/webui/src/public/shell.css
+@@ -17,7 +17,7 @@ body{font:400 14px/1.5 var(--font);color:var(--text);background:var(--canvas)}
+ .tree-title,.label{font:700 11px/1.3 var(--font);letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
+ code,kbd,pre,.mono{font-family:var(--mono);font-size:12.5px}
+ kbd{border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;padding:0 .35em;background:var(--surface);color:var(--strong);white-space:nowrap;font-size:11.5px}
+-.count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}
++
+ :focus-visible{outline:2px solid var(--focus);outline-offset:2px}
+ table.sessions tbody tr:focus-visible,table.s1-table tbody tr:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
+ svg.i{width:18px;height:18px;flex:none;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M16.txt b/agents/darkwing/work/queue-53-review/r2/mut/M16.txt
new file mode 100644
index 00000000..6f0fb147
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M16.txt
@@ -0,0 +1,58 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (7032.157582ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5974.415759ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8270.130573ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (480.132084ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (215.284099ms)
+✔ bus refusals map to statuses and never carry a path or a stack (202.050789ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2541.451512ms)
+✔ busReader takes --business, else the live bus host, else refuses (286.306148ms)
+✔ humanCall kills a transport that runs past its timeout (528.640541ms)
+✔ serve refuses a --business value that is not a business id (250.072087ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5934.362349ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3261.510465ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1883.827199ms)
+✔ conversation view: seats without history say so and offer no reply (1497.152757ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6942.276403ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (57525.879316ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6010.051378ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22782.377069ms)
+✔ loopback host and board origin fail closed (9.765723ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (126.74125ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (141.695296ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1790.575205ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.988386ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.255569ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.41268ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6915.352548ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3708.441788ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 58096.23649
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6915.352548ms)
+ AssertionError [ERR_ASSERTION]: #fresh
+ + actual - expected
+
+ + 'normal'
+ - 'tabular-nums'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:197:60)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 'normal',
+ expected: 'tabular-nums',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M17.diff b/agents/darkwing/work/queue-53-review/r2/mut/M17.diff
new file mode 100644
index 00000000..062e474b
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M17.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..8ccceb1f 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -43,7 +43,7 @@
+ document.documentElement.dataset.palette = palette;
+ if (mode === 'system') delete document.documentElement.dataset.mode; else document.documentElement.dataset.mode = mode;
+ $('palette').value = palette; $('mode').value = mode;
+- try { localStorage.setItem('mosaic-console-appearance', JSON.stringify({ palette, mode })); } catch {}
++ try { localStorage.setItem('mosaic-console-look', JSON.stringify({ palette, mode })); } catch {}
+ }
+ $('palette').innerHTML = Brand.palettes.map(p => ``).join('');
+ try { const saved = JSON.parse(localStorage.getItem('mosaic-console-appearance')); if (saved) { palette = saved.palette; mode = saved.mode; } } catch {}
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M17.txt b/agents/darkwing/work/queue-53-review/r2/mut/M17.txt
new file mode 100644
index 00000000..19cad8ce
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M17.txt
@@ -0,0 +1,48 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (7219.196692ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (7659.592024ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8632.286954ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (282.571341ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (122.635688ms)
+✔ bus refusals map to statuses and never carry a path or a stack (75.618193ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2211.018612ms)
+✔ busReader takes --business, else the live bus host, else refuses (397.540081ms)
+✔ humanCall kills a transport that runs past its timeout (566.728797ms)
+✔ serve refuses a --business value that is not a business id (174.980802ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (7757.890315ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2813.782157ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1649.062025ms)
+✔ conversation view: seats without history say so and offer no reply (1061.913097ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (7800.58257ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (57377.700776ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (7773.93166ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (25903.694289ms)
+✔ loopback host and board origin fail closed (10.020241ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (131.068377ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (140.661963ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1249.439995ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (2.059447ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.730261ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.702814ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7911.76887ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3765.63761ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 57861.215013
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7911.76887ms)
+ Error: Uncaught: TypeError: Cannot read properties of null (reading 'mode')
+ at :1:62
+ at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/browser.mjs:44:35)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:121:18)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M18.diff b/agents/darkwing/work/queue-53-review/r2/mut/M18.diff
new file mode 100644
index 00000000..c511cead
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M18.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
+index ed6d2d96..9b515c06 100644
+--- a/packages/webui/src/public/shell.css
++++ b/packages/webui/src/public/shell.css
+@@ -97,7 +97,7 @@ table.s1-table td code{font-size:12.5px;white-space:nowrap}
+ .skel{display:block;height:12px;border-radius:4px;background:var(--raised);animation:skel 1.4s ease-in-out infinite}
+ .skel:nth-child(odd){width:82%}
+ @keyframes skel{50%{opacity:.45}}
+-body.board-refused #board-view{display:none}
++
+ body.on-bus #board-refused{display:none}
+
+ /* Toast: one line, polite, bottom centre. */
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M18.txt b/agents/darkwing/work/queue-53-review/r2/mut/M18.txt
new file mode 100644
index 00000000..f8e4e68b
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M18.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3927.278203ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4657.75327ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5524.823411ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (257.569233ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (197.475849ms)
+✔ bus refusals map to statuses and never carry a path or a stack (62.384222ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2352.562117ms)
+✔ busReader takes --business, else the live bus host, else refuses (180.530201ms)
+✔ humanCall kills a transport that runs past its timeout (533.606041ms)
+✔ serve refuses a --business value that is not a business id (165.095593ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4242.583993ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2828.148222ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1663.099588ms)
+✔ conversation view: seats without history say so and offer no reply (1125.53899ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4488.22519ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53962.334042ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4220.745217ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23229.025406ms)
+✔ loopback host and board origin fail closed (11.407687ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (184.096852ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (295.763247ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1230.782963ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.468688ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.116895ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (4.445183ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4761.914043ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3437.488223ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54409.271455
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4761.914043ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+
+ 'block' !== 'none'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:150:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'block',
+ expected: 'none',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M19.diff b/agents/darkwing/work/queue-53-review/r2/mut/M19.diff
new file mode 100644
index 00000000..26813879
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M19.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..de1a56b8 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -433,7 +433,7 @@
+ try { html = await view(live, path, new URLSearchParams(query)); readAt = live.oldest(); }
+ catch (err) {
+ const kept = reader(false);
+- try { if (refusal(err)) throw err; html = await view(kept, path, new URLSearchParams(query)); readAt = kept.oldest(); html = staleBanner(err) + html; state = 'stale'; }
++ try { html = await view(kept, path, new URLSearchParams(query)); readAt = kept.oldest(); html = staleBanner(err) + html; state = 'stale'; }
+ catch { html = failedView(err); state = refusal(err) ? 'refused' : 'failed'; }
+ if (refusal(err)) forget();
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M19.txt b/agents/darkwing/work/queue-53-review/r2/mut/M19.txt
new file mode 100644
index 00000000..766b1372
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M19.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4453.411945ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5264.477386ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6343.176422ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (555.570309ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (154.111616ms)
+✔ bus refusals map to statuses and never carry a path or a stack (80.416177ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2073.643449ms)
+✔ busReader takes --business, else the live bus host, else refuses (267.731498ms)
+✔ humanCall kills a transport that runs past its timeout (530.094794ms)
+✔ serve refuses a --business value that is not a business id (169.493923ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4369.121592ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2242.808825ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1227.780012ms)
+✔ conversation view: seats without history say so and offer no reply (917.943994ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4861.316701ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55068.800905ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4414.74079ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22879.258682ms)
+✔ loopback host and board origin fail closed (8.430657ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (122.99485ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (126.993216ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1042.823066ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.949745ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.846898ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.237079ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8600.36373ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (5870.56617ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 25
+ℹ fail 2
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 55530.663629
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8600.36373ms)
+ Error: Uncaught (in promise) Error: Condition timed out: !!document.querySelector("#bus-view .banner.ref"): undefined
+ at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/browser.mjs:44:35)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:230:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (5870.56617ms)
+ Error: Uncaught (in promise) Error: Condition timed out: !!document.querySelector("#bus-view .banner.ref"): undefined
+ at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/browser.mjs:44:35)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:378:9)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M20.diff b/agents/darkwing/work/queue-53-review/r2/mut/M20.diff
new file mode 100644
index 00000000..e3b7754c
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M20.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..e9f550a1 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -314,7 +314,7 @@
+ $('status').textContent = 'Not read: the board refused the read';
+ inspect(); convForm();
+ }
+- $('error').className = refused ? 'banner ref' : 'banner err';
++ $('error').className = 'banner err';
+ $('board-refused').hidden = !refused; document.body.classList.toggle('board-refused', refused);
+ $('error').innerHTML = refused
+ ? `
The board refused the read. refused: ${esc(err.message)} Board: ${esc(board)}. Console shows nothing rather than a guess. Use Refresh to try again.
`
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M20.txt b/agents/darkwing/work/queue-53-review/r2/mut/M20.txt
new file mode 100644
index 00000000..01c59928
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M20.txt
@@ -0,0 +1,59 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3790.126485ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4070.339367ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6162.782857ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (326.590311ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (396.862759ms)
+✔ bus refusals map to statuses and never carry a path or a stack (110.608731ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2385.844223ms)
+✔ busReader takes --business, else the live bus host, else refuses (254.94543ms)
+✔ humanCall kills a transport that runs past its timeout (529.223498ms)
+✔ serve refuses a --business value that is not a business id (220.172057ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4138.868392ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2853.917903ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1258.099466ms)
+✔ conversation view: seats without history say so and offer no reply (812.16505ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4183.301896ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54639.801943ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4094.058594ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23424.360921ms)
+✔ loopback host and board origin fail closed (16.59858ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (188.870931ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (278.788458ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1419.616783ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (4.12186ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.602968ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (5.209893ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4052.812383ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (2860.652705ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 55419.923852
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4052.812383ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ + actual - expected
+
+ + 'banner err'
+ - 'banner ref'
+ ^
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:148:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'banner err',
+ expected: 'banner ref',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M21.diff b/agents/darkwing/work/queue-53-review/r2/mut/M21.diff
new file mode 100644
index 00000000..197c1c19
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M21.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..dc273736 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -370,7 +370,7 @@
+ // A refusal fails closed: no kept data, the code in mono. Any other failure keeps the last read, labelled with its time.
+ const refusal = err => err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);
+ // After a refusal nothing read before is shown anywhere: not in a view, the palette or the Inbox count.
+- function forget() { last.clear(); inboxCount = null; }
++ function forget() {}
+ const failedView = err => `${head(failTitle(err))}
${refusal(err) ? `refused: ${txt(err.code)}. ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.
${retry}
${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
+ const staleBanner = err => `
The last read failed. ${why(err)} This is what was read before, ${when(readAt)}. Nothing was changed.
${retry}
`;
+ // Freshness line in the command bar for bus pages.
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M21.txt b/agents/darkwing/work/queue-53-review/r2/mut/M21.txt
new file mode 100644
index 00000000..182963e6
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M21.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3567.402844ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4006.199314ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5272.110688ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (304.233276ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (107.385725ms)
+✔ bus refusals map to statuses and never carry a path or a stack (58.355469ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2413.175616ms)
+✔ busReader takes --business, else the live bus host, else refuses (143.018572ms)
+✔ humanCall kills a transport that runs past its timeout (529.454661ms)
+✔ serve refuses a --business value that is not a business id (225.520972ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3440.64227ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2063.812556ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1146.976215ms)
+✔ conversation view: seats without history say so and offer no reply (996.933872ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (3432.385645ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53753.61663ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3517.316598ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22592.030121ms)
+✔ loopback host and board origin fail closed (9.548699ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (116.171793ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (100.990811ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1426.440429ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.085029ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.918929ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.183322ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6763.556991ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (1226.800369ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54139.811347
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (1226.800369ms)
+ AssertionError [ERR_ASSERTION]: #/inbox drops the Inbox count on a human-required refusal
+
+ 2 !== 0
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:383:16)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 2,
+ expected: 0,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M22.diff b/agents/darkwing/work/queue-53-review/r2/mut/M22.diff
new file mode 100644
index 00000000..544410e2
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M22.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..ac5ee574 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -423,7 +423,7 @@
+ // The board page keeps its own title; the Inbox count still follows the bus.
+ if (shown !== null) { shown = null; $('bus-view').innerHTML = ''; document.title = 'Mosaic Console'; if (navigated) $('main').focus(); }
+ try { const r = await fetchRead('inbox'); last.set('inbox', r); if (g === gen) { countInbox(r.rows); sections(path); } }
+- catch (err) { if (refusal(err)) { forget(); if (g === gen) sections(path); } }
++ catch {}
+ if (g === gen) schedule();
+ return;
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M22.txt b/agents/darkwing/work/queue-53-review/r2/mut/M22.txt
new file mode 100644
index 00000000..d6ea9083
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M22.txt
@@ -0,0 +1,47 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3839.150823ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4398.773937ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5161.938687ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (257.233571ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (75.691859ms)
+✔ bus refusals map to statuses and never carry a path or a stack (70.807746ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2116.92695ms)
+✔ busReader takes --business, else the live bus host, else refuses (193.29717ms)
+✔ humanCall kills a transport that runs past its timeout (549.215635ms)
+✔ serve refuses a --business value that is not a business id (175.964255ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4205.85625ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2062.291696ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1227.269696ms)
+✔ conversation view: seats without history say so and offer no reply (1221.050447ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4210.391938ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53870.242716ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3848.544339ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22700.192342ms)
+✔ loopback host and board origin fail closed (8.406871ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (124.60245ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (103.540624ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (893.165438ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.457484ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.707206ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.687255ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7388.987757ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (7624.873854ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54287.706116
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (7624.873854ms)
+ Error: Uncaught (in promise) Error: Condition timed out: !document.querySelector("#sections .count"): undefined
+ at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/browser.mjs:44:35)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:418:68)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M23.diff b/agents/darkwing/work/queue-53-review/r2/mut/M23.diff
new file mode 100644
index 00000000..19ee3de5
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M23.diff
@@ -0,0 +1,12 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..76758e26 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -435,7 +435,6 @@
+ const kept = reader(false);
+ try { if (refusal(err)) throw err; html = await view(kept, path, new URLSearchParams(query)); readAt = kept.oldest(); html = staleBanner(err) + html; state = 'stale'; }
+ catch { html = failedView(err); state = refusal(err) ? 'refused' : 'failed'; }
+- if (refusal(err)) forget();
+ }
+ if (g !== gen) return;
+ freshBus(state);
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M23.txt b/agents/darkwing/work/queue-53-review/r2/mut/M23.txt
new file mode 100644
index 00000000..661aab18
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M23.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3690.442184ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3849.350418ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5179.717435ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (231.525972ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (137.616984ms)
+✔ bus refusals map to statuses and never carry a path or a stack (62.325904ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2171.007692ms)
+✔ busReader takes --business, else the live bus host, else refuses (141.854219ms)
+✔ humanCall kills a transport that runs past its timeout (528.99615ms)
+✔ serve refuses a --business value that is not a business id (160.592221ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3644.327268ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2456.357644ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1296.77647ms)
+✔ conversation view: seats without history say so and offer no reply (1069.763404ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (3612.07748ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53490.878162ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3605.370048ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22582.383388ms)
+✔ loopback host and board origin fail closed (9.211601ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (128.119652ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (107.85881ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (995.745599ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.903771ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.53098ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.427432ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7142.657614ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (1130.262824ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 53881.267549
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (1130.262824ms)
+ AssertionError [ERR_ASSERTION]: #/inbox drops the Inbox count on a human-required refusal
+
+ 2 !== 0
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:383:16)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 2,
+ expected: 0,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M24.diff b/agents/darkwing/work/queue-53-review/r2/mut/M24.diff
new file mode 100644
index 00000000..8b08aa4a
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M24.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..49e54847 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -511,7 +511,7 @@
+ pkBack = document.activeElement; pkAt = 0; $('cmdk-input').value = '';
+ pkItems(); pkFill(); d.showModal(); $('cmdk-input').focus();
+ Promise.allSettled(['inbox', 'tasks'].map(async v => last.set(v, await fetchRead(v)))).then(rs => {
+- if (rs.some(r => r.status === 'rejected' && refusal(r.reason))) { forget(); sections(routeOf().split('?')[0]); }
++
+ if (d.open) { pkItems(); pkFill(); }
+ });
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M24.txt b/agents/darkwing/work/queue-53-review/r2/mut/M24.txt
new file mode 100644
index 00000000..dac5d831
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M24.txt
@@ -0,0 +1,47 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3094.868838ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4479.963024ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5207.878049ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (253.189333ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (166.673421ms)
+✔ bus refusals map to statuses and never carry a path or a stack (250.543874ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2711.339811ms)
+✔ busReader takes --business, else the live bus host, else refuses (124.064744ms)
+✔ humanCall kills a transport that runs past its timeout (528.361869ms)
+✔ serve refuses a --business value that is not a business id (179.900947ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (2787.993908ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2713.629338ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1517.334847ms)
+✔ conversation view: seats without history say so and offer no reply (1262.349937ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2789.431642ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53580.275598ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (2782.596251ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22064.392292ms)
+✔ loopback host and board origin fail closed (7.027509ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (107.473266ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (83.115149ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1860.131739ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.88699ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.960146ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (1.992866ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6498.656891ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (7332.608632ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54368.682085
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (7332.608632ms)
+ Error: Uncaught (in promise) Error: Condition timed out: document.querySelector("#cmdk-dialog").open && [...document.querySelectorAll("#cmdk-list [data-href]")].map(e=>e.dataset.href).length===4 && !document.querySelector("#sections .count"): undefined
+ at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/browser.mjs:44:35)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:405:34)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M25.diff b/agents/darkwing/work/queue-53-review/r2/mut/M25.diff
new file mode 100644
index 00000000..99cf7a15
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M25.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..510aea43 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -307,7 +307,7 @@
+ const refused = err.status === 403;
+ failed = refused ? 'refused' : true; $('error').hidden = false;
+ if (refused) {
+- data = null; selected = null; project = null;
++ data = null; project = null;
+ $('projects').innerHTML = '
Not read: the board refused the read.
';
+ for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';
+ $('footer').textContent = 'Board not read: refused';
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M25.txt b/agents/darkwing/work/queue-53-review/r2/mut/M25.txt
new file mode 100644
index 00000000..8b80cd93
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M25.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3086.813365ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3278.687202ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5638.664355ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (239.637465ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (197.053056ms)
+✔ bus refusals map to statuses and never carry a path or a stack (168.899142ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2952.702683ms)
+✔ busReader takes --business, else the live bus host, else refuses (114.932507ms)
+✔ humanCall kills a transport that runs past its timeout (528.008507ms)
+✔ serve refuses a --business value that is not a business id (168.452683ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3069.725175ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2812.549981ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1122.606966ms)
+✔ conversation view: seats without history say so and offer no reply (769.203298ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2877.518379ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53655.195021ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (2938.919633ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22116.008047ms)
+✔ loopback host and board origin fail closed (6.758241ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (112.880418ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (110.760082ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1924.942791ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.902975ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.804197ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.006071ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2930.528977ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3482.984298ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54060.857983
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2930.528977ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+
+ false !== true
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:152:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: false,
+ expected: true,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M26.diff b/agents/darkwing/work/queue-53-review/r2/mut/M26.diff
new file mode 100644
index 00000000..0b0edd2a
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M26.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..2de73dc9 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -282,7 +282,7 @@
+ // Freshness line in the command bar: when the board last scanned, and warning words when the last refresh failed.
+ function fresh() {
+ const at = Date.parse(data?.generatedAt), ago = Number.isFinite(at) ? age(Math.max(0, Math.round((Date.now() - at) / 1000))) : null;
+- if (!data) { $('fresh-board').innerHTML = failed === 'refused' ? 'Board not read: refused' : failed ? 'Board not read: the read failed' : 'Board not read yet'; return; }
++ if (!data) { $('fresh-board').innerHTML = failed ? 'Board not read: the read failed' : 'Board not read yet'; return; }
+ const scan = `Board scanned ${esc(Number.isFinite(at) ? `${new Date(at).toISOString().slice(11, 19)} UTC` : 'unknown')}${ago ? ` (${ago} ago)` : ''}`;
+ $('fresh-board').innerHTML = failed ? `${scan} · stale: the last refresh failed` : scan;
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M26.txt b/agents/darkwing/work/queue-53-review/r2/mut/M26.txt
new file mode 100644
index 00000000..d63603fc
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M26.txt
@@ -0,0 +1,59 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (2968.889817ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3226.573849ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5700.168779ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (266.368346ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (289.193528ms)
+✔ bus refusals map to statuses and never carry a path or a stack (576.468911ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2511.116714ms)
+✔ busReader takes --business, else the live bus host, else refuses (430.389135ms)
+✔ humanCall kills a transport that runs past its timeout (528.253433ms)
+✔ serve refuses a --business value that is not a business id (190.157217ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (2961.036578ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2837.798308ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1272.634327ms)
+✔ conversation view: seats without history say so and offer no reply (831.966075ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2864.021743ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53178.274663ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (2862.922541ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22346.280842ms)
+✔ loopback host and board origin fail closed (7.233985ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (103.43982ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (83.580754ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1875.027395ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.192019ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.359592ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.448547ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2864.793151ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3930.695527ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 53561.128538
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2864.793151ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ + actual - expected
+
+ + 'Board not read: the read failed'
+ - 'Board not read: refused'
+ ^
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:156:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'Board not read: the read failed',
+ expected: 'Board not read: refused',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M27.diff b/agents/darkwing/work/queue-53-review/r2/mut/M27.diff
new file mode 100644
index 00000000..7244863d
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M27.diff
@@ -0,0 +1,12 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..e34ee5fd 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -310,7 +310,6 @@
+ data = null; selected = null; project = null;
+ $('projects').innerHTML = '
Not read: the board refused the read.
';
+ for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';
+- $('footer').textContent = 'Board not read: refused';
+ $('status').textContent = 'Not read: the board refused the read';
+ inspect(); convForm();
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M27.txt b/agents/darkwing/work/queue-53-review/r2/mut/M27.txt
new file mode 100644
index 00000000..79f9fbc0
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M27.txt
@@ -0,0 +1,58 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3246.245856ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3674.93145ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5179.540346ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (239.681337ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (196.812069ms)
+✔ bus refusals map to statuses and never carry a path or a stack (44.758167ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2933.216401ms)
+✔ busReader takes --business, else the live bus host, else refuses (107.108112ms)
+✔ humanCall kills a transport that runs past its timeout (529.400306ms)
+✔ serve refuses a --business value that is not a business id (161.249002ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3218.875059ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2575.330787ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1147.311364ms)
+✔ conversation view: seats without history say so and offer no reply (804.925523ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2689.75633ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53854.571559ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (2860.421809ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22255.535822ms)
+✔ loopback host and board origin fail closed (8.336514ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (118.861441ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (95.830197ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1834.666373ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.986879ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.98463ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.208649ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2883.477769ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (2756.953859ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54274.036903
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2883.477769ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ + actual - expected
+
+ + 'waiting 1 · working 1'
+ - 'Board not read: refused'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:155:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'waiting 1 · working 1',
+ expected: 'Board not read: refused',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M28.diff b/agents/darkwing/work/queue-53-review/r2/mut/M28.diff
new file mode 100644
index 00000000..35ab963c
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M28.diff
@@ -0,0 +1,12 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..169e8e0c 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -311,7 +311,6 @@
+ $('projects').innerHTML = '
Not read: the board refused the read.
';
+ for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';
+ $('footer').textContent = 'Board not read: refused';
+- $('status').textContent = 'Not read: the board refused the read';
+ inspect(); convForm();
+ }
+ $('error').className = refused ? 'banner ref' : 'banner err';
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M28.txt b/agents/darkwing/work/queue-53-review/r2/mut/M28.txt
new file mode 100644
index 00000000..4a4bd93b
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M28.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3550.51874ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5312.307526ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5616.759717ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (260.854664ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (91.58931ms)
+✔ bus refusals map to statuses and never carry a path or a stack (159.936555ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2972.254326ms)
+✔ busReader takes --business, else the live bus host, else refuses (165.485236ms)
+✔ humanCall kills a transport that runs past its timeout (547.85034ms)
+✔ serve refuses a --business value that is not a business id (162.092336ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3539.736538ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3160.834001ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1301.74645ms)
+✔ conversation view: seats without history say so and offer no reply (826.83122ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2888.780959ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54197.380733ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3020.912636ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22115.319317ms)
+✔ loopback host and board origin fail closed (9.401662ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (119.854295ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (321.466276ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1709.391542ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.258316ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.899559ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.650272ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2910.736129ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (4240.183759ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54846.778865
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2910.736129ms)
+ AssertionError [ERR_ASSERTION]: The input was expected to not match the regular expression /Scanned/. Input:
+
+ 'Scanned 2026-10-10T18:51:40.678Z · refresh every 10s'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:157:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'Scanned 2026-10-10T18:51:40.678Z · refresh every 10s',
+ expected: /Scanned/,
+ operator: 'doesNotMatch',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M29.diff b/agents/darkwing/work/queue-53-review/r2/mut/M29.diff
new file mode 100644
index 00000000..0b73bd01
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M29.diff
@@ -0,0 +1,12 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..9a94ec51 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -308,7 +308,6 @@
+ failed = refused ? 'refused' : true; $('error').hidden = false;
+ if (refused) {
+ data = null; selected = null; project = null;
+- $('projects').innerHTML = '
Not read: the board refused the read.
';
+ for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';
+ $('footer').textContent = 'Board not read: refused';
+ $('status').textContent = 'Not read: the board refused the read';
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M29.txt b/agents/darkwing/work/queue-53-review/r2/mut/M29.txt
new file mode 100644
index 00000000..52f34252
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M29.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3943.764665ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4161.06461ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5544.885357ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (621.447301ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (179.59438ms)
+✔ bus refusals map to statuses and never carry a path or a stack (130.608711ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2724.299629ms)
+✔ busReader takes --business, else the live bus host, else refuses (110.308126ms)
+✔ humanCall kills a transport that runs past its timeout (528.747596ms)
+✔ serve refuses a --business value that is not a business id (188.683838ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3892.153976ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2405.469187ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1162.017836ms)
+✔ conversation view: seats without history say so and offer no reply (811.669296ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2843.374378ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54334.298298ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (2861.443553ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22345.735665ms)
+✔ loopback host and board origin fail closed (6.544532ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (105.279642ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (306.595913ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1904.82471ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.160351ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.292111ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.341858ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2793.054072ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3257.19315ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54777.426057
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (2793.054072ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+
+ 4 !== 0
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:154:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 4,
+ expected: 0,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M30.diff b/agents/darkwing/work/queue-53-review/r2/mut/M30.diff
new file mode 100644
index 00000000..e77b2706
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M30.diff
@@ -0,0 +1,12 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..33702149 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -309,7 +309,6 @@
+ if (refused) {
+ data = null; selected = null; project = null;
+ $('projects').innerHTML = '
Not read: the board refused the read.
';
+- for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';
+ $('footer').textContent = 'Board not read: refused';
+ $('status').textContent = 'Not read: the board refused the read';
+ inspect(); convForm();
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M30.txt b/agents/darkwing/work/queue-53-review/r2/mut/M30.txt
new file mode 100644
index 00000000..056b0667
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M30.txt
@@ -0,0 +1,36 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4287.251342ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4257.078572ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (4787.813726ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (248.673864ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (108.850367ms)
+✔ bus refusals map to statuses and never carry a path or a stack (57.034728ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2123.171508ms)
+✔ busReader takes --business, else the live bus host, else refuses (181.909869ms)
+✔ humanCall kills a transport that runs past its timeout (528.763166ms)
+✔ serve refuses a --business value that is not a business id (158.778448ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4196.796291ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (1947.944484ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1219.575356ms)
+✔ conversation view: seats without history say so and offer no reply (966.856189ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4154.261341ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53503.07169ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3990.479246ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22660.736326ms)
+✔ loopback host and board origin fail closed (8.965093ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (126.518024ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (104.109094ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1039.219515ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.241848ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.50003ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.17149ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6799.567456ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (2563.79395ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 27
+ℹ fail 0
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 53936.307319
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M31.diff b/agents/darkwing/work/queue-53-review/r2/mut/M31.diff
new file mode 100644
index 00000000..4ea44ad5
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M31.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..bfe9075b 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -376,7 +376,7 @@
+ // Freshness line in the command bar for bus pages.
+ const stamp = iso => { const t = Date.parse(iso); return Number.isFinite(t) ? `${new Date(t).toISOString().slice(11, 19)} UTC` : 'unknown'; };
+ function freshBus(state) {
+- $('fresh-bus').innerHTML = state === 'refused' ? 'Bus not read: refused' : state === 'failed' ? 'Bus not read: the read failed'
++ $('fresh-bus').innerHTML = state === 'failed' ? 'Bus not read: the read failed'
+ : `Bus read ${esc(stamp(readAt))}${readAt ? ` (${esc(ago(readAt))})` : ''}${state === 'stale' ? ' · stale: the last read failed' : ''}`;
+ }
+
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M31.txt b/agents/darkwing/work/queue-53-review/r2/mut/M31.txt
new file mode 100644
index 00000000..bae57695
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M31.txt
@@ -0,0 +1,80 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4019.454985ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4218.465523ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5722.957436ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (288.58676ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (146.939199ms)
+✔ bus refusals map to statuses and never carry a path or a stack (263.376856ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2922.82782ms)
+✔ busReader takes --business, else the live bus host, else refuses (244.943803ms)
+✔ humanCall kills a transport that runs past its timeout (530.490728ms)
+✔ serve refuses a --business value that is not a business id (308.685115ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4008.930441ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2357.061135ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1100.14734ms)
+✔ conversation view: seats without history say so and offer no reply (799.501081ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2671.451659ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53877.624865ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (2890.013136ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22280.584605ms)
+✔ loopback host and board origin fail closed (9.459608ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (150.74983ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (98.568173ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1760.354168ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.048301ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.876693ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.620976ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4024.870689ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (2076.962299ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 25
+ℹ fail 2
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54355.140712
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4024.870689ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ + actual - expected
+
+ + 'Bus read 18:54:25 UTC (0 s ago)'
+ - 'Bus not read: refused'
+ ^
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:234:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'Bus read 18:54:25 UTC (0 s ago)',
+ expected: 'Bus not read: refused',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (2076.962299ms)
+ AssertionError [ERR_ASSERTION]: #/inbox
+ + actual - expected
+
+ + 'Bus read 18:54:28 UTC (0 s ago)'
+ - 'Bus not read: refused'
+ ^
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:382:16)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 'Bus read 18:54:28 UTC (0 s ago)',
+ expected: 'Bus not read: refused',
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M32.diff b/agents/darkwing/work/queue-53-review/r2/mut/M32.diff
new file mode 100644
index 00000000..6884168b
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M32.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
+index ed6d2d96..14821b7b 100644
+--- a/packages/webui/src/public/shell.css
++++ b/packages/webui/src/public/shell.css
+@@ -103,7 +103,7 @@ body.on-bus #board-refused{display:none}
+ /* Toast: one line, polite, bottom centre. */
+ .toast{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);display:flex;align-items:center;gap:10px;background:var(--strong);color:var(--surface);padding:6px 8px 6px 14px;border-radius:var(--r);font-size:13px;z-index:60;max-width:calc(100% - 24px);box-shadow:var(--shadow)}
+ /* Off, the toast stays in the accessibility tree, empty and visually hidden, so the first copy is announced. */
+-.toast:not(.on){width:1px;height:1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;box-shadow:none}
++.toast:not(.on){display:none}
+ .toast span{min-width:0;overflow-wrap:anywhere}
+ .toast.err{background:var(--danger)}
+ .toast button{font:inherit;font-weight:600;border:1px solid currentColor;background:none;color:inherit;border-radius:4px;padding:1px 8px;cursor:pointer}
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M32.txt b/agents/darkwing/work/queue-53-review/r2/mut/M32.txt
new file mode 100644
index 00000000..6ad67b23
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M32.txt
@@ -0,0 +1,63 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3328.993527ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3531.78405ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5447.140363ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (269.185034ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (125.783547ms)
+✔ bus refusals map to statuses and never carry a path or a stack (145.763412ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2793.230461ms)
+✔ busReader takes --business, else the live bus host, else refuses (120.744303ms)
+✔ humanCall kills a transport that runs past its timeout (588.228776ms)
+✔ serve refuses a --business value that is not a business id (158.710131ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3282.87396ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2349.879429ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1255.661234ms)
+✔ conversation view: seats without history say so and offer no reply (834.227184ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2771.824123ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53870.749227ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3156.662852ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22133.981151ms)
+✔ loopback host and board origin fail closed (8.165648ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (133.174467ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (104.076118ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1812.887702ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.313076ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.501953ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.280554ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (3339.870267ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3129.879391ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54285.916301
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (3339.870267ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ + actual - expected
+
+ [
+ + false,
+ - true,
+ 'visible',
+ '',
+ true
+ ]
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:199:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: [ false, 'visible', '', true ],
+ expected: [ true, 'visible', '', true ],
+ operator: 'deepStrictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M33.diff b/agents/darkwing/work/queue-53-review/r2/mut/M33.diff
new file mode 100644
index 00000000..75d13d7f
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M33.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..4ceace5b 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -370,7 +370,7 @@
+ // A refusal fails closed: no kept data, the code in mono. Any other failure keeps the last read, labelled with its time.
+ const refusal = err => err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);
+ // After a refusal nothing read before is shown anywhere: not in a view, the palette or the Inbox count.
+- function forget() { last.clear(); inboxCount = null; }
++ function forget() { last.clear(); }
+ const failedView = err => `${head(failTitle(err))}
${refusal(err) ? `refused: ${txt(err.code)}. ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.
${retry}
${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
+ const staleBanner = err => `
The last read failed. ${why(err)} This is what was read before, ${when(readAt)}. Nothing was changed.
${retry}
`;
+ // Freshness line in the command bar for bus pages.
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M33.txt b/agents/darkwing/work/queue-53-review/r2/mut/M33.txt
new file mode 100644
index 00000000..6a5921a3
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M33.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3126.358489ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4118.593367ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5006.994875ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (293.322998ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (179.622323ms)
+✔ bus refusals map to statuses and never carry a path or a stack (244.651528ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2463.711647ms)
+✔ busReader takes --business, else the live bus host, else refuses (126.115149ms)
+✔ humanCall kills a transport that runs past its timeout (528.077583ms)
+✔ serve refuses a --business value that is not a business id (153.121325ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (2776.188695ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2558.872677ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1138.046042ms)
+✔ conversation view: seats without history say so and offer no reply (1204.449823ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2668.08359ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53852.495895ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (2670.260808ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22057.59907ms)
+✔ loopback host and board origin fail closed (8.782534ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (130.541717ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (140.203928ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1610.160969ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.884644ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.761476ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (1.839968ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6358.781073ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (1322.190764ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 54329.286857
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (1322.190764ms)
+ AssertionError [ERR_ASSERTION]: #/inbox drops the Inbox count on a human-required refusal
+
+ 2 !== 0
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:383:16)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 2,
+ expected: 0,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M34.diff b/agents/darkwing/work/queue-53-review/r2/mut/M34.diff
new file mode 100644
index 00000000..b7cff8e9
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M34.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
+index 93df4371..c2eacbe1 100644
+--- a/packages/webui/src/public/bus.js
++++ b/packages/webui/src/public/bus.js
+@@ -370,7 +370,7 @@
+ // A refusal fails closed: no kept data, the code in mono. Any other failure keeps the last read, labelled with its time.
+ const refusal = err => err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);
+ // After a refusal nothing read before is shown anywhere: not in a view, the palette or the Inbox count.
+- function forget() { last.clear(); inboxCount = null; }
++ function forget() { inboxCount = null; }
+ const failedView = err => `${head(failTitle(err))}
${refusal(err) ? `refused: ${txt(err.code)}. ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.
${retry}
${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
+ const staleBanner = err => `
The last read failed. ${why(err)} This is what was read before, ${when(readAt)}. Nothing was changed.
${retry}
`;
+ // Freshness line in the command bar for bus pages.
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M34.txt b/agents/darkwing/work/queue-53-review/r2/mut/M34.txt
new file mode 100644
index 00000000..e5dc99f7
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M34.txt
@@ -0,0 +1,65 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3007.173261ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3855.294086ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5615.842981ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (261.282923ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (93.524702ms)
+✔ bus refusals map to statuses and never carry a path or a stack (152.594397ms)
+✔ humanCall speaks the human transport protocol without blocking the server (3222.083926ms)
+✔ busReader takes --business, else the live bus host, else refuses (80.345244ms)
+✔ humanCall kills a transport that runs past its timeout (575.740134ms)
+✔ serve refuses a --business value that is not a business id (190.165655ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (2882.103601ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2486.2508ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1177.664134ms)
+✔ conversation view: seats without history say so and offer no reply (1284.697782ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (2706.579171ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53381.0835ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (2781.75392ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22306.183997ms)
+✔ loopback host and board origin fail closed (7.394334ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (107.914025ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (97.224984ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1885.353532ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.899596ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.989552ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (1.889945ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6673.23278ms)
+✖ five states on Board, Inbox, Tasks, Agents and Trail (2369.587424ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 53793.045051
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:316:1
+✖ five states on Board, Inbox, Tasks, Agents and Trail (2369.587424ms)
+ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
+ + actual - expected
+
+ [
+ '#/',
+ '#/inbox',
+ '#/tasks',
+ '#/agents',
+ + '#/inbox/dddddddddddddddddddddddddddddddd',
+ + '#/tasks/vikunja%3A32%2F7',
+ + '#/tasks/vikunja%3A32%2F8'
+ ]
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:397:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: [ '#/', '#/inbox', '#/tasks', '#/agents', '#/inbox/dddddddddddddddddddddddddddddddd', '#/tasks/vikunja%3A32%2F7', '#/tasks/vikunja%3A32%2F8' ],
+ expected: [ '#/', '#/inbox', '#/tasks', '#/agents' ],
+ operator: 'deepStrictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M35.diff b/agents/darkwing/work/queue-53-review/r2/mut/M35.diff
new file mode 100644
index 00000000..3576879d
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M35.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
+index 2084ff63..5ca3d420 100644
+--- a/packages/webui/src/public/app.js
++++ b/packages/webui/src/public/app.js
+@@ -283,7 +283,7 @@
+ function fresh() {
+ const at = Date.parse(data?.generatedAt), ago = Number.isFinite(at) ? age(Math.max(0, Math.round((Date.now() - at) / 1000))) : null;
+ if (!data) { $('fresh-board').innerHTML = failed === 'refused' ? 'Board not read: refused' : failed ? 'Board not read: the read failed' : 'Board not read yet'; return; }
+- const scan = `Board scanned ${esc(Number.isFinite(at) ? `${new Date(at).toISOString().slice(11, 19)} UTC` : 'unknown')}${ago ? ` (${ago} ago)` : ''}`;
++ const scan = `Board scanned ${esc(Number.isFinite(at) ? new Date(at).toLocaleTimeString([], { hour12: false }) : 'unknown')}${ago ? ` (${ago} ago)` : ''}`;
+ $('fresh-board').innerHTML = failed ? `${scan} · stale: the last refresh failed` : scan;
+ }
+ setInterval(() => { if (data) fresh(); }, 5000);
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M35.txt b/agents/darkwing/work/queue-53-review/r2/mut/M35.txt
new file mode 100644
index 00000000..d81e925d
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M35.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3672.88716ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (3626.292542ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6049.955031ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (298.139781ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (384.361372ms)
+✔ bus refusals map to statuses and never carry a path or a stack (95.057268ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2630.859361ms)
+✔ busReader takes --business, else the live bus host, else refuses (153.24859ms)
+✔ humanCall kills a transport that runs past its timeout (530.057319ms)
+✔ serve refuses a --business value that is not a business id (149.60264ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3646.12638ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2657.957896ms)
+✔ conversation view: a newer session with no readable history keeps the marker (1187.981349ms)
+✔ conversation view: seats without history say so and offer no reply (824.394033ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (3514.633496ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54861.537569ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3495.154258ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22156.108066ms)
+✔ loopback host and board origin fail closed (6.632866ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (109.752328ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (116.522219ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1874.392891ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (0.924477ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.681684ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.146795ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (3244.793375ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (3494.281686ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 55222.326952
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (3244.793375ms)
+ AssertionError [ERR_ASSERTION]: The input did not match the regular expression /^Board scanned \d\d:\d\d:\d\d UTC/. Input:
+
+ 'Board scanned 13:57:59 (2s ago)'
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:128:12)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: true,
+ code: 'ERR_ASSERTION',
+ actual: 'Board scanned 13:57:59 (2s ago)',
+ expected: /^Board scanned \d\d:\d\d:\d\d UTC/,
+ operator: 'match',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M36.diff b/agents/darkwing/work/queue-53-review/r2/mut/M36.diff
new file mode 100644
index 00000000..93520848
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M36.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
+index ed6d2d96..c3c3d718 100644
+--- a/packages/webui/src/public/shell.css
++++ b/packages/webui/src/public/shell.css
+@@ -166,7 +166,7 @@ body.on-bus #board-refused{display:none}
+ .cmd-right label{flex:1 1 0;min-width:0}
+ .cmd-right .btn{flex:none}
+ /* The section list is one strip that scrolls inside itself (IMPLEMENTING.md), so more sections never add rows. */
+- .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;flex-basis:100%;min-width:0;max-width:100%;gap:2px;padding-bottom:2px;scrollbar-width:thin}
++ .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:visible;flex-basis:100%;min-width:0;max-width:100%;gap:2px;padding-bottom:2px;scrollbar-width:thin}
+ .s1-sections>li{flex:none}
+ .s1-section{border-radius:var(--r);padding:5px 8px;white-space:nowrap;flex:none}
+ .inspector{inset:0;top:0;width:100%;z-index:40;box-shadow:none}
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M36.txt b/agents/darkwing/work/queue-53-review/r2/mut/M36.txt
new file mode 100644
index 00000000..85c9e3a8
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M36.txt
@@ -0,0 +1,53 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5211.322674ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5406.834792ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7967.747109ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (291.194633ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (167.355846ms)
+✔ bus refusals map to statuses and never carry a path or a stack (301.032325ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2370.843823ms)
+✔ busReader takes --business, else the live bus host, else refuses (511.36435ms)
+✔ humanCall kills a transport that runs past its timeout (528.862393ms)
+✔ serve refuses a --business value that is not a business id (163.431821ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5370.262527ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4365.992749ms)
+✔ conversation view: a newer session with no readable history keeps the marker (2791.289399ms)
+✔ conversation view: seats without history say so and offer no reply (1223.433429ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5354.865178ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56830.63505ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5434.62527ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22694.896098ms)
+✔ loopback host and board origin fail closed (9.937835ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (137.366904ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (141.117982ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1498.910339ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.431161ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.986511ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.729744ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5309.354326ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (6092.066387ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 57366.349902
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5309.354326ms)
+ AssertionError [ERR_ASSERTION]: strip scrolls at 360px
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:205:14)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 'visible',
+ expected: /^(auto|scroll)$/,
+ operator: 'match',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M37.diff b/agents/darkwing/work/queue-53-review/r2/mut/M37.diff
new file mode 100644
index 00000000..57fd4d52
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M37.diff
@@ -0,0 +1,13 @@
+diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
+index ed6d2d96..77fc8ff8 100644
+--- a/packages/webui/src/public/shell.css
++++ b/packages/webui/src/public/shell.css
+@@ -166,7 +166,7 @@ body.on-bus #board-refused{display:none}
+ .cmd-right label{flex:1 1 0;min-width:0}
+ .cmd-right .btn{flex:none}
+ /* The section list is one strip that scrolls inside itself (IMPLEMENTING.md), so more sections never add rows. */
+- .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;flex-basis:100%;min-width:0;max-width:100%;gap:2px;padding-bottom:2px;scrollbar-width:thin}
++ .s1-sections{display:flex;flex-wrap:wrap;overflow-x:auto;flex-basis:100%;min-width:0;max-width:100%;gap:2px;padding-bottom:2px;scrollbar-width:thin}
+ .s1-sections>li{flex:none}
+ .s1-section{border-radius:var(--r);padding:5px 8px;white-space:nowrap;flex:none}
+ .inspector{inset:0;top:0;width:100%;z-index:40;box-shadow:none}
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/M37.txt b/agents/darkwing/work/queue-53-review/r2/mut/M37.txt
new file mode 100644
index 00000000..47e08341
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/M37.txt
@@ -0,0 +1,56 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5754.769823ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5803.927596ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8809.823038ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (355.250288ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (113.044848ms)
+✔ bus refusals map to statuses and never carry a path or a stack (74.932958ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2169.690829ms)
+✔ busReader takes --business, else the live bus host, else refuses (700.614062ms)
+✔ humanCall kills a transport that runs past its timeout (529.626355ms)
+✔ serve refuses a --business value that is not a business id (157.707334ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5687.132751ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4440.235802ms)
+✔ conversation view: a newer session with no readable history keeps the marker (2682.046974ms)
+✔ conversation view: seats without history say so and offer no reply (2581.852312ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5716.272685ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (57961.778739ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5798.600313ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23168.713365ms)
+✔ loopback host and board origin fail closed (10.029846ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (119.87584ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (116.102285ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1062.369733ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.26065ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.576684ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.555527ms)
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5642.483696ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (5046.143675ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 26
+ℹ fail 1
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 58384.246613
+
+✖ failing tests:
+
+test at tests/shell.test.mjs:88:1
+✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5642.483696ms)
+ AssertionError [ERR_ASSERTION]: one row at 360px
+
+ 2 !== 1
+
+ at TestContext. (file:///home/jwoltje/darkwing-scratch/r53b/mutwt/packages/webui/tests/shell.test.mjs:204:14)
+ at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
+ at async Test.run (node:internal/test_runner/test:1409:7)
+ at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
+ generatedMessage: false,
+ code: 'ERR_ASSERTION',
+ actual: 2,
+ expected: 1,
+ operator: 'strictEqual',
+ diff: 'simple'
+ }
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/manifest-after.txt b/agents/darkwing/work/queue-53-review/r2/mut/manifest-after.txt
new file mode 100644
index 00000000..5f69a82a
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/manifest-after.txt
@@ -0,0 +1,16 @@
+packages/webui/README.md: OK
+packages/webui/src/public/app.js: OK
+packages/webui/src/public/assets/fonts/jetbrains-mono-400.woff2: OK
+packages/webui/src/public/assets/fonts/jetbrains-mono-500.woff2: OK
+packages/webui/src/public/assets/fonts/jetbrains-mono-700.woff2: OK
+packages/webui/src/public/assets/fonts/jetbrains-mono-OFL.txt: OK
+packages/webui/src/public/assets/fonts/jetbrains-mono-sources.txt: OK
+packages/webui/src/public/bus.js: OK
+packages/webui/src/public/icons.svg: OK
+packages/webui/src/public/index.html: OK
+packages/webui/src/public/shell.css: OK
+packages/webui/src/public/tokens.css: OK
+packages/webui/src/serve.mjs: OK
+packages/webui/tests/browser.mjs: OK
+packages/webui/tests/serve.test.mjs: OK
+packages/webui/tests/shell.test.mjs: OK
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/mutate.py b/agents/darkwing/work/queue-53-review/r2/mut/mutate.py
new file mode 100644
index 00000000..0a1506f1
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/mutate.py
@@ -0,0 +1,48 @@
+# mutate.py : apply one named mutant to the candidate (exact text, must match once). Run from the tree root.
+import sys
+B, A, C, S, H = "packages/webui/src/public/bus.js", "packages/webui/src/public/app.js", "packages/webui/src/public/shell.css", "packages/webui/src/serve.mjs", "packages/webui/src/public/index.html"
+M = {
+ "M01": [(B, "err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);", "err.status === 403;")],
+ "M02": [(A, "const refused = err.status === 403;", "const refused = false;")],
+ "M03": [(A, "document.body.classList.toggle('board-refused', refused);", "")],
+ "M04": [(B, "refused: ${txt(err.code)}. ", "refused: ${txt(err.code)}. ")],
+ "M05": [(B, "${state === 'stale' ? ' · stale: the last read failed' : ''}", "")],
+ "M06": [(A, "if (mode === 'system') delete document.documentElement.dataset.mode; else document.documentElement.dataset.mode = mode;", "document.documentElement.dataset.mode = mode;")],
+ "M07": [(B, "t.innerHTML = `${esc(text)}", "t.innerHTML = `${text}")],
+ "M08": [(B, "${txt(i.label)}", "${i.label}")],
+ "M09": [(C, ":focus-visible{outline:2px solid var(--focus);outline-offset:2px}", ":focus-visible{outline:2px solid var(--focus);outline-offset:0}")],
+ "M10": [(C, ":focus-visible{outline:2px solid var(--focus);outline-offset:2px}", ":focus-visible{outline:1px solid var(--focus);outline-offset:2px}")],
+ "M11": [(C, " .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;", " .s1-sections{display:flex;flex-wrap:wrap;overflow-x:visible;")],
+ "M21": [(B, "function forget() { last.clear(); inboxCount = null; }", "function forget() {}")],
+ "M22": [(B, "catch (err) { if (refusal(err)) { forget(); if (g === gen) sections(path); } }", "catch {}")],
+ "M23": [(B, " if (refusal(err)) forget();\n", "")],
+ "M24": [(B, "if (rs.some(r => r.status === 'rejected' && refusal(r.reason))) { forget(); sections(routeOf().split('?')[0]); }", "")],
+ "M25": [(A, "data = null; selected = null; project = null;", "data = null; project = null;")],
+ "M26": [(A, "failed === 'refused' ? 'Board not read: refused' : ", "")],
+ "M27": [(A, " $('footer').textContent = 'Board not read: refused';\n", "")],
+ "M28": [(A, " $('status').textContent = 'Not read: the board refused the read';\n", "")],
+ "M29": [(A, " $('projects').innerHTML = '
Not read: the board refused the read.
';\n", "")],
+ "M30": [(A, " for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';\n", "")],
+ "M31": [(B, "state === 'refused' ? 'Bus not read: refused' : ", "")],
+ "M32": [(C, ".toast:not(.on){width:1px;height:1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;box-shadow:none}", ".toast:not(.on){display:none}")],
+ "M33": [(B, "function forget() { last.clear(); inboxCount = null; }", "function forget() { last.clear(); }")],
+ "M34": [(B, "function forget() { last.clear(); inboxCount = null; }", "function forget() { inboxCount = null; }")],
+ "M35": [(A, "`${new Date(at).toISOString().slice(11, 19)} UTC`", "new Date(at).toLocaleTimeString([], { hour12: false })")],
+ "M36": [(C, " .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;", " .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:visible;")],
+ "M37": [(C, " .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;", " .s1-sections{display:flex;flex-wrap:wrap;overflow-x:auto;")],
+ "M12": [(B, "", "")],
+ "M13": [(A, " $('board-refused').hidden = true; document.body.classList.remove('board-refused');\n", "")],
+ "M14": [(B, "links[i + (e.key === 'ArrowDown' ? 1 : -1)]?.focus();", "links[i + (e.key === 'ArrowDown' ? -1 : 1)]?.focus();")],
+ "M15": [(S, "['/icons.svg', ['icons.svg', 'image/svg+xml']],", "['/icons.svg', ['icons.svg', 'text/plain']],")],
+ "M16": [(C, ".count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}", "")],
+ "M17": [(A, "try { localStorage.setItem('mosaic-console-appearance',", "try { localStorage.setItem('mosaic-console-look',")],
+ "M18": [(C, "body.board-refused #board-view{display:none}", "")],
+ "M19": [(B, "if (refusal(err)) throw err; html = await view(kept,", "html = await view(kept,")],
+ "M20": [(A, "$('error').className = refused ? 'banner ref' : 'banner err';", "$('error').className = 'banner err';")],
+}
+for f, old, new in M[sys.argv[1]]:
+ s = open(f).read()
+ n = s.count(old)
+ if n != 1: sys.exit(f"{sys.argv[1]}: {n} matches in {f}")
+ open(f, "w").write(s.replace(old, new))
+print(sys.argv[1], "applied")
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/run.sh b/agents/darkwing/work/queue-53-review/r2/mut/run.sh
new file mode 100755
index 00000000..017f041d
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/run.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Each mutant against the packages/webui suite in a candidate worktree, then restores from the index.
+export TMPDIR=~/darkwing-scratch/r53b/tmp
+S=~/darkwing-scratch/r53b; M=$S/mut; W=$S/mutwt
+: > $M/summary.txt
+echo "start $(date -u +%FT%TZ)" >> $M/summary.txt
+for v in $(python3 -c 'import re;print(" ".join(sorted(set(re.findall(r"\"(M\d\d)\"", open("'$M'/mutate.py").read())))))'); do
+ (cd $W && git checkout -q -- packages/webui && python3 $M/mutate.py $v > /dev/null && git diff > $M/$v.diff) || { echo "$v APPLY-FAILED" >> $M/summary.txt; continue; }
+ (cd $W/packages/webui && env -u NODE_TEST_CONTEXT node --test 'tests/*.test.mjs' > $M/$v.txt 2>&1); e=$?
+ r=killed; [ $e = 0 ] && r=SURVIVED
+ echo "$v $r exit=$e $(grep -E '^ℹ (pass|fail)' $M/$v.txt | tr '\n' ' ')" >> $M/summary.txt
+done
+(cd $W && git checkout -q -- packages/webui && sha256sum -c $S/pkt/candidate-manifest.sha256) > $M/manifest-after.txt 2>&1
+echo "end $(date -u +%FT%TZ)" >> $M/summary.txt
+echo DONE >> $M/summary.txt
diff --git a/agents/darkwing/work/queue-53-review/r2/mut/summary.txt b/agents/darkwing/work/queue-53-review/r2/mut/summary.txt
new file mode 100644
index 00000000..fd7a2db1
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/mut/summary.txt
@@ -0,0 +1,40 @@
+start 2026-10-10T18:25:08Z
+M01 killed exit=1 ℹ pass 26 ℹ fail 1
+M02 killed exit=1 ℹ pass 26 ℹ fail 1
+M03 killed exit=1 ℹ pass 26 ℹ fail 1
+M04 killed exit=1 ℹ pass 26 ℹ fail 1
+M05 killed exit=1 ℹ pass 24 ℹ fail 3
+M06 killed exit=1 ℹ pass 26 ℹ fail 1
+M07 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
+M08 killed exit=1 ℹ pass 26 ℹ fail 1
+M09 killed exit=1 ℹ pass 26 ℹ fail 1
+M10 killed exit=1 ℹ pass 26 ℹ fail 1
+M11 killed exit=1 ℹ pass 26 ℹ fail 1
+M12 killed exit=1 ℹ pass 26 ℹ fail 1
+M13 killed exit=1 ℹ pass 26 ℹ fail 1
+M14 killed exit=1 ℹ pass 26 ℹ fail 1
+M15 killed exit=1 ℹ pass 26 ℹ fail 1
+M16 killed exit=1 ℹ pass 26 ℹ fail 1
+M17 killed exit=1 ℹ pass 26 ℹ fail 1
+M18 killed exit=1 ℹ pass 26 ℹ fail 1
+M19 killed exit=1 ℹ pass 25 ℹ fail 2
+M20 killed exit=1 ℹ pass 26 ℹ fail 1
+M21 killed exit=1 ℹ pass 26 ℹ fail 1
+M22 killed exit=1 ℹ pass 26 ℹ fail 1
+M23 killed exit=1 ℹ pass 26 ℹ fail 1
+M24 killed exit=1 ℹ pass 26 ℹ fail 1
+M25 killed exit=1 ℹ pass 26 ℹ fail 1
+M26 killed exit=1 ℹ pass 26 ℹ fail 1
+M27 killed exit=1 ℹ pass 26 ℹ fail 1
+M28 killed exit=1 ℹ pass 26 ℹ fail 1
+M29 killed exit=1 ℹ pass 26 ℹ fail 1
+M30 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
+M31 killed exit=1 ℹ pass 25 ℹ fail 2
+M32 killed exit=1 ℹ pass 26 ℹ fail 1
+M33 killed exit=1 ℹ pass 26 ℹ fail 1
+M34 killed exit=1 ℹ pass 26 ℹ fail 1
+M35 killed exit=1 ℹ pass 26 ℹ fail 1
+M36 killed exit=1 ℹ pass 26 ℹ fail 1
+M37 killed exit=1 ℹ pass 26 ℹ fail 1
+end 2026-10-10T19:00:50Z
+DONE
diff --git a/agents/darkwing/work/queue-53-review/r2/out/build-tokens.txt b/agents/darkwing/work/queue-53-review/r2/out/build-tokens.txt
new file mode 100644
index 00000000..20cb200f
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/out/build-tokens.txt
@@ -0,0 +1 @@
+tokens.css is current
diff --git a/agents/darkwing/work/queue-53-review/r2/out/node-webui.txt b/agents/darkwing/work/queue-53-review/r2/out/node-webui.txt
new file mode 100644
index 00000000..80b7ed23
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/out/node-webui.txt
@@ -0,0 +1,36 @@
+✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5523.436991ms)
+Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
+✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (8766.561351ms)
+✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8827.954235ms)
+✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (277.316884ms)
+✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (201.217171ms)
+✔ bus refusals map to statuses and never carry a path or a stack (73.461855ms)
+✔ humanCall speaks the human transport protocol without blocking the server (2813.609766ms)
+✔ busReader takes --business, else the live bus host, else refuses (175.887468ms)
+✔ humanCall kills a transport that runs past its timeout (529.046089ms)
+✔ serve refuses a --business value that is not a business id (197.251891ms)
+✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (6431.465011ms)
+✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3853.631876ms)
+✔ conversation view: a newer session with no readable history keeps the marker (3922.98223ms)
+✔ conversation view: seats without history say so and offer no reply (3482.629009ms)
+✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5496.850194ms)
+✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (58053.664671ms)
+✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5499.821805ms)
+✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (25062.757457ms)
+✔ loopback host and board origin fail closed (9.306713ms)
+✔ real board fixture passes through WebUI; assets and isolated seen/reply work (134.500699ms)
+✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (127.67224ms)
+✔ unreachable board reports URL; CLI rejects unsupported options (1474.550223ms)
+✔ tokens.css and icons.svg are byte copies of docs/design (1.345771ms)
+✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.627495ms)
+✔ shipped strings are unchanged, and the web keeps its write boundary (2.591051ms)
+✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8724.52559ms)
+✔ five states on Board, Inbox, Tasks, Agents and Trail (7349.679734ms)
+ℹ tests 27
+ℹ suites 0
+ℹ pass 27
+ℹ fail 0
+ℹ cancelled 0
+ℹ skipped 0
+ℹ todo 0
+ℹ duration_ms 58535.525593
diff --git a/agents/darkwing/work/queue-53-review/r2/out/r1-to-r2.diff b/agents/darkwing/work/queue-53-review/r2/out/r1-to-r2.diff
new file mode 100644
index 00000000..fdb52aa3
--- /dev/null
+++ b/agents/darkwing/work/queue-53-review/r2/out/r1-to-r2.diff
@@ -0,0 +1,391 @@
+diff -ru /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/README.md packages/webui/README.md
+--- /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/README.md 2026-10-10 12:23:48.000000000 -0500
++++ packages/webui/README.md 2026-10-10 13:15:05.000000000 -0500
+@@ -91,7 +91,9 @@
+ open sections and the copy status survive a refresh.
+ - A failed read keeps the last good answer for that read and says it is old,
+ with the time it was read. A refusal (403, `not-configured` or `no-bus-host`)
+- never shows kept rows (row 53). A page never read, or refused, shows the failure instead,
++ never shows kept rows (row 53), and it drops every kept bus read: the Inbox
++ count and the palette's decisions and tasks go too, until a read succeeds.
++ A page never read, or refused, shows the failure instead,
+ titled "Bus refused the read" (403: the bus refused the Console's read, for
+ example `human-required` from a Console started inside an agent run), "No bus to read" (no system
+ config, or no bus host and no `--business`) or "The read failed".
+@@ -120,12 +122,16 @@
+ and tasks; arrows move, Enter opens, Esc closes and returns focus. Arrow
+ keys also move between task links in the bus tables.
+ - Copy reports in a toast. If the clipboard is unavailable, the toast stays
+- until dismissed and the command is selected for Ctrl+C.
+-- The command bar shows when the board was scanned and the bus read, and
+- says when the last attempt failed. A board refusal hides the board rather
+- than showing the last scan.
++ until dismissed and the command is selected for Ctrl+C. When no toast shows,
++ the toast is an empty live region, visually hidden but still in the
++ accessibility tree, so the first copy is announced.
++- The command bar shows, in UTC, when the board was scanned and the bus read,
++ and says when the last attempt failed. A board refusal drops the last scan
++ and everything drawn from it: the table, the inspector, the project tree,
++ the counts, the footer and the scan line all say the board was not read.
+ - From 760px the footer is a one-line status bar and the side column fits
+- between it and the command bar. Below 760px the section list wraps.
++ between it and the command bar. Below 760px the section list is one strip
++ that scrolls inside itself.
+
+ ## Data and boundaries
+
+@@ -204,11 +210,15 @@
+
+ Shell tests (`shell.test.mjs`) check the copies, the font hashes and the kept
+ strings, and in the browser at 400px: System mode under an emulated dark and
+-light OS, the empty, stale and refused states of the board and the bus views,
+-not found, the palette, the toast, keyboard and visible focus, no sideways
++light OS, the empty, stale and refused states of the board and the bus views
++(a board refusal with the inspector open), not found, the palette, the toast,
++keyboard and visible focus, the section strip at 360 and 400px, no sideways
+ scroll, no script error and no request other than GET. A second test walks
+ the Board, Inbox, Tasks, Agents and a decision trail through loading (a held
+-read), normal, a failed read over kept rows, and a refusal.
++read), normal, a failed read over kept rows, and a refusal by the bus
++(`human-required`) and for want of one (`no-bus-host`). It then checks that a
++refusal empties the palette and the Inbox count, from a view, from the
++palette's own reads and from the board page, and that palette labels are text.
+
+ No root CI workflow is configured for this package. These local tests are not a
+ claim of CI, deployment, live-seat delivery or user acceptance.
+diff -ru /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/src/public/app.js packages/webui/src/public/app.js
+--- /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/src/public/app.js 2026-10-10 12:03:18.000000000 -0500
++++ packages/webui/src/public/app.js 2026-10-10 13:15:05.000000000 -0500
+@@ -282,8 +282,8 @@
+ // Freshness line in the command bar: when the board last scanned, and warning words when the last refresh failed.
+ function fresh() {
+ const at = Date.parse(data?.generatedAt), ago = Number.isFinite(at) ? age(Math.max(0, Math.round((Date.now() - at) / 1000))) : null;
+- if (!data) { $('fresh-board').innerHTML = failed ? 'Board not read: the read failed' : 'Board not read yet'; return; }
+- const scan = `Board scanned ${esc(Number.isFinite(at) ? new Date(at).toLocaleTimeString([], { hour12: false }) : 'unknown')}${ago ? ` (${ago} ago)` : ''}`;
++ if (!data) { $('fresh-board').innerHTML = failed === 'refused' ? 'Board not read: refused' : failed ? 'Board not read: the read failed' : 'Board not read yet'; return; }
++ const scan = `Board scanned ${esc(Number.isFinite(at) ? `${new Date(at).toISOString().slice(11, 19)} UTC` : 'unknown')}${ago ? ` (${ago} ago)` : ''}`;
+ $('fresh-board').innerHTML = failed ? `${scan} · stale: the last refresh failed` : scan;
+ }
+ setInterval(() => { if (data) fresh(); }, 5000);
+@@ -300,10 +300,20 @@
+ for (const id of awaiting.keys()) { const r = row(id); if (r && !pending(r)) awaiting.delete(id); }
+ render();
+ }
+- // A refusal (403) fails closed: the last data is hidden, not shown as current. Any other failure keeps the last data with its scan time.
++ // A refusal (403) fails closed: the last data is dropped, not kept or shown as current, and so is
++ // everything drawn from it: the inspector, the project tree, the counts and the footer. Any other
++ // failure keeps the last data with its scan time.
+ function error(err) {
+- failed = true; $('error').hidden = false;
+ const refused = err.status === 403;
++ failed = refused ? 'refused' : true; $('error').hidden = false;
++ if (refused) {
++ data = null; selected = null; project = null;
++ $('projects').innerHTML = '
Not read: the board refused the read.
';
++ for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';
++ $('footer').textContent = 'Board not read: refused';
++ $('status').textContent = 'Not read: the board refused the read';
++ inspect(); convForm();
++ }
+ $('error').className = refused ? 'banner ref' : 'banner err';
+ $('board-refused').hidden = !refused; document.body.classList.toggle('board-refused', refused);
+ $('error').innerHTML = refused
+diff -ru /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/src/public/bus.js packages/webui/src/public/bus.js
+--- /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/src/public/bus.js 2026-10-10 11:58:46.000000000 -0500
++++ packages/webui/src/public/bus.js 2026-10-10 13:15:05.000000000 -0500
+@@ -369,12 +369,14 @@
+ const failTitle = err => err.status === 403 ? 'Bus refused the read' : ['not-configured', 'no-bus-host'].includes(err.code) ? 'No bus to read' : 'The read failed';
+ // A refusal fails closed: no kept data, the code in mono. Any other failure keeps the last read, labelled with its time.
+ const refusal = err => err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);
++ // After a refusal nothing read before is shown anywhere: not in a view, the palette or the Inbox count.
++ function forget() { last.clear(); inboxCount = null; }
+ const failedView = err => `${head(failTitle(err))}
${refusal(err) ? `refused: ${txt(err.code)}. ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.
${retry}
${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
+ const staleBanner = err => `
The last read failed. ${why(err)} This is what was read before, ${when(readAt)}. Nothing was changed.
${retry}
`;
+ // Freshness line in the command bar for bus pages.
+ const stamp = iso => { const t = Date.parse(iso); return Number.isFinite(t) ? `${new Date(t).toISOString().slice(11, 19)} UTC` : 'unknown'; };
+ function freshBus(state) {
+- $('fresh-bus').innerHTML = state === 'failed' ? 'Bus not read: the read failed'
++ $('fresh-bus').innerHTML = state === 'refused' ? 'Bus not read: refused' : state === 'failed' ? 'Bus not read: the read failed'
+ : `Bus read ${esc(stamp(readAt))}${readAt ? ` (${esc(ago(readAt))})` : ''}${state === 'stale' ? ' · stale: the last read failed' : ''}`;
+ }
+
+@@ -420,7 +422,8 @@
+ if (board) {
+ // The board page keeps its own title; the Inbox count still follows the bus.
+ if (shown !== null) { shown = null; $('bus-view').innerHTML = ''; document.title = 'Mosaic Console'; if (navigated) $('main').focus(); }
+- try { const r = await fetchRead('inbox'); last.set('inbox', r); if (g === gen) { countInbox(r.rows); sections(path); } } catch {}
++ try { const r = await fetchRead('inbox'); last.set('inbox', r); if (g === gen) { countInbox(r.rows); sections(path); } }
++ catch (err) { if (refusal(err)) { forget(); if (g === gen) sections(path); } }
+ if (g === gen) schedule();
+ return;
+ }
+@@ -431,7 +434,8 @@
+ catch (err) {
+ const kept = reader(false);
+ try { if (refusal(err)) throw err; html = await view(kept, path, new URLSearchParams(query)); readAt = kept.oldest(); html = staleBanner(err) + html; state = 'stale'; }
+- catch { html = failedView(err); state = 'failed'; }
++ catch { html = failedView(err); state = refusal(err) ? 'refused' : 'failed'; }
++ if (refusal(err)) forget();
+ }
+ if (g !== gen) return;
+ freshBus(state);
+@@ -506,7 +510,10 @@
+ if (d.open) return;
+ pkBack = document.activeElement; pkAt = 0; $('cmdk-input').value = '';
+ pkItems(); pkFill(); d.showModal(); $('cmdk-input').focus();
+- Promise.allSettled(['inbox', 'tasks'].map(async v => last.set(v, await fetchRead(v)))).then(() => { if (d.open) { pkItems(); pkFill(); } });
++ Promise.allSettled(['inbox', 'tasks'].map(async v => last.set(v, await fetchRead(v)))).then(rs => {
++ if (rs.some(r => r.status === 'rejected' && refusal(r.reason))) { forget(); sections(routeOf().split('?')[0]); }
++ if (d.open) { pkItems(); pkFill(); }
++ });
+ }
+ function pkGo(href) {
+ pkBack = null; $('cmdk-dialog').close();
+diff -ru /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/src/public/shell.css packages/webui/src/public/shell.css
+--- /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/src/public/shell.css 2026-10-10 12:14:49.000000000 -0500
++++ packages/webui/src/public/shell.css 2026-10-10 13:15:05.000000000 -0500
+@@ -101,8 +101,9 @@
+ body.on-bus #board-refused{display:none}
+
+ /* Toast: one line, polite, bottom centre. */
+-.toast{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);display:none;align-items:center;gap:10px;background:var(--strong);color:var(--surface);padding:6px 8px 6px 14px;border-radius:var(--r);font-size:13px;z-index:60;max-width:calc(100% - 24px);box-shadow:var(--shadow)}
+-.toast.on{display:flex}
++.toast{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);display:flex;align-items:center;gap:10px;background:var(--strong);color:var(--surface);padding:6px 8px 6px 14px;border-radius:var(--r);font-size:13px;z-index:60;max-width:calc(100% - 24px);box-shadow:var(--shadow)}
++/* Off, the toast stays in the accessibility tree, empty and visually hidden, so the first copy is announced. */
++.toast:not(.on){width:1px;height:1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;box-shadow:none}
+ .toast span{min-width:0;overflow-wrap:anywhere}
+ .toast.err{background:var(--danger)}
+ .toast button{font:inherit;font-weight:600;border:1px solid currentColor;background:none;color:inherit;border-radius:4px;padding:1px 8px;cursor:pointer}
+@@ -164,8 +165,9 @@
+ .cmd-right{margin-left:0;flex:1 1 100%;flex-wrap:nowrap;min-width:0}
+ .cmd-right label{flex:1 1 0;min-width:0}
+ .cmd-right .btn{flex:none}
+- /* The section list wraps rather than scrolling, so a blocking count never hides a section. */
+- .s1-sections{display:flex;flex-wrap:wrap;overflow-x:visible;flex-basis:100%;gap:2px;padding-bottom:2px}
++ /* The section list is one strip that scrolls inside itself (IMPLEMENTING.md), so more sections never add rows. */
++ .s1-sections{display:flex;flex-wrap:nowrap;overflow-x:auto;flex-basis:100%;min-width:0;max-width:100%;gap:2px;padding-bottom:2px;scrollbar-width:thin}
++ .s1-sections>li{flex:none}
+ .s1-section{border-radius:var(--r);padding:5px 8px;white-space:nowrap;flex:none}
+ .inspector{inset:0;top:0;width:100%;z-index:40;box-shadow:none}
+ }
+diff -ru /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/tests/shell.test.mjs packages/webui/tests/shell.test.mjs
+--- /home/jwoltje/darkwing-scratch/r53a/snap/packages/webui/tests/shell.test.mjs 2026-10-10 12:23:48.000000000 -0500
++++ packages/webui/tests/shell.test.mjs 2026-10-10 13:15:05.000000000 -0500
+@@ -35,17 +35,21 @@
+ });
+
+ test('shipped strings are unchanged, and the web keeps its write boundary', () => {
+- // Markup in the source (, ) is not part of the string.
++ // Markup in the source (, ) is not part of the string. Each string is counted in the
++ // file that ships it, so dropping one of two copies fails too.
+ const src = ['app.js', 'bus.js', 'index.html'].map(f => read(f).toString()).join('\n');
+- const plain = src.replace(/<\/?(code|b)>/g, '');
+- for (const s of [
+- 'Copied: ${text}',
+- 'The clipboard is unavailable. The command is selected; press Ctrl+C to copy it.',
+- 'Decisions are answered in a terminal with mosaic decide; Console only shows them.',
+- 'No task ${txt(ref)} in this business.', 'No decision with id ${txt(id)}.', '${txt(b)} is not a decision id.', '${txt(b)} is not a task reference.',
+- 'No page at this address.', 'Nothing is waiting on you.', 'No tasks in this business yet.', 'Tasks appear after the PM creates them or the poller reads them from Vikunja.',
+- 'No open tasks.', 'No role is held right now.', 'Nothing of this kind in the trail.', 'Console shows nothing rather than a guess. Nothing was written.',
+- ]) assert.ok(plain.includes(s), s);
++ const plain = Object.fromEntries(['app.js', 'bus.js'].map(f => [f, read(f).toString().replace(/<\/?(code|b)>/g, '')]));
++ for (const [file, s, n = 1] of [
++ ['bus.js', 'Copied: ${text}'],
++ ['bus.js', 'The clipboard is unavailable. The command is selected; press Ctrl+C to copy it.'],
++ ['bus.js', 'Decisions are answered in a terminal with mosaic decide; Console only shows them.'],
++ ['bus.js', 'No task ${txt(ref)} in this business.', 2], ['bus.js', 'No decision with id ${txt(id)}.'],
++ ['bus.js', '${txt(b)} is not a decision id.'], ['bus.js', '${txt(b)} is not a task reference.'],
++ ['bus.js', 'No page at this address.'], ['app.js', 'Nothing is waiting on you.'], ['bus.js', 'Nothing is waiting on you.'],
++ ['bus.js', 'No tasks in this business yet.'], ['bus.js', 'Tasks appear after the PM creates them or the poller reads them from Vikunja.'],
++ ['bus.js', 'No open tasks.'], ['bus.js', 'No role is held right now.'], ['bus.js', 'Nothing of this kind in the trail.'],
++ ['bus.js', 'Console shows nothing rather than a guess. Nothing was written.'],
++ ]) assert.equal(plain[file].split(s).length - 1, n, `${file}: ${s}`);
+ // No Resolve control and no bus write: the only POSTs are the board's Seen and reply.
+ assert.doesNotMatch(src, /