diff --git a/agents/darkwing/work/queue-53-review/r3/candidate-manifest.sha256 b/agents/darkwing/work/queue-53-review/r3/candidate-manifest.sha256 new file mode 100644 index 00000000..7910a15e --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/candidate-manifest.sha256 @@ -0,0 +1,16 @@ +eb355c2d22fbfcc14e973a1f793891b0caab04a50cf6fd83c64b9de73a84bfac packages/webui/README.md +6154b49628a613059bb35c26b577817e8ed5fd084c9dfb50aef11431578f14e7 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 +da37a24308e51875502b81a5694d4e9c69dae24d36ee272a0b99b1ace7c4d317 packages/webui/tests/shell.test.mjs diff --git a/agents/darkwing/work/queue-53-review/r3/gate.sh b/agents/darkwing/work/queue-53-review/r3/gate.sh new file mode 100755 index 00000000..8919ca59 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/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/r53c/tmp DOCKER_HOST=unix:///nonexistent.sock +cd ~/darkwing-scratch/r53c/cand +O=~/darkwing-scratch/r53c/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/r3/mut/R01.diff b/agents/darkwing/work/queue-53-review/r3/mut/R01.diff new file mode 100644 index 00000000..73913b78 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R01.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..112010bd 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -308,7 +308,7 @@ + function error(err) { + const refused = err.status === 403; + failed = refused ? 'refused' : true; $('error').hidden = false; +- if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } ++ if (refused) { data = null; selected = null; project = null; } + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R01.txt b/agents/darkwing/work/queue-53-review/r3/mut/R01.txt new file mode 100644 index 00000000..9caebc3e --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R01.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4357.364683ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5606.369695ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7280.218799ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (285.542274ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (157.338486ms) +✔ bus refusals map to statuses and never carry a path or a stack (316.904847ms) +✔ humanCall speaks the human transport protocol without blocking the server (2487.061551ms) +✔ busReader takes --business, else the live bus host, else refuses (336.421998ms) +✔ humanCall kills a transport that runs past its timeout (528.263473ms) +✔ serve refuses a --business value that is not a business id (197.400597ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4373.974175ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3178.919122ms) +✔ conversation view: a newer session with no readable history keeps the marker (1638.653594ms) +✔ conversation view: seats without history say so and offer no reply (1022.655709ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5580.491856ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54785.556991ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5349.447192ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22901.932391ms) +✔ loopback host and board origin fail closed (10.225551ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (133.809594ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (90.434917ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1774.668623ms) +✔ tokens.css and icons.svg are byte copies of docs/design (5.724676ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (13.029263ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (3.292396ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4631.885541ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3637.934453ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 55170.160307 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4631.885541ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + false !== true + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:200: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/r3/mut/R02.diff b/agents/darkwing/work/queue-53-review/r3/mut/R02.diff new file mode 100644 index 00000000..14dda08f --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R02.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..8636ad73 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -308,7 +308,7 @@ + function error(err) { + const refused = err.status === 403; + failed = refused ? 'refused' : true; $('error').hidden = false; +- if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } ++ if (refused) { data = null; selected = null; project = null; if (conv) { closeConversation(); } } + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R02.txt b/agents/darkwing/work/queue-53-review/r3/mut/R02.txt new file mode 100644 index 00000000..add41726 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R02.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4855.702517ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6320.269832ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6730.573327ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (331.32457ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (146.624553ms) +✔ bus refusals map to statuses and never carry a path or a stack (76.885706ms) +✔ humanCall speaks the human transport protocol without blocking the server (2060.096289ms) +✔ busReader takes --business, else the live bus host, else refuses (189.158327ms) +✔ humanCall kills a transport that runs past its timeout (529.637878ms) +✔ serve refuses a --business value that is not a business id (247.237132ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5389.609333ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2501.421482ms) +✔ conversation view: a newer session with no readable history keeps the marker (1310.369236ms) +✔ conversation view: seats without history say so and offer no reply (878.453526ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5669.785351ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55399.462805ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5444.715817ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23838.29648ms) +✔ loopback host and board origin fail closed (9.455093ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (117.609002ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (90.209362ms) +✔ unreachable board reports URL; CLI rejects unsupported options (935.047647ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.365172ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.577104ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.750164ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5432.797602ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3531.698004ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 55797.162398 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5432.797602ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 1 !== 0 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:202: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: 1, + expected: 0, + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R03.diff b/agents/darkwing/work/queue-53-review/r3/mut/R03.diff new file mode 100644 index 00000000..71afc2f3 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R03.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..ecac6ea6 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -308,7 +308,7 @@ + function error(err) { + const refused = err.status === 403; + failed = refused ? 'refused' : true; $('error').hidden = false; +- if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } ++ if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); showConversation(false); } } + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R03.txt b/agents/darkwing/work/queue-53-review/r3/mut/R03.txt new file mode 100644 index 00000000..9e04a9c2 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R03.txt @@ -0,0 +1,47 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4894.224914ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4840.674479ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6613.741507ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (664.975397ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (425.806763ms) +✔ bus refusals map to statuses and never carry a path or a stack (67.063325ms) +✔ humanCall speaks the human transport protocol without blocking the server (2077.716621ms) +✔ busReader takes --business, else the live bus host, else refuses (531.836271ms) +✔ humanCall kills a transport that runs past its timeout (530.052372ms) +✔ serve refuses a --business value that is not a business id (171.001006ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4861.432832ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2733.981528ms) +✔ conversation view: a newer session with no readable history keeps the marker (1341.539484ms) +✔ conversation view: seats without history say so and offer no reply (863.397661ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4864.411016ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55457.728647ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4831.449262ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22275.110746ms) +✔ loopback host and board origin fail closed (7.438572ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (135.245611ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (174.946225ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1438.695438ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.00061ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.83711ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.045232ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7781.958592ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (2788.807591ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 56053.212777 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7781.958592ms) + Error: Uncaught (in promise) Error: Condition timed out: document.activeElement?.matches("[data-open]") && document.activeElement.textContent==="agent1": undefined + at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53c/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/r53c/mutwt/packages/webui/tests/shell.test.mjs:215:5) + 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/r3/mut/R04.diff b/agents/darkwing/work/queue-53-review/r3/mut/R04.diff new file mode 100644 index 00000000..866d5b66 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R04.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..ea420eb4 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -309,7 +309,7 @@ + const refused = err.status === 403; + failed = refused ? 'refused' : true; $('error').hidden = false; + if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } +- if (!data) { ++ if (refused) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; + for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R04.txt b/agents/darkwing/work/queue-53-review/r3/mut/R04.txt new file mode 100644 index 00000000..63636e85 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R04.txt @@ -0,0 +1,59 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4138.053527ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4310.599257ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5552.190765ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (273.704359ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (353.352341ms) +✔ bus refusals map to statuses and never carry a path or a stack (217.326745ms) +✔ humanCall speaks the human transport protocol without blocking the server (2545.275102ms) +✔ busReader takes --business, else the live bus host, else refuses (288.289302ms) +✔ humanCall kills a transport that runs past its timeout (529.2749ms) +✔ serve refuses a --business value that is not a business id (267.579967ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4310.725198ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2380.319162ms) +✔ conversation view: a newer session with no readable history keeps the marker (1108.514853ms) +✔ conversation view: seats without history say so and offer no reply (739.010404ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4211.527735ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53894.209091ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4017.881869ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22340.898892ms) +✔ loopback host and board origin fail closed (8.4696ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (113.976306ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (112.568935ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1664.496002ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.267374ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.514151ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.411806ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4017.126857ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3040.520103ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 54278.918401 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4017.126857ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + actual - expected + + + 'Board not read: refused' + - 'Board not read: the read failed' + ^ + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:180: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: refused', + expected: 'Board not read: the read failed', + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R05.diff b/agents/darkwing/work/queue-53-review/r3/mut/R05.diff new file mode 100644 index 00000000..b67580ce --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R05.diff @@ -0,0 +1,12 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..76b00755 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -312,7 +312,6 @@ + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; +- for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); + for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–'; + $('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`; + $('status').textContent = `Not read: ${why}`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R05.txt b/agents/darkwing/work/queue-53-review/r3/mut/R05.txt new file mode 100644 index 00000000..b29c9a24 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R05.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4803.099952ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4688.540875ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6571.898793ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (292.441148ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (190.781931ms) +✔ bus refusals map to statuses and never carry a path or a stack (62.185517ms) +✔ humanCall speaks the human transport protocol without blocking the server (2433.800874ms) +✔ busReader takes --business, else the live bus host, else refuses (223.279532ms) +✔ humanCall kills a transport that runs past its timeout (530.182798ms) +✔ serve refuses a --business value that is not a business id (147.728257ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4805.500178ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2376.564491ms) +✔ conversation view: a newer session with no readable history keeps the marker (1107.914187ms) +✔ conversation view: seats without history say so and offer no reply (726.437678ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4771.118004ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55737.030014ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4789.0592ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22243.778003ms) +✔ loopback host and board origin fail closed (9.600543ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (108.618347ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (102.037953ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1561.753343ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.371336ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.094789ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.364592ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4749.995989ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3130.895181ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 56141.922296 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4749.995989ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 11 !== 0 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:178: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: 11, + expected: 0, + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R06.diff b/agents/darkwing/work/queue-53-review/r3/mut/R06.diff new file mode 100644 index 00000000..0b7e3961 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R06.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..9238d4ad 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -312,7 +312,7 @@ + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; +- for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); ++ for (const id of ['waiting', 'sessions']) $(id).replaceChildren(); + for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–'; + $('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`; + $('status').textContent = `Not read: ${why}`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R06.txt b/agents/darkwing/work/queue-53-review/r3/mut/R06.txt new file mode 100644 index 00000000..1ffce76f --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R06.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4388.587757ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4415.26492ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6321.569047ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (320.319672ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (306.321478ms) +✔ bus refusals map to statuses and never carry a path or a stack (318.963185ms) +✔ humanCall speaks the human transport protocol without blocking the server (2194.687043ms) +✔ busReader takes --business, else the live bus host, else refuses (320.203199ms) +✔ humanCall kills a transport that runs past its timeout (554.353ms) +✔ serve refuses a --business value that is not a business id (167.646967ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4846.113484ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2027.977829ms) +✔ conversation view: a newer session with no readable history keeps the marker (1161.508504ms) +✔ conversation view: seats without history say so and offer no reply (760.511986ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4346.108258ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (45634.23458ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4849.4561ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22243.45107ms) +✔ loopback host and board origin fail closed (7.156936ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (111.873671ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (127.79059ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1492.129995ms) +✔ tokens.css and icons.svg are byte copies of docs/design (0.960519ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.943369ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (1.992483ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4352.755458ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (2978.13126ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 46089.278953 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4352.755458ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 2 !== 0 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:178: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/r3/mut/R07.diff b/agents/darkwing/work/queue-53-review/r3/mut/R07.diff new file mode 100644 index 00000000..47683b7d --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R07.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..d4e0dbfb 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -312,7 +312,7 @@ + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; +- for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); ++ for (const id of ['seen', 'sessions']) $(id).replaceChildren(); + for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–'; + $('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`; + $('status').textContent = `Not read: ${why}`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R07.txt b/agents/darkwing/work/queue-53-review/r3/mut/R07.txt new file mode 100644 index 00000000..69435919 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R07.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (6036.593035ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6100.894321ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8128.82253ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (286.736519ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (64.674194ms) +✔ bus refusals map to statuses and never carry a path or a stack (57.136766ms) +✔ humanCall speaks the human transport protocol without blocking the server (2193.388754ms) +✔ busReader takes --business, else the live bus host, else refuses (274.849013ms) +✔ humanCall kills a transport that runs past its timeout (529.49086ms) +✔ serve refuses a --business value that is not a business id (180.054135ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (6103.960998ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2681.456786ms) +✔ conversation view: a newer session with no readable history keeps the marker (1287.650059ms) +✔ conversation view: seats without history say so and offer no reply (793.309869ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6168.138254ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56488.219447ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6051.844481ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23107.35492ms) +✔ loopback host and board origin fail closed (9.209811ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (121.057055ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (140.860249ms) +✔ unreachable board reports URL; CLI rejects unsupported options (879.49217ms) +✔ tokens.css and icons.svg are byte copies of docs/design (0.924842ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.7955ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.254758ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6081.58039ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3787.790968ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 56843.035622 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6081.58039ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 2 !== 0 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:178: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/r3/mut/R08.diff b/agents/darkwing/work/queue-53-review/r3/mut/R08.diff new file mode 100644 index 00000000..21b5a652 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R08.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..9896d88d 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -312,7 +312,7 @@ + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; +- for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); ++ for (const id of ['waiting', 'seen']) $(id).replaceChildren(); + for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–'; + $('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`; + $('status').textContent = `Not read: ${why}`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R08.txt b/agents/darkwing/work/queue-53-review/r3/mut/R08.txt new file mode 100644 index 00000000..25710bbf --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R08.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4900.207456ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5083.939777ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6572.822309ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (321.20192ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (232.17288ms) +✔ bus refusals map to statuses and never carry a path or a stack (199.358364ms) +✔ humanCall speaks the human transport protocol without blocking the server (2259.246413ms) +✔ busReader takes --business, else the live bus host, else refuses (673.781883ms) +✔ humanCall kills a transport that runs past its timeout (533.333407ms) +✔ serve refuses a --business value that is not a business id (193.758775ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4558.232742ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2276.697584ms) +✔ conversation view: a newer session with no readable history keeps the marker (1102.029166ms) +✔ conversation view: seats without history say so and offer no reply (908.417782ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4904.720077ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (45186.714012ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4899.11086ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23184.867229ms) +✔ loopback host and board origin fail closed (7.160896ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (126.69408ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (118.514677ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1188.266786ms) +✔ tokens.css and icons.svg are byte copies of docs/design (0.921274ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.667648ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (1.967926ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4871.93075ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3432.477449ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 45655.547661 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4871.93075ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 7 !== 0 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:178: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: 7, + expected: 0, + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R09.diff b/agents/darkwing/work/queue-53-review/r3/mut/R09.diff new file mode 100644 index 00000000..6d6b619c --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R09.diff @@ -0,0 +1,12 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..cf6acd3a 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -313,7 +313,6 @@ + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; + for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); +- for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–'; + $('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`; + $('status').textContent = `Not read: ${why}`; + inspect(); diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R09.txt b/agents/darkwing/work/queue-53-review/r3/mut/R09.txt new file mode 100644 index 00000000..a9ac3418 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R09.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5042.417022ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6255.981482ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7622.154685ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (835.304749ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (208.683705ms) +✔ bus refusals map to statuses and never carry a path or a stack (198.695171ms) +✔ humanCall speaks the human transport protocol without blocking the server (2332.630157ms) +✔ busReader takes --business, else the live bus host, else refuses (392.502506ms) +✔ humanCall kills a transport that runs past its timeout (529.641646ms) +✔ serve refuses a --business value that is not a business id (189.184677ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5305.067115ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2727.339279ms) +✔ conversation view: a newer session with no readable history keeps the marker (1309.474994ms) +✔ conversation view: seats without history say so and offer no reply (795.825407ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5156.419695ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56394.343322ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5665.906343ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22515.741357ms) +✔ loopback host and board origin fail closed (9.890577ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (145.760824ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (98.004231ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1653.18752ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.355435ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.020533ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.776918ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5878.107856ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3293.499639ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 56836.962867 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5878.107856ms) + AssertionError [ERR_ASSERTION]: #waiting-count + + '1' !== '–' + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:170:82) + 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: '1', + expected: '–', + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R10.diff b/agents/darkwing/work/queue-53-review/r3/mut/R10.diff new file mode 100644 index 00000000..a363f71f --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R10.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..d3776a01 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -314,7 +314,7 @@ + $('projects').innerHTML = `

Not read: ${why}.

`; + for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); + for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–'; +- $('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`; ++ $('footer').textContent = 'Board not read: refused'; + $('status').textContent = `Not read: ${why}`; + inspect(); + } diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R10.txt b/agents/darkwing/work/queue-53-review/r3/mut/R10.txt new file mode 100644 index 00000000..7ec52655 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R10.txt @@ -0,0 +1,59 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5050.385435ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5043.562016ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6603.09917ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (474.208971ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (267.476295ms) +✔ bus refusals map to statuses and never carry a path or a stack (174.709188ms) +✔ humanCall speaks the human transport protocol without blocking the server (2272.778823ms) +✔ busReader takes --business, else the live bus host, else refuses (174.265748ms) +✔ humanCall kills a transport that runs past its timeout (528.397088ms) +✔ serve refuses a --business value that is not a business id (179.433644ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5250.655315ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2378.948314ms) +✔ conversation view: a newer session with no readable history keeps the marker (1190.032821ms) +✔ conversation view: seats without history say so and offer no reply (808.96696ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4978.669482ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54992.098098ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4913.440869ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23385.886205ms) +✔ loopback host and board origin fail closed (8.441654ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (125.381941ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (88.118654ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1520.733067ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.243298ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.589141ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.627381ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4768.175563ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3631.304572ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 55438.777304 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4768.175563ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + actual - expected + + + 'Board not read: refused' + - 'Board not read: the read failed' + ^ + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:180: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: refused', + expected: 'Board not read: the read failed', + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R11.diff b/agents/darkwing/work/queue-53-review/r3/mut/R11.diff new file mode 100644 index 00000000..853c3068 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R11.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..0dac0174 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -310,7 +310,7 @@ + failed = refused ? 'refused' : true; $('error').hidden = false; + if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } + if (!data) { +- const why = refused ? 'the board refused the read' : 'the read failed'; ++ const why = 'the board refused the read'; + $('projects').innerHTML = `

Not read: ${why}.

`; + for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); + for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–'; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R11.txt b/agents/darkwing/work/queue-53-review/r3/mut/R11.txt new file mode 100644 index 00000000..c4cce5f2 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R11.txt @@ -0,0 +1,59 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5650.912391ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6162.937461ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7308.837935ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (353.912872ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (146.299774ms) +✔ bus refusals map to statuses and never carry a path or a stack (100.39279ms) +✔ humanCall speaks the human transport protocol without blocking the server (2110.43097ms) +✔ busReader takes --business, else the live bus host, else refuses (256.398016ms) +✔ humanCall kills a transport that runs past its timeout (665.019901ms) +✔ serve refuses a --business value that is not a business id (160.743926ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5876.60575ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (1901.922149ms) +✔ conversation view: a newer session with no readable history keeps the marker (1374.173262ms) +✔ conversation view: seats without history say so and offer no reply (888.075297ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5878.334661ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55888.208065ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6156.340851ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22681.684546ms) +✔ loopback host and board origin fail closed (9.702895ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (122.969313ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (115.314798ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1242.745272ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.320161ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.215405ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.543711ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6262.777615ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3210.027001ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 56300.428205 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6262.777615ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + actual - expected + + + 'Not read: the board refused the read' + - 'Not read: the read failed' + ^ + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:182: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: 'Not read: the board refused the read', + expected: 'Not read: the read failed', + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R12.diff b/agents/darkwing/work/queue-53-review/r3/mut/R12.diff new file mode 100644 index 00000000..eb3741d4 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R12.diff @@ -0,0 +1,12 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..f08e1c6f 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -316,7 +316,6 @@ + for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–'; + $('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`; + $('status').textContent = `Not read: ${why}`; +- inspect(); + } + $('error').className = refused ? 'banner ref' : 'banner err'; + $('board-refused').hidden = !refused; document.body.classList.toggle('board-refused', refused); diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R12.txt b/agents/darkwing/work/queue-53-review/r3/mut/R12.txt new file mode 100644 index 00000000..ecca2824 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R12.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5556.899402ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6058.035533ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6942.067417ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (253.97288ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (83.219593ms) +✔ bus refusals map to statuses and never carry a path or a stack (103.494196ms) +✔ humanCall speaks the human transport protocol without blocking the server (2173.393637ms) +✔ busReader takes --business, else the live bus host, else refuses (173.699979ms) +✔ humanCall kills a transport that runs past its timeout (527.897056ms) +✔ serve refuses a --business value that is not a business id (158.452896ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4719.166139ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3027.465998ms) +✔ conversation view: a newer session with no readable history keeps the marker (1450.244115ms) +✔ conversation view: seats without history say so and offer no reply (806.679811ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4994.551896ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56326.781282ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4814.661956ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22241.515676ms) +✔ loopback host and board origin fail closed (6.963843ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (105.737467ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (99.870326ms) +✔ unreachable board reports URL; CLI rejects unsupported options (885.6488ms) +✔ tokens.css and icons.svg are byte copies of docs/design (0.953653ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.786699ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.145606ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4841.378827ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (4184.730508ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 56742.461593 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4841.378827ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + false !== true + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:164: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/r3/mut/R13.diff b/agents/darkwing/work/queue-53-review/r3/mut/R13.diff new file mode 100644 index 00000000..b655dfe2 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R13.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..a1df8aaf 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -308,7 +308,7 @@ + function error(err) { + const refused = err.status === 403; + failed = refused ? 'refused' : true; $('error').hidden = false; +- if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } ++ if (refused) { data = null; selected = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R13.txt b/agents/darkwing/work/queue-53-review/r3/mut/R13.txt new file mode 100644 index 00000000..d34e2d1e --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R13.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4958.436261ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5839.680736ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6752.747552ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (313.110002ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (209.181124ms) +✔ bus refusals map to statuses and never carry a path or a stack (132.196704ms) +✔ humanCall speaks the human transport protocol without blocking the server (2490.855076ms) +✔ busReader takes --business, else the live bus host, else refuses (914.332215ms) +✔ humanCall kills a transport that runs past its timeout (530.46568ms) +✔ serve refuses a --business value that is not a business id (165.845097ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5366.203786ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2292.540248ms) +✔ conversation view: a newer session with no readable history keeps the marker (1224.20263ms) +✔ conversation view: seats without history say so and offer no reply (920.065471ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5438.909685ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55064.68829ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5751.325816ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22542.858137ms) +✔ loopback host and board origin fail closed (8.112756ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (118.794689ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (98.229427ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1391.894302ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.045049ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.418334ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.203271ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5530.681465ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3243.523818ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 55485.89588 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5530.681465ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'false' !== 'true' + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:187: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/r3/mut/R14.diff b/agents/darkwing/work/queue-53-review/r3/mut/R14.diff new file mode 100644 index 00000000..9d1cb036 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R14.diff @@ -0,0 +1,13 @@ +diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js +index efe7ba9e..21c6f4ac 100644 +--- a/packages/webui/src/public/app.js ++++ b/packages/webui/src/public/app.js +@@ -308,7 +308,7 @@ + function error(err) { + const refused = err.status === 403; + failed = refused ? 'refused' : true; $('error').hidden = false; +- if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } ++ if (refused) { data = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } + if (!data) { + const why = refused ? 'the board refused the read' : 'the read failed'; + $('projects').innerHTML = `

Not read: ${why}.

`; diff --git a/agents/darkwing/work/queue-53-review/r3/mut/R14.txt b/agents/darkwing/work/queue-53-review/r3/mut/R14.txt new file mode 100644 index 00000000..84b30a3f --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/R14.txt @@ -0,0 +1,56 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4617.694886ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4583.641477ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6203.178815ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (425.84534ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (243.006036ms) +✔ bus refusals map to statuses and never carry a path or a stack (97.760263ms) +✔ humanCall speaks the human transport protocol without blocking the server (2112.252953ms) +✔ busReader takes --business, else the live bus host, else refuses (178.424797ms) +✔ humanCall kills a transport that runs past its timeout (528.349537ms) +✔ serve refuses a --business value that is not a business id (187.247791ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4591.731864ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (1895.812928ms) +✔ conversation view: a newer session with no readable history keeps the marker (1115.788704ms) +✔ conversation view: seats without history say so and offer no reply (767.542558ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4850.217739ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55022.437588ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4926.547646ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22233.744565ms) +✔ loopback host and board origin fail closed (9.651345ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (135.566789ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (110.732547ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1154.724864ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.451541ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.811802ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.799964ms) +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4922.844102ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (2893.4734ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 26 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 55550.563039 + +✖ failing tests: + +test at tests/shell.test.mjs:96:1 +✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4922.844102ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + false !== true + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r53c/mutwt/packages/webui/tests/shell.test.mjs:164: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/r3/mut/manifest-after.txt b/agents/darkwing/work/queue-53-review/r3/mut/manifest-after.txt new file mode 100644 index 00000000..5f69a82a --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/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/r3/mut/mutate.py b/agents/darkwing/work/queue-53-review/r3/mut/mutate.py new file mode 100644 index 00000000..04a9d8be --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/mutate.py @@ -0,0 +1,26 @@ +# Round 3 mutants: exact text, must match once. Run from the worktree root. +import sys +A = "packages/webui/src/public/app.js" +CLOSE = "if (conv) { $('conv-log').replaceChildren(); closeConversation(); }" +M = { + "R01": [(A, " " + CLOSE, "")], + "R02": [(A, CLOSE, "if (conv) { closeConversation(); }")], + "R03": [(A, CLOSE, "if (conv) { $('conv-log').replaceChildren(); showConversation(false); }")], + "R04": [(A, " if (!data) {\n const why", " if (refused) {\n const why")], + "R05": [(A, " for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren();\n", "")], + "R06": [(A, "for (const id of ['waiting', 'seen', 'sessions'])", "for (const id of ['waiting', 'sessions'])")], + "R07": [(A, "for (const id of ['waiting', 'seen', 'sessions'])", "for (const id of ['seen', 'sessions'])")], + "R08": [(A, "for (const id of ['waiting', 'seen', 'sessions'])", "for (const id of ['waiting', 'seen'])")], + "R09": [(A, " for (const id of ['waiting-count', 'seen-count', 'session-count']) $(id).textContent = '–';\n", "")], + "R10": [(A, "$('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`;", "$('footer').textContent = 'Board not read: refused';")], + "R11": [(A, "const why = refused ? 'the board refused the read' : 'the read failed';", "const why = 'the board refused the read';")], + "R12": [(A, " inspect();\n }\n $('error').className", " }\n $('error').className")], + "R13": [(A, "if (refused) { data = null; selected = null; project = null;", "if (refused) { data = null; selected = null;")], + "R14": [(A, "if (refused) { data = null; selected = null; project = null;", "if (refused) { data = null; project = null;")], +} +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/r3/mut/run.sh b/agents/darkwing/work/queue-53-review/r3/mut/run.sh new file mode 100755 index 00000000..0879125c --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/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/r53c/tmp +S=~/darkwing-scratch/r53c; 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"\"(R\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/r3/mut/summary.txt b/agents/darkwing/work/queue-53-review/r3/mut/summary.txt new file mode 100644 index 00000000..40c84128 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/mut/summary.txt @@ -0,0 +1,17 @@ +start 2026-10-10T19:26:06Z +R01 killed exit=1 ℹ pass 26 ℹ fail 1 +R02 killed exit=1 ℹ pass 26 ℹ fail 1 +R03 killed exit=1 ℹ pass 26 ℹ fail 1 +R04 killed exit=1 ℹ pass 26 ℹ fail 1 +R05 killed exit=1 ℹ pass 26 ℹ fail 1 +R06 killed exit=1 ℹ pass 26 ℹ fail 1 +R07 killed exit=1 ℹ pass 26 ℹ fail 1 +R08 killed exit=1 ℹ pass 26 ℹ fail 1 +R09 killed exit=1 ℹ pass 26 ℹ fail 1 +R10 killed exit=1 ℹ pass 26 ℹ fail 1 +R11 killed exit=1 ℹ pass 26 ℹ fail 1 +R12 killed exit=1 ℹ pass 26 ℹ fail 1 +R13 killed exit=1 ℹ pass 26 ℹ fail 1 +R14 killed exit=1 ℹ pass 26 ℹ fail 1 +end 2026-10-10T19:38:50Z +DONE diff --git a/agents/darkwing/work/queue-53-review/r3/out/build-tokens.txt b/agents/darkwing/work/queue-53-review/r3/out/build-tokens.txt new file mode 100644 index 00000000..20cb200f --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/build-tokens.txt @@ -0,0 +1 @@ +tokens.css is current diff --git a/agents/darkwing/work/queue-53-review/r3/out/node-webui.txt b/agents/darkwing/work/queue-53-review/r3/out/node-webui.txt new file mode 100644 index 00000000..cdbe3065 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/node-webui.txt @@ -0,0 +1,36 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (6060.523918ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6504.221202ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7770.043591ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (309.254238ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (148.596287ms) +✔ bus refusals map to statuses and never carry a path or a stack (196.362869ms) +✔ humanCall speaks the human transport protocol without blocking the server (2435.021376ms) +✔ busReader takes --business, else the live bus host, else refuses (349.294707ms) +✔ humanCall kills a transport that runs past its timeout (532.169891ms) +✔ serve refuses a --business value that is not a business id (261.462336ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5977.305191ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4319.030475ms) +✔ conversation view: a newer session with no readable history keeps the marker (1875.816756ms) +✔ conversation view: seats without history say so and offer no reply (1635.252753ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5813.776191ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56573.703754ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5744.431882ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22842.231747ms) +✔ loopback host and board origin fail closed (7.949761ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (145.46719ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (156.678394ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1280.951527ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.350765ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.436856ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.130262ms) +✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8204.713465ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (3668.031892ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 27 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 57021.687567 diff --git a/agents/darkwing/work/queue-53-review/r3/out/r2-to-r3.diff b/agents/darkwing/work/queue-53-review/r3/out/r2-to-r3.diff new file mode 100644 index 00000000..12fa7018 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/r2-to-r3.diff @@ -0,0 +1,163 @@ +diff -ru r53b/snap/packages/webui/README.md r53c/snap/packages/webui/README.md +--- r53b/snap/packages/webui/README.md 2026-10-10 13:15:05.000000000 -0500 ++++ r53c/snap/packages/webui/README.md 2026-10-10 14:18:51.000000000 -0500 +@@ -127,8 +127,12 @@ + 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. ++ and everything drawn from it: the cards, the table, the inspector, the ++ project filter and tree, the counts, the footer and the scan line all say ++ the board was not read. A failed read with no scan held, after a refusal or ++ before the first scan, shows the board empty and says the read failed; it ++ never brings back rows from a refused scan. A refusal also closes an open ++ conversation and clears its history. + - 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 is one strip + that scrolls inside itself. +@@ -211,7 +215,8 @@ + 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 +-(a board refusal with the inspector open), not found, the palette, the toast, ++(a board refusal with the inspector open and a project picked, then a failed ++read, and a refusal with a conversation 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 +diff -ru r53b/snap/packages/webui/src/public/app.js r53c/snap/packages/webui/src/public/app.js +--- r53b/snap/packages/webui/src/public/app.js 2026-10-10 13:15:05.000000000 -0500 ++++ r53c/snap/packages/webui/src/public/app.js 2026-10-10 14:18:51.000000000 -0500 +@@ -301,18 +301,22 @@ + render(); + } + // 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. ++ // everything drawn from it: the cards, the table, the inspector, an open conversation and its ++ // history, the project tree, the counts and the footer. Any other failure keeps the last data with ++ // its scan time. With no data, from a refusal or before the first scan, the board is drawn empty ++ // and says why, so a later failure never brings back old rows. + function error(err) { + 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.

'; ++ if (refused) { data = null; selected = null; project = null; if (conv) { $('conv-log').replaceChildren(); closeConversation(); } } ++ if (!data) { ++ const why = refused ? 'the board refused the read' : 'the read failed'; ++ $('projects').innerHTML = `

Not read: ${why}.

`; ++ for (const id of ['waiting', 'seen', 'sessions']) $(id).replaceChildren(); + 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(); ++ $('footer').textContent = `Board not read: ${refused ? 'refused' : 'the read failed'}`; ++ $('status').textContent = `Not read: ${why}`; ++ inspect(); + } + $('error').className = refused ? 'banner ref' : 'banner err'; + $('board-refused').hidden = !refused; document.body.classList.toggle('board-refused', refused); +diff -ru r53b/snap/packages/webui/tests/shell.test.mjs r53c/snap/packages/webui/tests/shell.test.mjs +--- r53b/snap/packages/webui/tests/shell.test.mjs 2026-10-10 13:15:05.000000000 -0500 ++++ r53c/snap/packages/webui/tests/shell.test.mjs 2026-10-10 14:18:51.000000000 -0500 +@@ -59,20 +59,28 @@ + function board() { + let reply = { status: 200, body: { sessions: [], counts: {}, generatedAt: new Date().toISOString() } }; + const one = { agent: 'agent1', project: 'proj', state: 'waiting', waitingOnYou: true, task: 'Fixture task', lastActivity: '2026-10-10T00:00:00Z', lastAssistantText: 'Input needed: fixture', registered: null }; ++ // While the board answers, agent1 has one conversation with one message. A failure or refusal answers every path. ++ const catalogue = { conversations: [{ project: 'proj', seat: 'agent1', conversation: 'c1', availability: 'available', title: 'Fixture', conversationCreatedAt: '2026-10-10T00:00:00Z', lastActivityAt: '2026-10-10T00:00:00Z' }] }; ++ const page = { page: { branch: 'b1', entries: [{ message: 'm1', role: 'assistant', createdAt: '2026-10-10T00:00:00Z', content: [{ block: 0, type: 'text', text: 'Fixture history line' }] }] }, view: { incomplete: false, defaultBranch: 'b1', branch: 'b1' }, cursor: null, follow: null }; + let gate = null; + const server = createServer(async (req, res) => { + for await (const chunk of req) { void chunk; } + await gate; +- res.writeHead(reply.status, { 'content-type': 'application/json' }); res.end(JSON.stringify(reply.body)); ++ const path = new URL(req.url, 'http://localhost').pathname; ++ const body = reply.status !== 200 ? reply.body : path === '/api/conversations' ? catalogue : path === '/api/conversation' ? page : reply.body; ++ res.writeHead(reply.status, { 'content-type': 'application/json' }); res.end(JSON.stringify(body)); + }); + return { + server, + // Holds every reply until the returned function is called. + hold: () => { let go; gate = new Promise(r => { go = r; }); return () => { gate = null; go(); }; }, + empty: () => { reply = { status: 200, body: { sessions: [], counts: {}, generatedAt: new Date().toISOString() } }; }, +- one: () => { reply = { status: 200, body: { sessions: [one, { ...one, agent: 'agent2', state: 'working', waitingOnYou: false }], counts: { waiting: 1, working: 1 }, generatedAt: new Date().toISOString() } }; }, ++ one: () => { reply = { status: 200, body: { sessions: [one, { ...one, agent: 'agent2', state: 'working', waitingOnYou: false }, { ...one, agent: 'agent3', state: 'idle', waitingOnYou: false, seen: true }], counts: { waiting: 1, working: 1 }, generatedAt: new Date().toISOString() } }; }, + fail: () => { reply = { status: 500, body: { error: 'board scan failed' } }; }, + refuse: () => { reply = { status: 403, body: { error: 'board-refused' } }; }, ++ // One seat a reply can reach: registered, alive, with a tmux session. ++ registered: () => { reply = { status: 200, body: { sessions: [{ ...one, registered: { alive: true, tmux: { session: 'fixture' } } }], counts: { waiting: 1 }, generatedAt: new Date().toISOString() } }; }, ++ unavailable: () => { reply = { status: 503, body: { error: 'board unavailable' } }; }, + }; + } + +@@ -95,6 +103,7 @@ + const shot = async name => { if (out) await b.screenshot(join(out, `shell-${name}.png`)); }; + const wait = expr => b.evaluate(`(async()=>{for(let i=0;i<100;i++){if(${expr})return true;await new Promise(r=>setTimeout(r,50))}throw new Error('Condition timed out: '+${JSON.stringify(expr)})})()`); + const text = sel => b.evaluate(`document.querySelector(${JSON.stringify(sel)})?.textContent ?? null`); ++ const count = sel => b.evaluate(`document.querySelectorAll(${JSON.stringify(sel)}).length`); + const flat = async () => assert.equal(await b.evaluate('document.documentElement.scrollWidth<=document.documentElement.clientWidth'), true, 'sideways scroll at 400px'); + const refresh = async () => { await b.evaluate('document.querySelector("#refresh").click()'); await wait('!document.querySelector("#refresh").disabled'); }; + const go = async (hash, h1) => { await b.evaluate(`location.hash=${JSON.stringify(hash)}`); await wait(`document.querySelector("#bus-view h1")?.textContent.startsWith(${JSON.stringify(h1)}) && !document.querySelector("#bus-view [aria-busy]")`); }; +@@ -140,10 +149,13 @@ + await flat(); await shot('board-stale-400'); + + // Board, a refusal: fails closed. The kept rows are hidden, and so is everything drawn from +- // them: the open inspector, the project tree's counts and the footer. ++ // them: the open inspector, the project filter, the project tree's counts and the footer. ++ await b.evaluate('document.querySelector("#projects [data-project=proj]").click()'); ++ assert.equal(await b.evaluate('document.querySelector("#projects [data-project=proj]").getAttribute("aria-pressed")'), 'true'); + await b.evaluate('document.querySelector("table.sessions [data-open]").click()'); await wait('!document.querySelector("#inspector").hidden'); + assert.equal(await text('#footer'), 'waiting 1 · working 1'); + assert.equal(await b.evaluate('document.querySelectorAll("#projects .count").length'), 2); ++ assert.equal(await count('#seen .wait-item'), 1); + brd.refuse(); await refresh(); + assert.equal(await b.evaluate('document.querySelector("#error").className'), 'banner ref'); + assert.match(await text('#error'), /The board refused the read\. refused: board-refused/); +@@ -155,14 +167,43 @@ + assert.equal(await text('#footer'), 'Board not read: refused'); + assert.equal(await text('#fresh-board'), 'Board not read: refused'); + assert.doesNotMatch(await text('#status'), /Scanned/); ++ for (const id of ['#waiting-count', '#seen-count', '#session-count']) assert.equal(await text(id), '–', id); + await flat(); await shot('board-refused-400'); ++ // A failed read after the refusal shows the board again, empty: no row, card or count from ++ // the refused scan, and the footer says what the banner says. ++ brd.unavailable(); await refresh(); ++ assert.equal(await b.evaluate('document.querySelector("#error").className'), 'banner err'); ++ assert.match(await text('#error'), /board unavailable.*No board data loaded\./); ++ assert.notEqual(await b.evaluate('getComputedStyle(document.querySelector("#board-view")).display'), 'none'); ++ assert.equal(await count('#sessions tr, #sessions [data-open], #waiting .wait-item, #seen .wait-item, #board-view [data-history]'), 0); ++ for (const id of ['#waiting-count', '#seen-count', '#session-count']) assert.equal(await text(id), '–', id); ++ assert.equal(await text('#footer'), 'Board not read: the read failed'); ++ assert.equal(await text('#fresh-board'), 'Board not read: the read failed'); ++ assert.equal(await text('#status'), 'Not read: the read failed'); ++ assert.equal(await text('#projects'), 'Not read: the read failed.'); ++ await flat(); await shot('board-refused-then-failed-400'); + brd.one(); await refresh(); + assert.equal(await b.evaluate('document.querySelector("#error").hidden'), true); ++ assert.equal(await b.evaluate('document.querySelector("#projects [data-project=\'\']").getAttribute("aria-pressed")'), 'true'); + assert.notEqual(await b.evaluate('getComputedStyle(document.querySelector("#board-view")).display'), 'none'); + assert.equal(await text('#footer'), 'waiting 1 · working 1'); + // A good read after a failed one drops the stale words. + brd.fail(); await refresh(); assert.match(await text('#fresh-board'), /stale/); + brd.one(); await refresh(); assert.match(await text('#fresh-board'), /^Board scanned \d\d:\d\d:\d\d UTC/); assert.doesNotMatch(await text('#fresh-board'), /stale/); ++ // A refusal with a conversation open closes it and clears its history and reply form: the ++ // session is in no scan the page holds. ++ brd.registered(); await refresh(); await wait('document.querySelectorAll("table.sessions tbody tr").length===1'); ++ await b.evaluate('document.querySelector("table.sessions [data-history]").click()'); ++ await wait('document.querySelector("#conv-log").textContent.includes("Fixture history line")'); ++ assert.equal(await b.evaluate('document.querySelector("#conv-form").hidden'), false); ++ brd.refuse(); await refresh(); ++ assert.equal(await b.evaluate('document.querySelector("#conversation").hidden'), true); ++ assert.equal(await b.evaluate('document.body.classList.contains("has-conversation")'), false); ++ assert.equal(await count('#conv-log > *'), 0); ++ assert.equal(await b.evaluate('document.querySelector("#conv-form").checkVisibility()'), false); ++ assert.equal(await b.evaluate('getComputedStyle(document.querySelector("#board-view")).display'), 'none'); ++ assert.equal(await b.evaluate('document.querySelector("#board-refused").hidden'), false); ++ brd.one(); await refresh(); await wait('document.querySelectorAll("table.sessions tbody tr").length===2'); + + // Keyboard on the board: down moves between rows, Enter opens, Esc closes and returns focus. + await b.evaluate('document.querySelector("table.sessions [data-open]").focus()'); diff --git a/agents/darkwing/work/queue-53-review/r3/out/summary.txt b/agents/darkwing/work/queue-53-review/r3/out/summary.txt new file mode 100644 index 00000000..59a5c90c --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/summary.txt @@ -0,0 +1,14 @@ +start 2026-10-10T19:23:02Z +node-webui exit=0 ℹ pass 27 ℹ fail 0 +build-tokens --check exit=0 tokens.css is current +test-auth exit=0 selftest: 15 passed, 0 failed +test-conductor exit=0 selftest: 17 passed, 0 failed +test-config exit=0 selftest: 24 passed, 0 failed +test-discord exit=0 discord suite: 66 passed, 0 failed +test-extension-package exit=0 extension package selftest: 18 passed, 0 failed +test-foundation exit=0 selftest: 44 passed, 0 failed +test-queue exit=0 queue suite: 27 passed, 0 failed +test-release exit=0 selftest: 4 passed, 0 failed +test-task exit=0 selftest: 26 passed, 0 failed +end 2026-10-10T19:26:06Z +DONE diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-auth.txt b/agents/darkwing/work/queue-53-review/r3/out/test-auth.txt new file mode 100644 index 00000000..ac228760 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-auth.txt @@ -0,0 +1,17 @@ +OK status with missing harness credential exits 3 and still lists accounts +OK status reports harness credential (read-only) + mosaic accounts +OK api key material never reaches output +OK oauth token material never reaches output +OK unparseable credential file exits 2 +OK symlinked credential file exits 4 +OK env-side credential names reported +OK env var values never reach output +OK accounts without an accounts dir reports none and creates nothing +OK accounts lists files and marks the active one +OK loose account perms flagged in listing +OK agent --auth with missing account file refuses (exit 4) +OK agent --auth with non-0600 account file refuses +OK agent --auth with invalid account name refuses +OK auth.sh without valid config refuses + +selftest: 15 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-conductor.txt b/agents/darkwing/work/queue-53-review/r3/out/test-conductor.txt new file mode 100644 index 00000000..62afc513 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-conductor.txt @@ -0,0 +1,23 @@ +On branch refactor +Your branch is up to date with 'origin/refactor'. + +nothing to commit, working tree clean +OK dry-run: allowed change, exit 0, nothing committed (exit 0) +OK dry-run committed nothing +OK apply: allowed change exits 0 (exit 0) +OK apply: attribution in commit subject +OK apply: target tree clean after commit +OK disallowed path refused (exit 1) +OK disallowed path: target untouched +OK syntax gate refused broken .mjs (exit 1) +OK syntax gate: target untouched +OK suite failure refused (exit 1) +OK suite failure: target reverted to clean +OK disabled policy refused (exit 2) +OK disabled policy: target untouched +OK failed run refused (exit 1) +OK failed run: target untouched +OK missing run exits 4 (exit 4) +OK invalid policy exits 2 (exit 2) + +selftest: 17 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-config.txt b/agents/darkwing/work/queue-53-review/r3/out/test-config.txt new file mode 100644 index 00000000..76c05ef7 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-config.txt @@ -0,0 +1,26 @@ +OK absent adapter defaults to pi +OK adapter mock validates (exit 0) +OK unsupported adapter exits 2 (exit 2) +OK env exports adapter +OK bootstrap creates default when absent (exit 0) +OK bootstrap wrote config file +OK bootstrap is idempotent on existing config (exit 0) +OK bootstrap did not rewrite existing config +OK validate missing config exits 3 (exit 3) +OK malformed JSON exits 2 (exit 2) +OK unsupported configVersion exits 2 (exit 2) +OK unknown top-level key exits 2 (exit 2) +OK unknown execution key exits 2 (exit 2) +OK unsupported backend exits 2 (exit 2) +OK unsupported environment exits 2 (exit 2) +OK relative dataRoot exits 2 (exit 2) +OK non-canonical dataRoot exits 2 (exit 2) +OK filesystem root dataRoot exits 2 (exit 2) +OK home directory dataRoot exits 2 (exit 2) +OK dataRoot containing config dir exits 2 (exit 2) +OK control character in provider exits 2 (exit 2) +OK symlinked config file exits 2 (exit 2) +OK env exports resolve correctly +OK failed validation modified nothing + +selftest: 24 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-discord.txt b/agents/darkwing/work/queue-53-review/r3/out/test-discord.txt new file mode 100644 index 00000000..b013f9ff --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-discord.txt @@ -0,0 +1,70 @@ +toolchain: node v26.8.1 + +OK syntax: packages/discord/src/approvals.mjs +OK syntax: packages/discord/src/authorize.mjs +OK syntax: packages/discord/src/binding.mjs +OK syntax: packages/discord/src/cli.mjs +OK syntax: packages/discord/src/connector.mjs +OK syntax: packages/discord/src/context.mjs +OK syntax: packages/discord/src/engine-pi.mjs +OK syntax: packages/discord/src/errors.mjs +OK syntax: packages/discord/src/gateway.mjs +OK syntax: packages/discord/src/git.mjs +OK syntax: packages/discord/src/journal.mjs +OK syntax: packages/discord/src/notify.mjs +OK syntax: packages/discord/src/rest.mjs +OK syntax: packages/discord/src/setspark.mjs +OK syntax: packages/discord/src/tools.mjs +OK syntax: packages/discord/src/web.mjs +OK syntax: packages/discord/bin/git-credential.mjs +OK syntax: packages/discord/extension/tools.mjs +OK syntax: packages/discord/tests/approvals.test.mjs +OK syntax: packages/discord/tests/authorize.test.mjs +OK syntax: packages/discord/tests/binding.test.mjs +OK syntax: packages/discord/tests/connector.test.mjs +OK syntax: packages/discord/tests/context.test.mjs +OK syntax: packages/discord/tests/engine.test.mjs +OK syntax: packages/discord/tests/fake-pi.mjs +OK syntax: packages/discord/tests/gateway.test.mjs +OK syntax: packages/discord/tests/git.test.mjs +OK syntax: packages/discord/tests/helpers.mjs +OK syntax: packages/discord/tests/journal.test.mjs +OK syntax: packages/discord/tests/notify.test.mjs +OK syntax: packages/discord/tests/recover.test.mjs +OK syntax: packages/discord/tests/rest.test.mjs +OK syntax: packages/discord/tests/setspark.test.mjs +OK syntax: packages/discord/tests/tools.test.mjs +OK syntax: packages/discord/tests/web.test.mjs +OK syntax: packages/discord/fixtures/claim-worker.mjs +OK syntax: packages/discord/fixtures/legacy-owner-worker.mjs +OK syntax: scripts/discord.sh +OK syntax: scripts/discord-service.sh +OK packages/discord declares no dependencies +OK no bot-token-shaped string in packages/discord +OK fixture binding uses placeholder ids only +OK fixture binding validates +OK real pi with the extension exposes exactly list_dir, read_file, search and no built-in tool +OK real pi with a writable root exposes exactly the three reads plus write_file and edit_file, and writes nothing at start +OK real pi with a web key exposes the three reads plus web_fetch and web_search, and no write tool without a writable root +OK real pi with a git root exposes the reads, writes and the four git verbs, commits nothing at start, and never shows the token +OK real pi with protocol vault adds reserve_id to the git verbs +OK real pi with a setspark key exposes the reads and the eight record verbs, no counters, and never shows the key +OK real pi refuses a git key on a read-only root (fail closed) +OK real pi with the pilot flags (--no-tools) exposes no tool at all +OK real pi exits non-zero without MOSAIC_DISCORD_TOOLS: no session, no tools (fail closed) +OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT +OK node --test packages/discord/tests/ (ℹ pass 178) +OK scripts/discord.sh --help exits 0 +OK scripts/discord.sh check without a binding exits 4 +OK scripts/discord.sh recover without a binding exits 4 +OK scripts/discord.sh reload without a binding exits 4 +OK scripts/discord-service.sh without a command exits 4 +OK service unit renders with the repository path, a supervised run as the main process, exit 3 never retried, and reload as SIGHUP +OK service install writes the rendered unit (0644) and leaves no temp file +OK service install a second time reports unchanged +OK systemd-analyze verify accepts the rendered unit +OK service uninstall removes the unit file +OK service install with an unknown flag exits 4 +OK service install with USER unset finishes and names the account for lingering + +discord suite: 66 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-extension-package.txt b/agents/darkwing/work/queue-53-review/r3/out/test-extension-package.txt new file mode 100644 index 00000000..7c6238b1 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-extension-package.txt @@ -0,0 +1,21 @@ +OK initial ordinary-file install +OK installed tree matches canonical source +OK installed tree has no symlinks +OK check detects installation drift +OK sync refuses to overwrite installation drift +OK check detects an extra destination file +OK check detects an extra destination directory +OK check rejects a destination symlink +OK sync accepts a canonical source update +OK updated installation matches canonical source +scripts/test-extension-package.sh: line 14: 3852416 Killed "$@" > /dev/null 2>&1 +OK forced interruption kills the replacing process +OK next invocation recovers old consistent installation +OK interrupted replacement rolled back +OK sync succeeds after interruption recovery +OK unlocked stale lock file does not block +OK active lock refuses a concurrent sync +OK source symlink fails closed +OK nested second entrypoint fails closed + +extension package selftest: 18 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-foundation.txt b/agents/darkwing/work/queue-53-review/r3/out/test-foundation.txt new file mode 100644 index 00000000..6338e1e6 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-foundation.txt @@ -0,0 +1,53 @@ +toolchain: node v26.8.1, python 3.12.8, jsonschema 4.26.0 + +OK syntax: scripts/foundation-inspect.mjs +OK syntax: scripts/foundation/strict-json.mjs +OK syntax: scripts/foundation/canonical.mjs +OK syntax: scripts/foundation/resolve.mjs +OK syntax: scripts/foundation/validate-record.mjs +OK syntax: scripts/foundation/fixtures/build-fixtures.mjs +OK syntax: scripts/foundation/canonical.test.mjs +OK syntax: scripts/foundation/cli.test.mjs +OK syntax: scripts/foundation/fixtures.test.mjs +OK syntax: scripts/foundation/resolve.test.mjs +OK syntax: scripts/foundation/strict-json.test.mjs +OK syntax: scripts/foundation/verify-schema.py (ast only; no bytecode written) +OK fixture generator runs +OK checked-in fixtures/bundles equal a fresh generation +OK checked-in fixtures/raw equal a fresh generation +OK checked-in fixtures/index.json equal a fresh generation +OK checked-in demo bundles equal a fresh generation +OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT +OK node --test scripts/foundation/ (ℹ pass 80) +OK differential schema oracle: PASS: differential schema oracle (finite corpus; compatibility evidence, not equivalence proof) + platform witness: strftime('%Y') for year 999 -> '999' (pinned checker refuses years 0001..0999) + node v26.8.1; corpus 1568 records (38 pinned fixtures, 478 unique bundle records, 1052 typeCase/mutation/lexical cases) + schema column: agree-valid 540, agree-invalid 991, DISAGREEMENTS 0; strict-only (parser-bound) cases: 27; unsupported-kind records not schema-assessed by the inspector: 10 + profile column (schema-valid records only): profile-valid 510, profile-invalid 30 + profile refusals asserted: 30 schema-agreed-valid records refused only by the strict typed-string profile (rule profile-pattern-mismatch), 12 declared by name; 73 named probes verified against declared schema/profile columns +OK oracle: zero schema-column disagreements with the pinned checker +OK oracle: strict-only profile refusals are counted and asserted +OK demo: permitted read preview exits 0 (exit 0) +OK demo: permitted file.change preview exits 0 (exit 0) +OK demo: assignment.change proposal is unresolved (exit 3) (exit 3) +OK demo: revoked registration is refused (exit 3) (exit 3) +OK demo: message is not authority (exit 3) (exit 3) +OK usage: no arguments exits 2 (exit 2) +OK io: missing file exits 4 (exit 4) +OK io: directory exits 4 (exit 4) +OK io: symlink exits 4 (O_NOFOLLOW) (exit 4) +OK bound: oversize fixture exits 2 (exit 2) +OK profile: one final LF in a typed selection id is refused before admission (exit 2) (exit 2) +OK profile: two final LFs fail the schema pattern itself (exit 2) (exit 2) +OK profile: escaped newlines in free-form text stay allowed (exit 0) (exit 0) +OK profile refusal is invalid-request/profile-pattern-mismatch with selection and operation withheld, value not echoed +OK text output starts with the disclaimer +OK json output is valid JSON with result allowed and exactly the charter §7 fields +OK json golden matches byte-for-byte +OK sandboxed bundle run (env -i, PATH=/nonexistent) produced the unresolved proposal +OK sandbox inventory (path/type/size/mode/uid/gid/inode/mtime/sha256) unchanged by runs +OK canary never printed (bundle run and credential-file run) +OK a non-bundle JSON file is refused at the shape gate, not read into output +OK no field of the non-bundle file is echoed + +selftest: 44 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-queue.txt b/agents/darkwing/work/queue-53-review/r3/out/test-queue.txt new file mode 100644 index 00000000..d1398dbe --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-queue.txt @@ -0,0 +1,35 @@ +toolchain: node v26.8.1, git version 2.55.0 + +OK syntax: packages/queue/src/cli.mjs +OK syntax: packages/queue/src/errors.mjs +OK syntax: packages/queue/src/io.mjs +OK syntax: packages/queue/src/lock.mjs +OK syntax: packages/queue/src/queue.mjs +OK syntax: packages/queue/src/review.mjs +OK syntax: packages/queue/src/store.mjs +OK syntax: packages/queue/tests/commit.test.mjs +OK syntax: packages/queue/tests/data.test.mjs +OK syntax: packages/queue/tests/dispatch.test.mjs +OK syntax: packages/queue/tests/helpers.mjs +OK syntax: packages/queue/tests/lock.test.mjs +OK syntax: packages/queue/tests/migration.test.mjs +OK syntax: packages/queue/tests/review.test.mjs +OK syntax: packages/queue/tests/store.test.mjs +OK syntax: packages/queue/tests/write.test.mjs +OK syntax: packages/queue/tests/fixtures/fake-gitea.mjs +OK syntax: packages/queue/tests/fixtures/kill-at.mjs +OK syntax: packages/queue/tests/fixtures/lock-child.mjs +OK syntax: packages/queue/tests/fixtures/mosaic-pre-a2.sh +OK syntax: scripts/queue-commit.sh +OK syntax: scripts/git-hooks/pre-commit +OK syntax: scripts/mosaic +OK queue-commit.sh, the guard and scripts/mosaic are executable +OK packages/queue declares no dependencies +ℹ tests 148 +ℹ pass 148 +ℹ fail 0 +OK node --test packages/queue/tests/ +OK scripts/mosaic queue help +skip queue verify and render --check: this checkout (/home/jwoltje/darkwing-scratch/r53c/cand) is not the queue's canonical root (/mnt/storage/src/mosaic-stack) + +queue suite: 27 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-release-docker.txt b/agents/darkwing/work/queue-53-review/r3/out/test-release-docker.txt new file mode 100644 index 00000000..7202b85d --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-release-docker.txt @@ -0,0 +1,16 @@ +OK valid RELEASE resolves (exit 0) +OK invalid RELEASE exits 1 (exit 1) +OK missing RELEASE exits 1 (exit 1) +OK valid RELEASE leaves image tag consistent with version +OK status safe on empty state (exit 0) +OK status created no pointer +OK fault-injected activation refuses (exit 1) +OK refused activation wrote no pointer +OK refusal logged exactly once with valid fields +OK healthy activation succeeds (exit 0) +OK pointer written with valid fields +OK repeat activation succeeds (log grows) (exit 0) +OK log is append-only across activations +OK rollback without previous refuses (exit 1) + +selftest: 14 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-release.txt b/agents/darkwing/work/queue-53-review/r3/out/test-release.txt new file mode 100644 index 00000000..1d6ed050 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-release.txt @@ -0,0 +1,7 @@ +OK valid RELEASE resolves (exit 0) +OK invalid RELEASE exits 1 (exit 1) +OK missing RELEASE exits 1 (exit 1) +OK valid RELEASE leaves image tag consistent with version +skip state-machine cases (docker daemon unavailable) + +selftest: 4 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/out/test-task.txt b/agents/darkwing/work/queue-53-review/r3/out/test-task.txt new file mode 100644 index 00000000..cd89fe9b --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/out/test-task.txt @@ -0,0 +1,32 @@ +OK valid task validates (exit 0) +OK unknown task key exits 2 (exit 2) +OK unsupported taskVersion exits 2 (exit 2) +OK invalid task id exits 2 (exit 2) +OK empty prompt exits 2 (exit 2) +OK NUL in expectExact exits 2 (exit 2) +OK out-of-range timeout exits 2 (exit 2) +OK missing mission file exits 4 (exit 4) +OK task with valid mission validates (exit 0) +OK invalid mission exits 2 (exit 2) +OK validate missing task exits 4 (exit 4) +OK validation does not modify the task file +OK prune dry-run exits 0 (exit 0) +OK dry-run deleted nothing +OK prune --keep=2 --yes removes oldest (exit 0) +OK kept exactly 2 newest runs +OK newest run kept, oldest pruned +OK append-only receipt written (3 entries) +OK sessions/workspaces untouched by prune +OK prune with invalid keep exits 4 (exit 4) +skip adapter seam cases (docker daemon unavailable) +skip workspace/capability cases (docker daemon unavailable) +skip live task cases (docker unavailable) +OK onboard without name exits 4 (non-interactive) (exit 4) +OK onboard --name renders profile (exit 0) +OK profile written +OK canon structure: required filled, optional placeholdered +OK canon sections present +skip live recall pair: user recall run, recalled user name (docker daemon unavailable) +OK no agent identity on headless run + +selftest: 26 passed, 0 failed diff --git a/agents/darkwing/work/queue-53-review/r3/probes/probe3.test.mjs b/agents/darkwing/work/queue-53-review/r3/probes/probe3.test.mjs new file mode 100644 index 00000000..dcf6da17 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/probes/probe3.test.mjs @@ -0,0 +1,163 @@ +// Darkwing row 53 round 3 probes: round 2's probe set again (P1-P9, with P9 a 403 then a 500), then +// the conversation cases on the real control-board fixture: P10 (a 403 with History open), P11 (the +// session picker after a refusal, when the next catalogue read fails), P13 (a 403 while a history +// page is still in flight), and P12 (a first read that fails, before any scan). +// Run from a worktree's packages/webui: node --test with WT set to that worktree. +import { test, after } from 'node:test'; +import assert from 'node:assert/strict'; +import { createServer, request } from 'node:http'; +import { pathToFileURL } from 'node:url'; +const WT = process.env.WT; +const u = p => pathToFileURL(`${WT}/packages/webui/${p}`).href; +const { browser } = await import(u('tests/browser.mjs')); +const { close } = await import(u('tests/fixture.mjs')); +const { startServer } = await import(u('src/serve.mjs')); +const { BusReadError } = await import(u('src/bus.mjs')); +const H = await import(u('tests/history-fixture.mjs')); +const out = []; +const note = (k, v) => { out.push(`${k}: ${JSON.stringify(v)}`); }; + +after(() => console.log(out.join('\n'))); +test('probes, fake board and bus', { timeout: 120000 }, async () => { + let reply = null; + const one = { agent: 'agent1', project: 'secretproj', state: 'waiting', waitingOnYou: true, task: 'Kept fixture task', lastActivity: '2026-10-10T00:00:00Z', lastAssistantText: 'Input needed: kept text', registered: null }; + const ok = () => { reply = { status: 200, body: { sessions: [one, { ...one, agent: 'agent2', state: 'working', waitingOnYou: false }], counts: { waiting: 1, working: 1 }, generatedAt: new Date().toISOString() } }; }; + ok(); + const brd = createServer(async (req, res) => { for await (const c of req) void c; res.writeHead(reply.status, { 'content-type': 'application/json' }); res.end(JSON.stringify(reply.body)); }); + await new Promise(r => brd.listen(0, '127.0.0.1', r)); + const rows = { inbox: [{ id: 'd'.repeat(32), question: 'Kept question?', class: 'gated', action: 'git.push.protected', blocking: true, options: [{ key: 'yes', text: 'Yes' }], at: new Date().toISOString(), raised_by: 'coder' }], tasks: [{ task_ref: 'vikunja:32/7', fields: { title: 'Kept task title', bucket: 2, done: false, assignees: [] }, source: 'self' }], agents: [], trail: [] }; + let fail = null; + const verb = n => async () => { if (fail) throw new BusReadError(fail, `fixture ${fail}`); return structuredClone(rows[n]); }; + const web = await startServer({ port: 0, board: `http://127.0.0.1:${brd.address().port}`, bus: { inbox: verb('inbox'), tasks: verb('tasks'), agents: verb('agents'), trail: verb('trail') } }); + const base = `http://127.0.0.1:${web.address().port}/`, b = await browser(); + const wait = expr => b.evaluate(`(async()=>{for(let i=0;i<100;i++){if(${expr})return true;await new Promise(r=>setTimeout(r,50))}throw new Error('timed out: '+${JSON.stringify(expr)})})()`); + const vis = sel => b.evaluate(`(()=>{const e=document.querySelector(${JSON.stringify(sel)});if(!e)return null;return {shown:!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)&&!e.closest('[hidden]'),text:e.innerText.slice(0,200)}})()`); + const refresh = async () => { await b.evaluate('document.querySelector("#refresh").click()'); await wait('!document.querySelector("#refresh").disabled'); }; + try { + await b.viewport(1440, 900); + await b.navigate(base); await wait('document.querySelectorAll("table.sessions tbody tr").length===2'); + await b.evaluate('document.querySelector("table.sessions [data-open]").click()'); + await wait('document.querySelector("#inspector-title")?.textContent==="agent1"'); + reply = { status: 403, body: { error: 'non-local Host refused' } }; + await refresh(); + await wait('document.querySelector("#error").className==="banner ref"'); + note('P1 board refused: board-view display', await b.evaluate('getComputedStyle(document.querySelector("#board-view")).display')); + note('P1 board refused: inspector', await vis('#inspector')); + note('P2 board refused: projects tree', await vis('#projects')); + note('P2 board refused: footer', await vis('#footer')); + note('P2 board refused: #status', await vis('#status')); + note('P2 board refused: #fresh-board', await vis('#fresh-board')); + // P9: still no good read, now a 500. Do the rows from before the refusal come back? + reply = { status: 500, body: { error: 'scan failed' } }; + await refresh(); await wait('document.querySelector("#error").className==="banner err"'); + note('P9 403 then 500: board-view display', await b.evaluate('getComputedStyle(document.querySelector("#board-view")).display')); + note('P9 403 then 500: session rows in the DOM and shown', await b.evaluate('[document.querySelectorAll("table.sessions tbody tr").length, !!document.querySelector("table.sessions")?.offsetHeight]')); + note('P9 403 then 500: #waiting', await vis('#waiting')); + note('P9 403 then 500: #sessions', await vis('#sessions')); + note('P9 403 then 500: projects, footer, status, fresh', [await vis('#projects'), await vis('#footer'), await vis('#status'), await vis('#fresh-board')]); + note('P9 403 then 500: banner', await vis('#error')); + ok(); await refresh(); await wait('document.querySelector("#error").hidden'); + note('P9b recovered: rows, footer', [await b.evaluate('document.querySelectorAll("table.sessions tbody tr").length'), await vis('#footer')]); + // P3/P4: bus pages read once, then the bus refuses. + await b.evaluate('location.hash="#/tasks"'); await wait('document.querySelectorAll("#bus-view td.s1-title a").length===1'); + await b.evaluate('location.hash="#/inbox"'); await wait('!!document.querySelector("#bus-view .s1-dec-open")'); + fail = 'human-required'; await refresh(); await wait('!!document.querySelector("#bus-view .banner.ref")'); + note('P4 bus refused: section list', await vis('#sections')); + await b.evaluate('document.querySelector("#cmdk").click()'); await wait('document.querySelector("#cmdk-dialog").open'); + await new Promise(r => setTimeout(r, 500)); + note('P3 bus refused: palette list', await b.evaluate('[...document.querySelectorAll("#cmdk-list li")].map(l=>l.innerText.replace(/\\n/g," | "))')); + await b.key('Escape'); + await b.evaluate('location.hash="#/"'); await wait('document.querySelectorAll("table.sessions tbody tr").length===2'); + await new Promise(r => setTimeout(r, 500)); + note('P4b board page, bus refused: section list', await vis('#sections')); + fail = 'not-configured'; await b.evaluate('location.hash="#/tasks"'); await wait('!!document.querySelector("#bus-view .banner")'); + note('P6 not-configured: banner class, task links', await b.evaluate('[document.querySelector("#bus-view .banner").className, document.querySelectorAll("#bus-view td.s1-title a").length]')); + fail = 'outcome-unknown'; await refresh(); await wait('!!document.querySelector("#bus-view .banner")'); + note('P7 refusal then outcome-unknown: banner class, task links, banner text', await b.evaluate('[document.querySelector("#bus-view .banner").className, document.querySelectorAll("#bus-view td.s1-title a").length, document.querySelector("#bus-view .banner").innerText.slice(0,160)]')); + const ax = await b.call('Accessibility.getFullAXTree', {}); + note('P8 status/live nodes before any toast', ax.nodes.filter(n => ['status'].includes(n.role?.value)).map(n => n.name?.value ?? '')); + note('P8 toast display, rect', await b.evaluate('(()=>{const t=document.querySelector("#toast"),r=t.getBoundingClientRect();return [getComputedStyle(t).display,r.width,r.height,t.querySelectorAll("button").length]})()')); + note('errors', await b.evaluate('window.errors||null')); + } finally { + await b.close(); await close(web); await new Promise(r => brd.close(r)); + } +}); + +test('probes P10, P11, P13 on the real control-board', { timeout: 120000 }, async () => { + const fx = await H.historyFixture(); + const s = H.session(`${fx.sessionsDir}/2026-10-10T00-00-00-000Z_sess-1.jsonl`, fx.projectRoot); + s.add(H.user('Secret question from before the refusal')); s.add(H.assistant('Secret answer from before the refusal')); + // A proxy in front of the real board. refuse: every request 403. catFail: the catalogue 500. + // hold: history page requests wait until released, then go upstream as they were. + let refuse = false, catFail = false, hold = false; const held = []; + const up = new URL(`http://127.0.0.1:${fx.board.address().port}`); + const pass = (req, res) => { const p = request({ host: up.hostname, port: up.port, path: req.url, method: req.method, headers: { ...req.headers, host: up.host } }, r => { res.writeHead(r.statusCode, r.headers); r.pipe(res); }); req.pipe(p); }; + const proxy = createServer((req, res) => { + const path = new URL(req.url, 'http://x').pathname; + if (hold && path === '/api/conversation') { held.push(() => pass(req, res)); return; } + if (refuse) { res.writeHead(403, { 'content-type': 'application/json' }); res.end(JSON.stringify({ error: 'non-local Host refused' })); req.resume(); return; } + if (catFail && path === '/api/conversations') { res.writeHead(500, { 'content-type': 'application/json' }); res.end(JSON.stringify({ error: 'catalogue failed' })); req.resume(); return; } + pass(req, res); + }); + await new Promise(r => proxy.listen(0, '127.0.0.1', r)); + const web = await startServer({ port: 0, board: `http://127.0.0.1:${proxy.address().port}` }); + const b = await browser(), wait = H.waiter(b); + const vis = sel => b.evaluate(`(()=>{const e=document.querySelector(${JSON.stringify(sel)});if(!e)return null;return {shown:!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)&&!e.closest('[hidden]'),text:e.innerText.slice(0,200)}})()`); + const refresh = async () => { await b.evaluate('document.querySelector("#refresh").click()'); await wait('!document.querySelector("#refresh").disabled'); }; + const state = () => b.evaluate('({conversation:document.querySelector("#conversation").hidden, hasConv:document.body.classList.contains("has-conversation"), log:document.querySelector("#conv-log").children.length, logText:document.querySelector("#conv-log").textContent.slice(0,120), form:document.querySelector("#conv-form").checkVisibility(), active:document.activeElement.id||document.activeElement.tagName, boardView:getComputedStyle(document.querySelector("#board-view")).display})'); + try { + await b.viewport(1440, 900); + await b.navigate(`http://127.0.0.1:${web.address().port}/`); + await wait('!!document.querySelector("[data-history]")'); + await b.evaluate('document.querySelector("[data-history]").click()'); + await wait('document.querySelector("#conv-log")?.textContent.includes("Secret answer")'); + note('P10 before: conv-pick options', await b.evaluate('[...document.querySelectorAll("#conv-pick option")].map(o=>o.textContent)')); + refuse = true; await refresh(); await wait('document.querySelector("#error").className==="banner ref"'); + await new Promise(r => setTimeout(r, 500)); + note('P10 after 403: state', await state()); + note('P10 after 403: #conversation', await vis('#conversation')); + note('P10 after 403: board-refused', await vis('#board-refused')); + note('P10 after 403: conv-pick and conv-meta in the DOM', await b.evaluate('[[...document.querySelectorAll("#conv-pick option")].map(o=>o.textContent), document.querySelector("#conv-meta").textContent]')); + // P11: the board answers again, History is opened again, and the catalogue read fails. + refuse = false; await refresh(); await wait('document.querySelector("#error").hidden && !!document.querySelector("[data-history]")'); + catFail = true; + await b.evaluate('document.querySelector("[data-history]").click()'); + await wait('/History unavailable/.test(document.querySelector("#conv-status").textContent)'); + note('P11 catalogue fails after refusal: conv-pick', await vis('#conv-pick')); + note('P11 options', await b.evaluate('[...document.querySelectorAll("#conv-pick option")].map(o=>o.textContent)')); + note('P11 conv-meta, conv-status', [await vis('#conv-meta'), await vis('#conv-status')]); + // P13: History open again with the page held; the board refuses; then the held page answers. + catFail = false; await b.evaluate('document.querySelector("#conv-back").click()'); await wait('document.querySelector("#conversation").hidden'); + hold = true; + await b.evaluate('document.querySelector("[data-history]").click()'); + await wait('/Loading history/.test(document.querySelector("#conv-status").textContent)'); + for (let i = 0; i < 100 && !held.length; i++) await new Promise(r => setTimeout(r, 50)); + note('P13 held page requests', held.length); + refuse = true; await refresh(); await wait('document.querySelector("#error").className==="banner ref"'); + hold = false; refuse = false; for (const go of held.splice(0)) go(); + await new Promise(r => setTimeout(r, 1500)); + note('P13 after the held page answered: state', await state()); + note('errors', await b.evaluate('window.errors||null')); + } finally { + await b.close(); await close(web); await new Promise(r => proxy.close(r)); await fx.close(); + } +}); + +test('probe P12, the first read fails', { timeout: 60000 }, async () => { + let reply = { status: 500, body: { error: 'scan failed' } }; + const brd = createServer(async (req, res) => { for await (const c of req) void c; res.writeHead(reply.status, { 'content-type': 'application/json' }); res.end(JSON.stringify(reply.body)); }); + await new Promise(r => brd.listen(0, '127.0.0.1', r)); + const web = await startServer({ port: 0, board: `http://127.0.0.1:${brd.address().port}` }); + const b = await browser(); + const wait = expr => b.evaluate(`(async()=>{for(let i=0;i<100;i++){if(${expr})return true;await new Promise(r=>setTimeout(r,50))}throw new Error('timed out: '+${JSON.stringify(expr)})})()`); + const vis = sel => b.evaluate(`(()=>{const e=document.querySelector(${JSON.stringify(sel)});if(!e)return null;return {shown:!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)&&!e.closest('[hidden]'),text:e.innerText.slice(0,200)}})()`); + try { + await b.viewport(1440, 900); + await b.navigate(`http://127.0.0.1:${web.address().port}/`); await wait('!document.querySelector("#error").hidden'); + note('P12 first read 500: board-view display', await b.evaluate('getComputedStyle(document.querySelector("#board-view")).display')); + note('P12 projects, footer, status, fresh, banner', [await vis('#projects'), await vis('#footer'), await vis('#status'), await vis('#fresh-board'), await vis('#error')]); + note('P12 waiting, sessions', [await vis('#waiting'), await vis('#sessions')]); + } finally { + await b.close(); await close(web); await new Promise(r => brd.close(r)); + } +}); diff --git a/agents/darkwing/work/queue-53-review/r3/probes/probes-cand.txt b/agents/darkwing/work/queue-53-review/r3/probes/probes-cand.txt new file mode 100644 index 00000000..5dc508db --- /dev/null +++ b/agents/darkwing/work/queue-53-review/r3/probes/probes-cand.txt @@ -0,0 +1,46 @@ +✔ probes, fake board and bus (2656.90098ms) +✔ probes P10, P11, P13 on the real control-board (3802.384625ms) +P1 board refused: board-view display: "none" +P1 board refused: inspector: {"shown":false,"text":"agent1CloseStatewaitingProjectsecretprojTaskKept fixture taskTask sourceunknownTask set bynot applicable (task is not from a registration)Active projectunknownWorkspaceunknownModelunknownRegisteredNo "} +P2 board refused: projects tree: {"shown":true,"text":"Not read: the board refused the read."} +P2 board refused: footer: {"shown":true,"text":"Board not read: refused"} +P2 board refused: #status: {"shown":true,"text":"Not read: the board refused the read"} +P2 board refused: #fresh-board: {"shown":true,"text":"Board not read: refused"} +P9 403 then 500: board-view display: "block" +P9 403 then 500: session rows in the DOM and shown: [0,false] +P9 403 then 500: #waiting: {"shown":true,"text":""} +P9 403 then 500: #sessions: {"shown":true,"text":""} +P9 403 then 500: projects, footer, status, fresh: [{"shown":true,"text":"Not read: the read failed."},{"shown":true,"text":"Board not read: the read failed"},{"shown":true,"text":"Not read: the read failed"},{"shown":true,"text":"Board not read: the read failed"}] +P9 403 then 500: banner: {"shown":true,"text":"scan failed Board: http://127.0.0.1:45189. No board data loaded. Use Refresh to try again."} +P9b recovered: rows, footer: [2,{"shown":true,"text":"waiting 1 · working 1"}] +P4 bus refused: section list: {"shown":true,"text":"Board\nInbox\nTasks\nAgents"} +P3 bus refused: palette list: ["Board | view","Inbox | view","Tasks | view","Agents | view"] +P4b board page, bus refused: section list: {"shown":true,"text":"Board\nInbox\nTasks\nAgents"} +P6 not-configured: banner class, task links: ["banner ref",0] +P7 refusal then outcome-unknown: banner class, task links, banner text: ["banner err",0,"The bus did not answer in time. (outcome-unknown) Console shows nothing rather than a guess. Nothing was written.\n\nRead again"] +P8 status/live nodes before any toast: [""] +P8 toast display, rect: ["flex",1,1,0] +errors: null +P10 before: conv-pick options: ["Secret question from before the refusal · 2026-10-10T19:25:10.918Z"] +P10 after 403: state: {"conversation":true,"hasConv":false,"log":0,"logText":"","form":false,"active":"BODY","boardView":"none"} +P10 after 403: #conversation: {"shown":false,"text":"fixture conversationrepo · Secret question from before the refusal · started 2026-10-10T19:15:10.918ZSessionSecret question from before the refusal · 2026-10-10T19:25:10.918ZBack to board\n2 messages ·"} +P10 after 403: board-refused: {"shown":true,"text":"Nothing to show.\n\nThe board refused the read, so Console shows nothing rather than a guess. The reason is above."} +P10 after 403: conv-pick and conv-meta in the DOM: [["Secret question from before the refusal · 2026-10-10T19:25:10.918Z"],"repo · Secret question from before the refusal · started 2026-10-10T19:15:10.918Z"] +P11 catalogue fails after refusal: conv-pick: {"shown":true,"text":"Secret question from before the refusal · 2026-10-10T19:25:10.918Z"} +P11 options: ["Secret question from before the refusal · 2026-10-10T19:25:10.918Z"] +P11 conv-meta, conv-status: [{"shown":true,"text":""},{"shown":true,"text":"History unavailable: catalogue failed."}] +P13 held page requests: 1 +P13 after the held page answered: state: {"conversation":true,"hasConv":false,"log":0,"logText":"","form":false,"active":"BODY","boardView":"none"} +errors: null +P12 first read 500: board-view display: "block" +P12 projects, footer, status, fresh, banner: [{"shown":true,"text":"Not read: the read failed."},{"shown":true,"text":"Board not read: the read failed"},{"shown":true,"text":"Not read: the read failed"},{"shown":true,"text":"Board not read: the read failed"},{"shown":true,"text":"scan failed Board: http://127.0.0.1:40057. No board data loaded. Use Refresh to try again."}] +P12 waiting, sessions: [{"shown":true,"text":""},{"shown":true,"text":""}] +✔ probe P12, the first read fails (1018.796797ms) +ℹ tests 3 +ℹ suites 0 +ℹ pass 3 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 7599.426941 diff --git a/agents/darkwing/work/queue-53-review/review-r3.md b/agents/darkwing/work/queue-53-review/review-r3.md new file mode 100644 index 00000000..ca567ae9 --- /dev/null +++ b/agents/darkwing/work/queue-53-review/review-r3.md @@ -0,0 +1,154 @@ +# Row 53, console tokens and shell restyle, round 3 review (Darkwing) + +Issue #1542, request comment 27168, packet comment 27169, queue revs +367-369. Base `ea080fd8`. Candidate manifest sha256 +`2562c05d4a92f90096c0fe68ef8c2adfa7244fa547f3390155f5bee5cce64cba`, the +same 16 files under `packages/webui`. The packet manifest and my snapshot +of the checkout both check 16 OK. `round3.patch` applied to my round 2 +snapshot gives the round 3 files byte for byte, so the delta is README, +`app.js` and `shell.test.mjs` and nothing else (`r3/out/r2-to-r3.diff`). + +Verdict: **approve**. Both of my round 2 items are fixed, and the tests +pin them. Every suite is green, all 14 new mutants die, and my probes on +the real control-board show nothing from before a refusal. I have three +notes, none blocking. The worst is a stale session picker that this row +didn't introduce. + +## Method + +- Detached worktrees at `ea080fd8`, `cand`, `mutwt` and `pwt`, each with + the 16 candidate files staged and checking 16 OK. `mutwt` still checks + 16 OK after the mutant runs (`r3/mut/manifest-after.txt`). +- `r3/gate.sh`: the `packages/webui` suite, `build-tokens.mjs --check`, + then every `scripts/test-*.sh` with `DOCKER_HOST=unix:///nonexistent.sock`, + 19:23:02Z to 19:26:06Z. +- 14 mutants aimed at the round 3 code (`r3/mut/mutate.py`, + `r3/mut/run.sh`), each against the full webui suite, 19:26:06Z to + 19:38:50Z. +- `test-release` with Docker, finished 19:39:38Z. +- Probes in Chromium through the candidate's `tests/browser.mjs` + (`r3/probes/probe3.test.mjs`, output `r3/probes/probes-cand.txt`). Test + one is round 2's fake board and bus set (P1 to P9). Test two runs the + real control-board from `tests/history-fixture.mjs` behind a proxy that + can answer 403, fail the catalogue with a 500, or hold history pages + (P10, P11, P13). Test three is a board whose first read is a 500 (P12). + No tracker request. +- Read the three changed files against my round 2 required list and + Filbert's C4 (comment 27163). + +Node v26.8.1, `TMPDIR=~/darkwing-scratch/r53c/tmp`. + +## Suites + +| Suite | Result | +|---|---| +| packages/webui (node) | 27/0 | +| build-tokens --check | rc 0, "tokens.css is current" | +| test-auth | 15/0 | +| test-conductor | 17/0 | +| test-config | 24/0 | +| test-discord | 66/0 | +| test-extension-package | 18/0 | +| test-foundation | 44/0 | +| test-queue | 27/0 | +| test-release | 4/0 without Docker, 14/0 with it | +| test-task, Docker unreachable | 26/0 | + +As before, I didn't run test-task with real Docker because it makes live +model calls. + +## Round 2 items + +| Item | Result | +|---|---| +| Required 1, P9 and Filbert's C4 | Fixed. With no scan held, `error()` empties `#sessions`, `#waiting` and `#seen`, puts "–" in the three counts, and says "the read failed" in the tree, the footer and `#status`. P9 (403 then 500) and P12 (first read 500) both show an empty board. The test runs a 403, then a 503, and asserts no rows, no cards, no History buttons and the dashes | +| Required 2, P10 | Fixed. A 403 with a conversation open empties `#conv-log` and calls `closeConversation()`. P10 on the real control-board: `#conversation` hidden, no `has-conversation`, `#conv-log` empty, the form hidden | +| README wording | Fixed. The refusal line now names the cards, the project filter, the empty board after a failed read and the closed conversation. Each claim matches what the probes show | +| M30 (counts kept on refusal) | Now tested. R09 below drops the dashes and dies on `#waiting-count` | + +Dewey's test doesn't run a 500, only a 503. Both go through the same +non-403 branch, and my P9 and P12 run the 500. That's enough. + +## Probes + +Fixtures as in round 2. P10, P11 and P13 use the control-board fixture's +session, whose history holds "Secret question from before the refusal" +and "Secret answer from before the refusal". + +| Probe | Candidate | +|---|---| +| P1 board 403 with the inspector open | `#board-view` `display:none`, inspector hidden | +| P2 board 403 | tree, footer, `#status` and `#fresh-board` say not read | +| P3, P4, P4b bus refusal | the palette and section list show the four views only | +| P6, P7 | `banner ref` then `banner err`, no task rows | +| P8 the toast before any copy | 1×1, empty, in the tree | +| **P9** good read, board 403, then a 500 | `#board-view` shown but empty, 0 rows, `#waiting` and `#sessions` empty, tree, footer, `#status` and `#fresh-board` say "the read failed". Was the refused rows. Fixed | +| P9b then a good read | 2 rows, footer "waiting 1 · working 1" | +| **P10** History open, then every board request 403 | `#conversation` hidden, `#conv-log` empty, form hidden, `#board-refused` shown. Was the full history on screen. Fixed | +| P11 refusal, recovery, History again with the catalogue failing | `#conv-pick` shown with the earlier conversation's title. See note 1 | +| P12 first read 500, no scan ever | empty board, "the read failed" everywhere, banner "No board data loaded" | +| P13 a 403 while a history page is in flight, then the page answers | `#conv-log` stays empty, `#conversation` stays hidden. The `convGen` bump in `closeConversation()` drops the late page | + +## Mutants + +14 of 14 killed (`r3/mut/summary.txt`). Every kill is an assertion or a +wait timeout in the shell browser test, not a load error. + +| Mutant | Change | Killed at | +|---|---|---| +| R01 | no close block on a refusal | `#conversation` hidden, line 200 | +| R02 | close without clearing `#conv-log` | `#conv-log` empty, line 202 | +| R03 | `showConversation(false)` instead of `closeConversation()` | the keyboard focus wait, line 215 | +| R04 | `if (!data)` becomes `if (refused)` | footer "the read failed", line 180 | +| R05 | no `replaceChildren()` loop | no rows or cards, line 178 | +| R06 | the loop skips `seen` | line 178 | +| R07 | the loop skips `waiting` | line 178 | +| R08 | the loop skips `sessions` | line 178 | +| R09 | no count dashes | `#waiting-count`, line 170 | +| R10 | footer always "refused" | line 180 | +| R11 | `why` always "refused" | `#status`, line 182 | +| R12 | no `inspect()` in the no-data block | inspector hidden, line 164 | +| R13 | a refusal keeps `project` | "All projects" pressed after recovery, line 187 | +| R14 | a refusal keeps `selected` | inspector hidden, line 164 | + +R03 passes the conversation assertions, because they check only that the +panel is hidden and the log empty. It dies at the keyboard step because +`conv` stays set. The next Enter on a row runs `closeConversation()` +first (line 347), which moves focus to the old History button before +`focusSnapshot()`. Escape then returns focus to History, not to the row. +A direct check that the conversation is closed would catch it sooner, but +the kill is real. + +## Notes (not blocking) + +1. **Stale session picker (P11), not from this row.** `openConversation()` + clears the title, the meta line and the log, but replaces the + `#conv-pick` options only after a good catalogue read. When the + catalogue fails, the picker keeps the previous conversation's titles, + shown under "History unavailable". That can be a conversation from + before a refusal or from another seat. Choosing one doesn't open the + wrong session: the next catalogue read doesn't find it under this row + and falls back. Base `03969219` has the same code. The fix is one line, + `$('conv-pick').replaceChildren()` next to the `conv-meta` clear. It + fits in row 54 or a later shell row. +2. **Focus after a refusal closes a conversation.** In `error()`, + `closeConversation()` runs before the no-data block. + `restore()` puts focus back on the History button, which is still in + the DOM at that point. The next lines empty `#sessions`, the button + goes, and focus falls to `` (P10 `active: "BODY"`). The + `$('main').focus()` fallback in `closeConversation()` has already run + by then. A keyboard user ends up at the top of the document after a + refusal. Repeating the fallback at the end of `error()` fixes it. +3. Round 2's note 2 (the hidden inspector keeps its text in the DOM) and + Filbert's N4 to N7 still stand. M07 stays accepted. Round 2's note 3, + the refresh timer race, is now in row 54 with Dewey's test, and I'll + check it there. + +## Files + +- `r3/candidate-manifest.sha256`: copy of Dewey's. +- `r3/gate.sh`, `r3/out/`: suite runs, `summary.txt`, + `test-release-docker.txt` and `r2-to-r3.diff`. +- `r3/mut/`: mutant definitions, runner, diffs, outputs, `summary.txt` and + the manifest check after the runs. +- `r3/probes/`: the probe test and its output.