review(53): Darkwing round 1, request changes (#1542 comment 27148)
Refusal leaves board data in the inspector, project tree, footer and scan line, and bus data in the Inbox count and the Ctrl+K palette. Gate green, 13 of 20 mutants killed, fonts match the upstream archive. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
d7b2b6958857eb97902c46480bf7e3786966cae9436e3763512da526fa256da3 packages/webui/README.md
|
||||
b9b162ebf6ff1c690d2731c4b63ebfb36d12d3176a0be8fdc1a449b706432fd8 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
|
||||
65d4ea9386aca7ed57107695e13cf91c29d15ba44d87cc085d2a05732201b03e packages/webui/src/public/bus.js
|
||||
01b456c1ca685e69e2974d66a615b7b8736abbd51aef7a3f014bca3783710430 packages/webui/src/public/icons.svg
|
||||
fbbb51e5669a1f559015e0fdebf6f450b63383070472d2461f0bce9b9723d890 packages/webui/src/public/index.html
|
||||
b3ae07918fced7b0323835bc35e73fffb3c3fb0921a36e22dd2eb167997c1e69 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
|
||||
f0ce4368cf0f0caab11aeb0f603c90d12066a40c33c51a20b53badd451d66cef packages/webui/tests/shell.test.mjs
|
||||
@@ -0,0 +1,9 @@
|
||||
# 2026-10-10T17:40:36Z font provenance check (Darkwing)
|
||||
archive sha256: 6f6376c6ed2960ea8a963cd7387ec9d76e3f629125bc33d1fdcd7eb7012f7bbf
|
||||
Archive sha256: 6f6376c6ed2960ea8a963cd7387ec9d76e3f629125bc33d1fdcd7eb7012f7bbf
|
||||
fonts/webfonts/JetBrainsMono-Regular.woff2 archive=a9cb1cd82332b23a47e3a1239d25d13c86d16c4220695e34b243effa999f45f2 shipped=a9cb1cd82332b23a47e3a1239d25d13c86d16c4220695e34b243effa999f45f2 match
|
||||
fonts/webfonts/JetBrainsMono-Medium.woff2 archive=086c48dfbea9ddaff1320f7e09399b8e2924e88ce67453721255db3bdbb5a353 shipped=086c48dfbea9ddaff1320f7e09399b8e2924e88ce67453721255db3bdbb5a353 match
|
||||
fonts/webfonts/JetBrainsMono-Bold.woff2 archive=c503cc5ec5f8b2c7666b7ecda1adf44bd45f2e6579b2eba0fc292150416588a2 shipped=c503cc5ec5f8b2c7666b7ecda1adf44bd45f2e6579b2eba0fc292150416588a2 match
|
||||
OFL.txt archive=30f0c136e3c88e422d0791acd97238870f9054a9729bc34cf2ff0d4ed8cac4ad shipped=30f0c136e3c88e422d0791acd97238870f9054a9729bc34cf2ff0d4ed8cac4ad match
|
||||
tokens.css equal to docs/design
|
||||
icons.svg equal to docs/design
|
||||
+18
@@ -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/r53a/tmp DOCKER_HOST=unix:///nonexistent.sock
|
||||
cd ~/darkwing-scratch/r53a/cand
|
||||
O=~/darkwing-scratch/r53a/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
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
|
||||
index f5389ee6..5ea891ad 100644
|
||||
--- a/packages/webui/src/public/bus.js
|
||||
+++ b/packages/webui/src/public/bus.js
|
||||
@@ -368,7 +368,7 @@
|
||||
}
|
||||
const failTitle = err => err.status === 403 ? 'Bus refused the read' : ['not-configured', 'no-bus-host'].includes(err.code) ? 'No bus to read' : 'The read failed';
|
||||
// A refusal fails closed: no kept data, the code in mono. Any other failure keeps the last read, labelled with its time.
|
||||
- const refusal = err => err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);
|
||||
+ const refusal = err => err.status === 403;
|
||||
const failedView = err => `${head(failTitle(err))}<div class="banner ${refusal(err) ? 'ref' : 'err'}" role="alert"><p>${refusal(err) ? `<b>refused: <code>${txt(err.code)}</code>.</b> ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.</p>${retry}</div>${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
|
||||
const staleBanner = err => `<div class="banner err s1-stale" role="alert"><p><b>The last read failed.</b> ${why(err)} This is what was read before, ${when(readAt)}. Nothing was changed.</p>${retry}</div>`;
|
||||
// Freshness line in the command bar for bus pages.
|
||||
@@ -0,0 +1,36 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (7051.173711ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (7270.330094ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8305.819932ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (465.310562ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (142.624471ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (60.934334ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2813.055778ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (488.166908ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (538.051321ms)
|
||||
✔ serve refuses a --business value that is not a business id (500.293546ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5952.997676ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3085.264687ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1717.994807ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1097.051106ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6156.19174ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56811.320882ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6077.150559ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (25388.059358ms)
|
||||
✔ loopback host and board origin fail closed (10.456016ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (214.245672ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (234.702735ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1644.897153ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (3.908141ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.212866ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (2.272588ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7192.367132ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3294.146704ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57463.713678
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
|
||||
index 1bd88cf2..c941e531 100644
|
||||
--- a/packages/webui/src/public/app.js
|
||||
+++ b/packages/webui/src/public/app.js
|
||||
@@ -303,7 +303,7 @@
|
||||
// A refusal (403) fails closed: the last data is hidden, not shown as current. Any other failure keeps the last data with its scan time.
|
||||
function error(err) {
|
||||
failed = true; $('error').hidden = false;
|
||||
- const refused = err.status === 403;
|
||||
+ const refused = false;
|
||||
$('error').className = refused ? 'banner ref' : 'banner err';
|
||||
$('board-refused').hidden = !refused; document.body.classList.toggle('board-refused', refused);
|
||||
$('error').innerHTML = refused
|
||||
@@ -0,0 +1,59 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5906.359439ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6421.571921ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7790.380244ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (319.811693ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (141.932338ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (135.266704ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2526.57828ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (389.079573ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (531.702165ms)
|
||||
✔ serve refuses a --business value that is not a business id (225.100624ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5885.859729ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2943.465302ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1599.972822ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1304.01305ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5738.474826ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56134.123141ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5780.259394ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24979.223692ms)
|
||||
✔ loopback host and board origin fail closed (11.709394ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (216.387749ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (108.234726ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1702.907874ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.588661ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.421399ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (2.1794ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4814.72897ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3632.166067ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 56812.431306
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4814.72897ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
+ 'banner err'
|
||||
- 'banner ref'
|
||||
^
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:140:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 'banner err',
|
||||
expected: 'banner ref',
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
|
||||
index 1bd88cf2..a5cf03b4 100644
|
||||
--- a/packages/webui/src/public/app.js
|
||||
+++ b/packages/webui/src/public/app.js
|
||||
@@ -305,7 +305,7 @@
|
||||
failed = true; $('error').hidden = false;
|
||||
const refused = err.status === 403;
|
||||
$('error').className = refused ? 'banner ref' : 'banner err';
|
||||
- $('board-refused').hidden = !refused; document.body.classList.toggle('board-refused', refused);
|
||||
+ $('board-refused').hidden = !refused;
|
||||
$('error').innerHTML = refused
|
||||
? `<p><b>The board refused the read.</b> refused: <code>${esc(err.message)}</code> Board: ${esc(board)}. Console shows nothing rather than a guess. Use Refresh to try again.</p>`
|
||||
: `<p><b>${esc(err.message)}</b> Board: ${esc(board)}. ${data ? `Showing last known data.${data.generatedAt ? ` Scanned ${esc(data.generatedAt)}.` : ''}` : 'No board data loaded.'} Use Refresh to try again.</p>`;
|
||||
@@ -0,0 +1,56 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5843.810902ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6581.265927ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8986.282108ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (1059.307807ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (207.046686ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (70.701032ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2229.666935ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (349.885509ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (528.250357ms)
|
||||
✔ serve refuses a --business value that is not a business id (216.252848ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (6331.227648ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3044.074164ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1387.057031ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1032.915675ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6249.684157ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56312.695193ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5805.305368ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23253.279537ms)
|
||||
✔ loopback host and board origin fail closed (9.249748ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (148.461303ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (182.583553ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1604.6308ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.446228ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.794556ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.912476ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6098.431393ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3104.411072ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 56801.360852
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6098.431393ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
|
||||
'block' !== 'none'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:142:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 'block',
|
||||
expected: 'none',
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
|
||||
index f5389ee6..5496a305 100644
|
||||
--- a/packages/webui/src/public/bus.js
|
||||
+++ b/packages/webui/src/public/bus.js
|
||||
@@ -369,7 +369,7 @@
|
||||
const failTitle = err => err.status === 403 ? 'Bus refused the read' : ['not-configured', 'no-bus-host'].includes(err.code) ? 'No bus to read' : 'The read failed';
|
||||
// A refusal fails closed: no kept data, the code in mono. Any other failure keeps the last read, labelled with its time.
|
||||
const refusal = err => err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);
|
||||
- const failedView = err => `${head(failTitle(err))}<div class="banner ${refusal(err) ? 'ref' : 'err'}" role="alert"><p>${refusal(err) ? `<b>refused: <code>${txt(err.code)}</code>.</b> ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.</p>${retry}</div>${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
|
||||
+ const failedView = err => `${head(failTitle(err))}<div class="banner ${refusal(err) ? 'ref' : 'err'}" role="alert"><p>${refusal(err) ? `<b>refused: ${txt(err.code)}.</b> ` : ''}${why(err)} Console shows nothing rather than a guess. Nothing was written.</p>${retry}</div>${empty('Nothing to show.', refusal(err) ? 'The view stays empty until the problem above is fixed.' : 'Read again, or come back when the bus answers.')}`;
|
||||
const staleBanner = err => `<div class="banner err s1-stale" role="alert"><p><b>The last read failed.</b> ${why(err)} This is what was read before, ${when(readAt)}. Nothing was changed.</p>${retry}</div>`;
|
||||
// Freshness line in the command bar for bus pages.
|
||||
const stamp = iso => { const t = Date.parse(iso); return Number.isFinite(t) ? `${new Date(t).toISOString().slice(11, 19)} UTC` : 'unknown'; };
|
||||
@@ -0,0 +1,36 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5248.350804ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6871.236761ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (9267.987367ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (970.658233ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (316.969409ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (258.400443ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2432.255818ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (184.834293ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (528.843918ms)
|
||||
✔ serve refuses a --business value that is not a business id (199.945476ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5325.287046ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3880.82363ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1896.347832ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1341.397952ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (7915.59178ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (57016.635343ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6078.323228ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23058.579464ms)
|
||||
✔ loopback host and board origin fail closed (13.230744ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (310.414402ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (150.209364ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1760.353157ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.913986ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.340836ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (2.36321ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7850.747047ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2933.64496ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57785.087003
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
|
||||
index f5389ee6..60995f29 100644
|
||||
--- a/packages/webui/src/public/bus.js
|
||||
+++ b/packages/webui/src/public/bus.js
|
||||
@@ -375,7 +375,7 @@
|
||||
const stamp = iso => { const t = Date.parse(iso); return Number.isFinite(t) ? `${new Date(t).toISOString().slice(11, 19)} UTC` : 'unknown'; };
|
||||
function freshBus(state) {
|
||||
$('fresh-bus').innerHTML = state === 'failed' ? 'Bus <span class="warn">not read: the read failed</span>'
|
||||
- : `Bus read <b>${esc(stamp(readAt))}</b>${readAt ? ` (${esc(ago(readAt))})` : ''}${state === 'stale' ? ' · <span class="warn">stale: the last read failed</span>' : ''}`;
|
||||
+ : `Bus read <b>${esc(stamp(readAt))}</b>${readAt ? ` (${esc(ago(readAt))})` : ''}`;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- router
|
||||
@@ -0,0 +1,71 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5791.84315ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5931.424696ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8208.335483ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (288.745639ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (95.589345ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (43.548131ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (3157.970328ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (182.605399ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (528.453388ms)
|
||||
✔ serve refuses a --business value that is not a business id (173.453275ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5913.007381ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2826.523101ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1818.54918ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1217.464307ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5971.136144ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55587.199523ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5785.97143ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22792.773591ms)
|
||||
✔ loopback host and board origin fail closed (7.422204ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (114.173784ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (46.336575ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (921.432069ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (8.890882ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.17736ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.56056ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5850.038936ms)
|
||||
✖ five states on Board, Inbox, Tasks, Agents and Trail (2552.965234ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 25
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 55919.285318
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5850.038936ms)
|
||||
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /stale: the last read failed/. Input:
|
||||
|
||||
'Bus read 17:41:19 UTC (0 s ago)'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/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: 'Bus read 17:41:19 UTC (0 s ago)',
|
||||
expected: /stale: the last read failed/,
|
||||
operator: 'match',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at tests/shell.test.mjs:278:1
|
||||
✖ five states on Board, Inbox, Tasks, Agents and Trail (2552.965234ms)
|
||||
AssertionError [ERR_ASSERTION]: #/inbox
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:333:14)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 'Bus read 17:41:23 UTC (0 s ago)',
|
||||
expected: /stale: the last read failed/,
|
||||
operator: 'match',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
|
||||
index 1bd88cf2..78a1bf8d 100644
|
||||
--- a/packages/webui/src/public/app.js
|
||||
+++ b/packages/webui/src/public/app.js
|
||||
@@ -41,7 +41,7 @@
|
||||
palette = p.id;
|
||||
if (!['system', 'light', 'dim', 'dark'].includes(mode)) mode = 'system';
|
||||
document.documentElement.dataset.palette = palette;
|
||||
- if (mode === 'system') delete document.documentElement.dataset.mode; else document.documentElement.dataset.mode = mode;
|
||||
+ document.documentElement.dataset.mode = mode;
|
||||
$('palette').value = palette; $('mode').value = mode;
|
||||
try { localStorage.setItem('mosaic-console-appearance', JSON.stringify({ palette, mode })); } catch {}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5268.206473ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5667.727448ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6423.223294ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (397.075731ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (126.647007ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (50.303543ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2065.282756ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (206.772468ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (536.593624ms)
|
||||
✔ serve refuses a --business value that is not a business id (216.440541ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5279.816257ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2768.013147ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1710.014915ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (955.788723ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5054.287458ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54831.221513ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4747.666103ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23326.297774ms)
|
||||
✔ loopback host and board origin fail closed (9.530125ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (132.775432ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (129.121734ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (813.942492ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.744558ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.122253ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.750309ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5320.290317ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2836.644907ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 55294.850895
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5320.290317ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
|
||||
true !== false
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:104:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: true,
|
||||
expected: false,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
|
||||
index f5389ee6..e7305cbf 100644
|
||||
--- a/packages/webui/src/public/bus.js
|
||||
+++ b/packages/webui/src/public/bus.js
|
||||
@@ -477,7 +477,7 @@
|
||||
const t = $('toast'); clearTimeout(toastTimer);
|
||||
if (text === null) { t.className = 'toast'; t.textContent = ''; return; }
|
||||
t.className = `toast on${error ? ' err' : ''}`;
|
||||
- t.innerHTML = `<span>${esc(text)}</span>${error ? '<button type="button" data-dismiss>Dismiss</button>' : ''}`;
|
||||
+ t.innerHTML = `<span>${text}</span>${error ? '<button type="button" data-dismiss>Dismiss</button>' : ''}`;
|
||||
if (!error) toastTimer = setTimeout(() => toast(null), 2600);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3498.424498ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5073.27053ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5860.251528ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (316.037593ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (106.598219ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (85.782079ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2200.847869ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (239.201748ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (533.279441ms)
|
||||
✔ serve refuses a --business value that is not a business id (256.027601ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3551.87569ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2463.641056ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1169.125934ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (841.998568ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (3608.632384ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54356.685952ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3674.33323ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22885.872246ms)
|
||||
✔ loopback host and board origin fail closed (9.397593ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (128.255402ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (105.743453ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1209.792727ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.322274ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.723359ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.811832ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4370.26785ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2285.134171ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 54819.589769
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
|
||||
index f5389ee6..8911ba97 100644
|
||||
--- a/packages/webui/src/public/bus.js
|
||||
+++ b/packages/webui/src/public/bus.js
|
||||
@@ -496,7 +496,7 @@
|
||||
const q = $('cmdk-input').value.trim().toLowerCase();
|
||||
pkShown = pkAll.filter(i => !q || `${i.label} ${i.group}`.toLowerCase().includes(q)).slice(0, 50);
|
||||
pkAt = Math.min(pkAt, Math.max(0, pkShown.length - 1));
|
||||
- $('cmdk-list').innerHTML = pkShown.length ? pkShown.map((i, n) => `<li role="option" id="cmdk-opt-${n}" data-href="${esc(i.href)}" aria-selected="${n === pkAt}"><span>${txt(i.label)}</span><span class="g">${txt(i.group)}</span></li>`).join('')
|
||||
+ $('cmdk-list').innerHTML = pkShown.length ? pkShown.map((i, n) => `<li role="option" id="cmdk-opt-${n}" data-href="${esc(i.href)}" aria-selected="${n === pkAt}"><span>${i.label}</span><span class="g">${txt(i.group)}</span></li>`).join('')
|
||||
: '<li class="pk-none" role="option" aria-disabled="true" aria-selected="false">No view, decision or task matches.</li>';
|
||||
if (pkShown.length) { $('cmdk-input').setAttribute('aria-activedescendant', `cmdk-opt-${pkAt}`); $(`cmdk-opt-${pkAt}`)?.scrollIntoView({ block: 'nearest' }); }
|
||||
else $('cmdk-input').removeAttribute('aria-activedescendant');
|
||||
@@ -0,0 +1,36 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5754.334404ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6557.501052ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8416.074858ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (574.930974ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (797.089799ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (302.286778ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (1995.597872ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (228.695172ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (528.891783ms)
|
||||
✔ serve refuses a --business value that is not a business id (167.030411ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5671.033678ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3129.076355ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1801.429431ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (899.175464ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6209.788072ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55273.916567ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6379.070681ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24135.002505ms)
|
||||
✔ loopback host and board origin fail closed (9.440587ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (152.276494ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (124.824653ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1771.062865ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.492243ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.818143ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.856825ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6039.027572ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3366.746341ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 55726.493145
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
|
||||
index ae98ebd5..1d0049e5 100644
|
||||
--- a/packages/webui/src/public/shell.css
|
||||
+++ b/packages/webui/src/public/shell.css
|
||||
@@ -18,7 +18,7 @@ body{font:400 14px/1.5 var(--font);color:var(--text);background:var(--canvas)}
|
||||
code,kbd,pre,.mono{font-family:var(--mono);font-size:12.5px}
|
||||
kbd{border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;padding:0 .35em;background:var(--surface);color:var(--strong);white-space:nowrap;font-size:11.5px}
|
||||
.count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}
|
||||
-:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
|
||||
+:focus-visible{outline:2px solid var(--focus);outline-offset:0}
|
||||
table.sessions tbody tr:focus-visible,table.s1-table tbody tr:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
|
||||
svg.i{width:18px;height:18px;flex:none;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4400.430089ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4300.640965ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (5301.127984ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (276.547118ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (103.39068ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (65.485599ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2151.965579ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (163.976348ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (528.285651ms)
|
||||
✔ serve refuses a --business value that is not a business id (172.181607ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4371.961867ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2840.647816ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1998.086292ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1131.857592ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4574.654406ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53632.384811ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4727.108522ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22586.932856ms)
|
||||
✔ loopback host and board origin fail closed (7.712823ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (138.907671ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (128.085616ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1065.673871ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.242354ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.442883ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.419635ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4421.026726ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2740.769195ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 54058.53995
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
|
||||
index ae98ebd5..a410b866 100644
|
||||
--- a/packages/webui/src/public/shell.css
|
||||
+++ b/packages/webui/src/public/shell.css
|
||||
@@ -18,7 +18,7 @@ body{font:400 14px/1.5 var(--font);color:var(--text);background:var(--canvas)}
|
||||
code,kbd,pre,.mono{font-family:var(--mono);font-size:12.5px}
|
||||
kbd{border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;padding:0 .35em;background:var(--surface);color:var(--strong);white-space:nowrap;font-size:11.5px}
|
||||
.count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}
|
||||
-:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
|
||||
+:focus-visible{outline:1px solid var(--focus);outline-offset:2px}
|
||||
table.sessions tbody tr:focus-visible,table.s1-table tbody tr:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
|
||||
svg.i{width:18px;height:18px;flex:none;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3859.095965ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4343.268551ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6605.907754ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (526.606027ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (153.465165ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (55.167495ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2288.47965ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (261.219118ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (531.076935ms)
|
||||
✔ serve refuses a --business value that is not a business id (384.431269ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3856.193842ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3060.373427ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1167.486824ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (944.374404ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (3875.563993ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56587.254808ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3876.724799ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23324.969843ms)
|
||||
✔ loopback host and board origin fail closed (8.786574ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (146.934201ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (134.739961ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1346.776736ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (0.958173ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.776603ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.395916ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (3843.314767ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2988.092ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57019.428623
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (3843.314767ms)
|
||||
AssertionError [ERR_ASSERTION]: #cmdk outline 1px
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:163:69)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: false,
|
||||
expected: true,
|
||||
operator: '==',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
|
||||
index ae98ebd5..473b94fe 100644
|
||||
--- a/packages/webui/src/public/shell.css
|
||||
+++ b/packages/webui/src/public/shell.css
|
||||
@@ -165,7 +165,7 @@ body.on-bus #board-refused{display:none}
|
||||
.cmd-right label{flex:1 1 0;min-width:0}
|
||||
.cmd-right .btn{flex:none}
|
||||
/* The section list wraps rather than scrolling, so a blocking count never hides a section. */
|
||||
- .s1-sections{display:flex;flex-wrap:wrap;overflow-x:visible;flex-basis:100%;gap:2px;padding-bottom:2px}
|
||||
+ .s1-sections{display:flex;flex-basis:100%;gap:2px;padding-bottom:2px}
|
||||
.s1-section{border-radius:var(--r);padding:5px 8px;white-space:nowrap;flex:none}
|
||||
.inspector{inset:0;top:0;width:100%;z-index:40;box-shadow:none}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (7740.004399ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (15045.20497ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (15277.238224ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (1915.102997ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (37.390122ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (16.731727ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (1654.594624ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (229.623851ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (528.322018ms)
|
||||
✔ serve refuses a --business value that is not a business id (173.324632ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (11063.547959ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4337.313117ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1973.678474ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1440.938589ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (8131.126692ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (51061.883178ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (7907.667489ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (28815.695414ms)
|
||||
✔ loopback host and board origin fail closed (8.80561ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (302.179616ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (203.376087ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (867.064023ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (0.895645ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.910895ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.387285ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (8972.170949ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (6074.516516ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 51415.549688
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
|
||||
index f5389ee6..7dc2fb2c 100644
|
||||
--- a/packages/webui/src/public/bus.js
|
||||
+++ b/packages/webui/src/public/bus.js
|
||||
@@ -209,7 +209,7 @@
|
||||
const items = [['/', 'Board', '', 'board'], ['/inbox', 'Inbox', inboxCount ? `<span class="count" aria-label="${inboxCount.open} open for you">${inboxCount.open}</span>${inboxCount.blocking ? ` ${blockChip(`${inboxCount.blocking} blocking`)}` : ''}` : '', 'inbox'], ['/tasks', 'Tasks', '', 'tasks'], ['/agents', 'Agents', '', 'agents']];
|
||||
$('sections').innerHTML = items.map(([h, l, extra, icon]) => {
|
||||
const cur = h === '/' ? route === '/' : route.startsWith(h) || (h === '/tasks' && route.startsWith('/trail/task')) || (h === '/inbox' && route.startsWith('/trail/decision'));
|
||||
- return `<li><a href="#${h}" class="s1-section"${cur ? ' aria-current="page"' : ''}><svg class="i" aria-hidden="true"><use href="/icons.svg#i-${icon}"/></svg>${l}${extra ? ` ${extra}` : ''}</a></li>`;
|
||||
+ return `<li><a href="#${h}" class="s1-section"${cur ? ' aria-current="page"' : ''}>${l}${extra ? ` ${extra}` : ''}</a></li>`;
|
||||
}).join('');
|
||||
}
|
||||
function countInbox(rows) { inboxCount = { open: rows.length, blocking: rows.filter(d => d.blocking).length }; }
|
||||
@@ -0,0 +1,56 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (9498.845618ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (14178.704126ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (14655.718816ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (1567.119707ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (44.104039ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (20.542495ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (1704.198859ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (193.649625ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (529.634379ms)
|
||||
✔ serve refuses a --business value that is not a business id (195.352905ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (13040.964383ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3460.713697ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1590.068006ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1041.528275ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (7155.666046ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (61163.295912ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (8768.9756ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (30593.233514ms)
|
||||
✔ loopback host and board origin fail closed (10.042054ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (317.593824ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (158.705182ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1128.252253ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (0.836867ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (1.649855ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.204314ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7835.16493ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (5311.153032ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 61560.528856
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7835.16493ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
|
||||
0 !== 4
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:174:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 0,
|
||||
expected: 4,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
|
||||
index 1bd88cf2..05a6089e 100644
|
||||
--- a/packages/webui/src/public/app.js
|
||||
+++ b/packages/webui/src/public/app.js
|
||||
@@ -296,7 +296,6 @@
|
||||
function accept(value) {
|
||||
if (!value || !Array.isArray(value.sessions) || value.sessions.some(r => !r || typeof r.project !== 'string' || typeof r.agent !== 'string')) throw new Error('Invalid board session data');
|
||||
data = value; failed = false; $('error').hidden = true; $('error').className = 'banner err';
|
||||
- $('board-refused').hidden = true; document.body.classList.remove('board-refused');
|
||||
for (const id of awaiting.keys()) { const r = row(id); if (r && !pending(r)) awaiting.delete(id); }
|
||||
render();
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (7188.855809ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (7271.704177ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8077.985604ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (532.536088ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (239.548482ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (25.479189ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2707.003302ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (368.432283ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (532.75841ms)
|
||||
✔ serve refuses a --business value that is not a business id (253.697624ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (7156.651219ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2332.626421ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1564.440958ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1088.29525ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (7330.458092ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (57918.906247ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (7193.459074ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24552.102054ms)
|
||||
✔ loopback host and board origin fail closed (9.968967ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (200.59317ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (312.379414ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1496.667453ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.404264ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.784097ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.975862ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7313.200709ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2852.110982ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 58512.874055
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7313.200709ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to:
|
||||
|
||||
'none'
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:147:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 'none',
|
||||
expected: 'none',
|
||||
operator: 'notStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
|
||||
index f5389ee6..24750eb1 100644
|
||||
--- a/packages/webui/src/public/bus.js
|
||||
+++ b/packages/webui/src/public/bus.js
|
||||
@@ -525,7 +525,7 @@
|
||||
const a = e.target.closest?.('#bus-view table.s1-table td.s1-title a');
|
||||
if (!a || (e.key !== 'ArrowDown' && e.key !== 'ArrowUp')) return;
|
||||
const links = [...a.closest('table').querySelectorAll('td.s1-title a')], i = links.indexOf(a);
|
||||
- e.preventDefault(); links[i + (e.key === 'ArrowDown' ? 1 : -1)]?.focus();
|
||||
+ e.preventDefault(); links[i + (e.key === 'ArrowDown' ? -1 : 1)]?.focus();
|
||||
});
|
||||
window.addEventListener('hashchange', () => render(true));
|
||||
$('refresh').addEventListener('click', () => render(false));
|
||||
@@ -0,0 +1,56 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (7435.806805ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (7593.581724ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7674.576199ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (288.355604ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (177.319585ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (56.443497ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2392.104767ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (283.865828ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (530.708861ms)
|
||||
✔ serve refuses a --business value that is not a business id (293.569333ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (7220.28677ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2322.290614ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1306.780472ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (977.03291ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (7074.876596ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56183.087593ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6068.013766ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (25233.057689ms)
|
||||
✔ loopback host and board origin fail closed (9.354686ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (147.853081ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (132.817076ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1234.273937ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.454396ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.999574ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.794182ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7048.453702ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2437.068864ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 56798.36445
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7048.453702ms)
|
||||
AssertionError [ERR_ASSERTION]: The input did not match the regular expression /Second task/. Input:
|
||||
|
||||
'#7 Kept task'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:190:38)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: '#7 Kept task',
|
||||
expected: /Second task/,
|
||||
operator: 'match',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/serve.mjs b/packages/webui/src/serve.mjs
|
||||
index 280a228f..93a1958f 100644
|
||||
--- a/packages/webui/src/serve.mjs
|
||||
+++ b/packages/webui/src/serve.mjs
|
||||
@@ -22,7 +22,7 @@ const files = new Map([
|
||||
['/', ['index.html', 'text/html; charset=utf-8']],
|
||||
...['app.js', 'brand.js', 'bus.js'].map(f => ['/' + f, [f, 'text/javascript; charset=utf-8']]),
|
||||
...['shared/app.css', 'tokens.css', 'console.css', 'live.css', 'bus.css', 'shell.css'].map(f => ['/' + f, [f, 'text/css; charset=utf-8']]),
|
||||
- ['/icons.svg', ['icons.svg', 'image/svg+xml']],
|
||||
+ ['/icons.svg', ['icons.svg', 'text/plain']],
|
||||
...[400, 500, 600, 700].map(w => [`/assets/fonts/manrope-${w}.woff2`, [`assets/fonts/manrope-${w}.woff2`, 'font/woff2']]),
|
||||
...[400, 500, 700].map(w => [`/assets/fonts/jetbrains-mono-${w}.woff2`, [`assets/fonts/jetbrains-mono-${w}.woff2`, 'font/woff2']]),
|
||||
]);
|
||||
@@ -0,0 +1,53 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5198.663054ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5584.343092ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7086.448634ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (267.907334ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (134.094408ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (114.691386ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2562.538599ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (332.854133ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (537.451045ms)
|
||||
✔ serve refuses a --business value that is not a business id (322.845795ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5397.416668ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2651.201165ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1371.821427ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1038.855758ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5467.101437ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54944.465486ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5191.271543ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (24030.373521ms)
|
||||
✔ loopback host and board origin fail closed (11.434928ms)
|
||||
✖ real board fixture passes through WebUI; assets and isolated seen/reply work (119.713354ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (86.02832ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1407.454964ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.624361ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.168129ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.840078ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5147.231405ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2781.962804ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 55451.838299
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/serve.test.mjs:22:1
|
||||
✖ real board fixture passes through WebUI; assets and isolated seen/reply work (119.713354ms)
|
||||
AssertionError [ERR_ASSERTION]: /icons.svg
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/serve.test.mjs:41:101)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: false,
|
||||
expected: true,
|
||||
operator: '==',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
|
||||
index ae98ebd5..ef259cfa 100644
|
||||
--- a/packages/webui/src/public/shell.css
|
||||
+++ b/packages/webui/src/public/shell.css
|
||||
@@ -17,7 +17,7 @@ body{font:400 14px/1.5 var(--font);color:var(--text);background:var(--canvas)}
|
||||
.tree-title,.label{font:700 11px/1.3 var(--font);letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
|
||||
code,kbd,pre,.mono{font-family:var(--mono);font-size:12.5px}
|
||||
kbd{border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;padding:0 .35em;background:var(--surface);color:var(--strong);white-space:nowrap;font-size:11.5px}
|
||||
-.count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}
|
||||
+
|
||||
:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
|
||||
table.sessions tbody tr:focus-visible,table.s1-table tbody tr:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
|
||||
svg.i{width:18px;height:18px;flex:none;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
|
||||
@@ -0,0 +1,36 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5815.739101ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6306.605756ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6556.920755ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (230.898299ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (124.363066ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (99.788074ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2290.268607ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (512.295669ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (532.334409ms)
|
||||
✔ serve refuses a --business value that is not a business id (378.3221ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5862.379595ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2207.341974ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1319.855887ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (945.392215ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5845.529279ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55253.928142ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5750.276641ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23895.725251ms)
|
||||
✔ loopback host and board origin fail closed (11.74274ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (138.324612ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (125.990286ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1148.873598ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.610914ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.83ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (2.108441ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (6080.959306ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2551.546835ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 55753.3057
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
|
||||
index 1bd88cf2..889f9b50 100644
|
||||
--- a/packages/webui/src/public/app.js
|
||||
+++ b/packages/webui/src/public/app.js
|
||||
@@ -43,7 +43,7 @@
|
||||
document.documentElement.dataset.palette = palette;
|
||||
if (mode === 'system') delete document.documentElement.dataset.mode; else document.documentElement.dataset.mode = mode;
|
||||
$('palette').value = palette; $('mode').value = mode;
|
||||
- try { localStorage.setItem('mosaic-console-appearance', JSON.stringify({ palette, mode })); } catch {}
|
||||
+ try { localStorage.setItem('mosaic-console-look', JSON.stringify({ palette, mode })); } catch {}
|
||||
}
|
||||
$('palette').innerHTML = Brand.palettes.map(p => `<option value="${p.id}">${p.name}</option>`).join('');
|
||||
try { const saved = JSON.parse(localStorage.getItem('mosaic-console-appearance')); if (saved) { palette = saved.palette; mode = saved.mode; } } catch {}
|
||||
@@ -0,0 +1,48 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (6509.180091ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (6694.384219ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (8448.50645ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (283.095687ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (94.261689ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (171.22577ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (3166.486182ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (634.294634ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (546.416392ms)
|
||||
✔ serve refuses a --business value that is not a business id (277.920278ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5843.479393ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2979.713955ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1525.00909ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1119.901705ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5907.046805ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56798.491522ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5982.963587ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23060.663865ms)
|
||||
✔ loopback host and board origin fail closed (9.911459ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (151.827716ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (120.177257ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1888.294464ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.461055ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.105203ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.844539ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5599.305116ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3190.605625ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57257.534522
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (5599.305116ms)
|
||||
Error: Uncaught: TypeError: Cannot read properties of null (reading 'mode')
|
||||
at <anonymous>:1:62
|
||||
at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/browser.mjs:44:35)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:117:18)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/shell.css b/packages/webui/src/public/shell.css
|
||||
index ae98ebd5..618e1126 100644
|
||||
--- a/packages/webui/src/public/shell.css
|
||||
+++ b/packages/webui/src/public/shell.css
|
||||
@@ -97,7 +97,7 @@ table.s1-table td code{font-size:12.5px;white-space:nowrap}
|
||||
.skel{display:block;height:12px;border-radius:4px;background:var(--raised);animation:skel 1.4s ease-in-out infinite}
|
||||
.skel:nth-child(odd){width:82%}
|
||||
@keyframes skel{50%{opacity:.45}}
|
||||
-body.board-refused #board-view{display:none}
|
||||
+
|
||||
body.on-bus #board-refused{display:none}
|
||||
|
||||
/* Toast: one line, polite, bottom centre. */
|
||||
@@ -0,0 +1,56 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4795.15073ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5559.593964ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7776.997828ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (1077.378774ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (172.941475ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (171.347229ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2180.586418ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (290.631709ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (528.862733ms)
|
||||
✔ serve refuses a --business value that is not a business id (172.199777ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5528.326861ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3194.267668ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1843.504674ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1433.153552ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6538.626521ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55681.83814ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6466.894866ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22981.556096ms)
|
||||
✔ loopback host and board origin fail closed (10.31224ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (151.493703ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (131.02258ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1643.650438ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.118919ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.164409ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.524389ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4961.827843ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3334.087324ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 56099.695862
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4961.827843ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
|
||||
'block' !== 'none'
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:142:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 'block',
|
||||
expected: 'none',
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/bus.js b/packages/webui/src/public/bus.js
|
||||
index f5389ee6..c40651fd 100644
|
||||
--- a/packages/webui/src/public/bus.js
|
||||
+++ b/packages/webui/src/public/bus.js
|
||||
@@ -430,7 +430,7 @@
|
||||
try { html = await view(live, path, new URLSearchParams(query)); readAt = live.oldest(); }
|
||||
catch (err) {
|
||||
const kept = reader(false);
|
||||
- try { if (refusal(err)) throw err; html = await view(kept, path, new URLSearchParams(query)); readAt = kept.oldest(); html = staleBanner(err) + html; state = 'stale'; }
|
||||
+ try { html = await view(kept, path, new URLSearchParams(query)); readAt = kept.oldest(); html = staleBanner(err) + html; state = 'stale'; }
|
||||
catch { html = failedView(err); state = 'failed'; }
|
||||
}
|
||||
if (g !== gen) return;
|
||||
@@ -0,0 +1,56 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5189.150978ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4797.468611ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7333.317174ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (293.313629ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (270.398019ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (46.997252ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2498.469401ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (561.937736ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (529.448403ms)
|
||||
✔ serve refuses a --business value that is not a business id (158.123778ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (5165.831607ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2318.690956ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1214.295855ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (858.950234ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5772.38394ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56013.500976ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (5767.671969ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22044.47108ms)
|
||||
✔ loopback host and board origin fail closed (8.098491ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (116.266396ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (149.164044ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1526.468607ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.016667ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.453188ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.576672ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (10536.386855ms)
|
||||
✖ five states on Board, Inbox, Tasks, Agents and Trail (6210.0518ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 25
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 56442.086324
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (10536.386855ms)
|
||||
Error: Uncaught (in promise) Error: Condition timed out: !!document.querySelector("#bus-view .banner.ref"): undefined
|
||||
at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/browser.mjs:44:35)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:196:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
|
||||
|
||||
test at tests/shell.test.mjs:278:1
|
||||
✖ five states on Board, Inbox, Tasks, Agents and Trail (6210.0518ms)
|
||||
Error: Uncaught (in promise) Error: Condition timed out: !!document.querySelector("#bus-view .banner.ref"): undefined
|
||||
at Object.evaluate (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/browser.mjs:44:35)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:337:7)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/packages/webui/src/public/app.js b/packages/webui/src/public/app.js
|
||||
index 1bd88cf2..560b6b11 100644
|
||||
--- a/packages/webui/src/public/app.js
|
||||
+++ b/packages/webui/src/public/app.js
|
||||
@@ -304,7 +304,7 @@
|
||||
function error(err) {
|
||||
failed = true; $('error').hidden = false;
|
||||
const refused = err.status === 403;
|
||||
- $('error').className = refused ? 'banner ref' : 'banner err';
|
||||
+ $('error').className = 'banner err';
|
||||
$('board-refused').hidden = !refused; document.body.classList.toggle('board-refused', refused);
|
||||
$('error').innerHTML = refused
|
||||
? `<p><b>The board refused the read.</b> refused: <code>${esc(err.message)}</code> Board: ${esc(board)}. Console shows nothing rather than a guess. Use Refresh to try again.</p>`
|
||||
@@ -0,0 +1,59 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4106.705441ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4897.321923ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7067.560106ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (240.258586ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (133.598704ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (67.321441ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (3115.331024ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (181.812826ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (527.655765ms)
|
||||
✔ serve refuses a --business value that is not a business id (166.522998ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4231.728036ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2973.78925ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1229.737715ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (730.936985ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4274.78806ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55233.84178ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4670.272359ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (22574.934461ms)
|
||||
✔ loopback host and board origin fail closed (7.615952ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (131.841633ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (99.940777ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1879.694356ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.434754ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.048983ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (1.308296ms)
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4582.403832ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3147.731873ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 26
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 55736.314772
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/shell.test.mjs:84:1
|
||||
✖ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4582.403832ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
+ 'banner err'
|
||||
- 'banner ref'
|
||||
^
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/darkwing-scratch/r53a/mutwt/packages/webui/tests/shell.test.mjs:140:12)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 'banner err',
|
||||
expected: 'banner ref',
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,31 @@
|
||||
# mutate.py <id>: apply one named mutant to the candidate (exact text, must match once). Run from the tree root.
|
||||
import sys
|
||||
B, A, C, S, H = "packages/webui/src/public/bus.js", "packages/webui/src/public/app.js", "packages/webui/src/public/shell.css", "packages/webui/src/serve.mjs", "packages/webui/src/public/index.html"
|
||||
M = {
|
||||
"M01": [(B, "err.status === 403 || ['not-configured', 'no-bus-host'].includes(err.code);", "err.status === 403;")],
|
||||
"M02": [(A, "const refused = err.status === 403;", "const refused = false;")],
|
||||
"M03": [(A, "document.body.classList.toggle('board-refused', refused);", "")],
|
||||
"M04": [(B, "<b>refused: <code>${txt(err.code)}</code>.</b> ", "<b>refused: ${txt(err.code)}.</b> ")],
|
||||
"M05": [(B, "${state === 'stale' ? ' · <span class=\"warn\">stale: the last read failed</span>' : ''}", "")],
|
||||
"M06": [(A, "if (mode === 'system') delete document.documentElement.dataset.mode; else document.documentElement.dataset.mode = mode;", "document.documentElement.dataset.mode = mode;")],
|
||||
"M07": [(B, "t.innerHTML = `<span>${esc(text)}</span>", "t.innerHTML = `<span>${text}</span>")],
|
||||
"M08": [(B, "<span>${txt(i.label)}</span><span class=\"g\">", "<span>${i.label}</span><span class=\"g\">")],
|
||||
"M09": [(C, ":focus-visible{outline:2px solid var(--focus);outline-offset:2px}", ":focus-visible{outline:2px solid var(--focus);outline-offset:0}")],
|
||||
"M10": [(C, ":focus-visible{outline:2px solid var(--focus);outline-offset:2px}", ":focus-visible{outline:1px solid var(--focus);outline-offset:2px}")],
|
||||
"M11": [(C, " .s1-sections{display:flex;flex-wrap:wrap;overflow-x:visible;flex-basis:100%;gap:2px;padding-bottom:2px}", " .s1-sections{display:flex;flex-basis:100%;gap:2px;padding-bottom:2px}")],
|
||||
"M12": [(B, "<svg class=\"i\" aria-hidden=\"true\"><use href=\"/icons.svg#i-${icon}\"/></svg>", "")],
|
||||
"M13": [(A, " $('board-refused').hidden = true; document.body.classList.remove('board-refused');\n", "")],
|
||||
"M14": [(B, "links[i + (e.key === 'ArrowDown' ? 1 : -1)]?.focus();", "links[i + (e.key === 'ArrowDown' ? -1 : 1)]?.focus();")],
|
||||
"M15": [(S, "['/icons.svg', ['icons.svg', 'image/svg+xml']],", "['/icons.svg', ['icons.svg', 'text/plain']],")],
|
||||
"M16": [(C, ".count,td,.s1-twhen,time,.fresh,.kv dd{font-variant-numeric:tabular-nums}", "")],
|
||||
"M17": [(A, "try { localStorage.setItem('mosaic-console-appearance',", "try { localStorage.setItem('mosaic-console-look',")],
|
||||
"M18": [(C, "body.board-refused #board-view{display:none}", "")],
|
||||
"M19": [(B, "if (refusal(err)) throw err; html = await view(kept,", "html = await view(kept,")],
|
||||
"M20": [(A, "$('error').className = refused ? 'banner ref' : 'banner err';", "$('error').className = 'banner err';")],
|
||||
}
|
||||
for f, old, new in M[sys.argv[1]]:
|
||||
s = open(f).read()
|
||||
n = s.count(old)
|
||||
if n != 1: sys.exit(f"{sys.argv[1]}: {n} matches in {f}")
|
||||
open(f, "w").write(s.replace(old, new))
|
||||
print(sys.argv[1], "applied")
|
||||
+15
@@ -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/r53a/tmp
|
||||
S=~/darkwing-scratch/r53a; M=$S/mut; W=$S/mutwt
|
||||
: > $M/summary.txt
|
||||
echo "start $(date -u +%FT%TZ)" >> $M/summary.txt
|
||||
for v in $(python3 -c 'import re;print(" ".join(sorted(set(re.findall(r"\"(M\d\d)\"", open("'$M'/mutate.py").read())))))'); do
|
||||
(cd $W && git checkout -q -- packages/webui && python3 $M/mutate.py $v > /dev/null && git diff > $M/$v.diff) || { echo "$v APPLY-FAILED" >> $M/summary.txt; continue; }
|
||||
(cd $W/packages/webui && env -u NODE_TEST_CONTEXT node --test 'tests/*.test.mjs' > $M/$v.txt 2>&1); e=$?
|
||||
r=killed; [ $e = 0 ] && r=SURVIVED
|
||||
echo "$v $r exit=$e $(grep -E '^ℹ (pass|fail)' $M/$v.txt | tr '\n' ' ')" >> $M/summary.txt
|
||||
done
|
||||
(cd $W && git checkout -q -- packages/webui && sha256sum -c $S/pkt/candidate-manifest.sha256) > $M/manifest-after.txt 2>&1
|
||||
echo "end $(date -u +%FT%TZ)" >> $M/summary.txt
|
||||
echo DONE >> $M/summary.txt
|
||||
@@ -0,0 +1,23 @@
|
||||
start 2026-10-10T17:37:26Z
|
||||
M01 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
|
||||
M02 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M03 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M04 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
|
||||
M05 killed exit=1 ℹ pass 25 ℹ fail 2
|
||||
M06 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M07 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
|
||||
M08 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
|
||||
M09 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
|
||||
M10 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M11 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
|
||||
M12 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M13 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M14 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M15 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M16 SURVIVED exit=0 ℹ pass 27 ℹ fail 0
|
||||
M17 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M18 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
M19 killed exit=1 ℹ pass 25 ℹ fail 2
|
||||
M20 killed exit=1 ℹ pass 26 ℹ fail 1
|
||||
end 2026-10-10T17:56:15Z
|
||||
DONE
|
||||
@@ -0,0 +1 @@
|
||||
tokens.css is current
|
||||
@@ -0,0 +1,36 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3254.037973ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (4707.01393ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6741.095235ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (341.416961ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (180.268473ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (112.024139ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (2572.17701ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (222.163707ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (535.12865ms)
|
||||
✔ serve refuses a --business value that is not a business id (197.661373ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3213.259707ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3818.250352ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1561.547729ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (1241.12093ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (5596.096268ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (55064.519411ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4872.400872ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23577.983738ms)
|
||||
✔ loopback host and board origin fail closed (9.569663ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (138.151914ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (103.234277ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (1667.864763ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.458809ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.787806ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (2.003515ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (4887.914731ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3288.045605ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 55485.658358
|
||||
@@ -0,0 +1,14 @@
|
||||
start 2026-10-10T17:31:49Z
|
||||
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-10T17:34:30Z
|
||||
DONE
|
||||
@@ -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
|
||||
@@ -0,0 +1,55 @@
|
||||
Note: switching to '8a7871ff00f35f943054f5beb68b19f31ed1a3bd'.
|
||||
|
||||
You are in 'detached HEAD' state. You can look around, make experimental
|
||||
changes and commit them, and you can discard any commits you make in this
|
||||
state without impacting any branches by switching back to a branch.
|
||||
|
||||
If you want to create a new branch to retain commits you create, you may
|
||||
do so (now or later) by using -c with the switch command. Example:
|
||||
|
||||
git switch -c <new-branch-name>
|
||||
|
||||
Or undo this operation with:
|
||||
|
||||
git switch -
|
||||
|
||||
Turn off this advice by setting config variable advice.detachedHead to false
|
||||
|
||||
Not currently on any branch.
|
||||
nothing to commit, working tree clean
|
||||
Note: switching to '8a7871ff00f35f943054f5beb68b19f31ed1a3bd'.
|
||||
|
||||
You are in 'detached HEAD' state. You can look around, make experimental
|
||||
changes and commit them, and you can discard any commits you make in this
|
||||
state without impacting any branches by switching back to a branch.
|
||||
|
||||
If you want to create a new branch to retain commits you create, you may
|
||||
do so (now or later) by using -c with the switch command. Example:
|
||||
|
||||
git switch -c <new-branch-name>
|
||||
|
||||
Or undo this operation with:
|
||||
|
||||
git switch -
|
||||
|
||||
Turn off this advice by setting config variable advice.detachedHead to false
|
||||
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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: 1734733 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
|
||||
@@ -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
|
||||
@@ -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/r53a/cand) is not the queue's canonical root (/mnt/storage/src/mosaic-stack)
|
||||
|
||||
queue suite: 27 passed, 0 failed
|
||||
@@ -0,0 +1,18 @@
|
||||
start 2026-10-10T17:56:30Z
|
||||
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
|
||||
rc=0 end 2026-10-10T17:56:43Z
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,74 @@
|
||||
// Darkwing row 53 probes: does kept data show anywhere while the board or the bus refuses?
|
||||
// Run from a worktree's packages/webui: node --test <this file> with WT set to that worktree.
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createServer } 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 out = [];
|
||||
const note = (k, v) => { out.push(`${k}: ${JSON.stringify(v)}`); };
|
||||
|
||||
test('probes', { 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');
|
||||
// P1/P2: open the inspector on agent1, then the board refuses.
|
||||
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'));
|
||||
// P1b: Escape from the inspector while refused.
|
||||
ok(); await refresh(); await wait('document.querySelector("#error").hidden');
|
||||
// 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');
|
||||
// P3b: from the board page while the bus refuses, the Inbox count.
|
||||
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'));
|
||||
// P6: not-configured on a page read before.
|
||||
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]'));
|
||||
// P7: after a refusal, a non-refusal failure: are rows from before the refusal shown as stale?
|
||||
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)]'));
|
||||
// P8: toast in the accessibility tree before any copy.
|
||||
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', await b.evaluate('getComputedStyle(document.querySelector("#toast")).display'));
|
||||
} finally {
|
||||
console.log(out.join('\n'));
|
||||
await b.close(); await close(web); await new Promise(r => brd.close(r));
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
P1 board refused: board-view display: "none"
|
||||
P1 board refused: inspector: {"shown":true,"text":"agent1\nClose\nState\nwaiting\nProject\nsecretproj\nTask\nKept fixture task\nTask source\nunknown\nTask set by\nnot applicable (task is not from a registration)\nActive project\nunknown\nWorkspace\nunknown\nModel\nunk"}
|
||||
P2 board refused: projects tree: {"shown":true,"text":"All projects 2\nsecretproj 2"}
|
||||
P2 board refused: footer: {"shown":true,"text":"waiting 1 · working 1"}
|
||||
P2 board refused: #status: {"shown":true,"text":"Scanned 2026-10-10T17:35:07.220Z · refresh every 10s"}
|
||||
P4 bus refused: section list: {"shown":true,"text":"Board\nInbox\n1\n1 BLOCKING\nTasks\nAgents"}
|
||||
P3 bus refused: palette list: ["Board | view","Inbox | view","Tasks | view","Agents | view","Kept question? | decision dddddddd","#7 Kept task title | task"]
|
||||
P4b board page, bus refused: section list: {"shown":true,"text":"Board\nInbox\n1\n1 BLOCKING\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 s1-stale",1,"The last read failed. The bus did not answer in time. (outcome-unknown) This is what was read before, 1 s ago. Nothing was changed.\n\nRead again"]
|
||||
P8 status/live nodes before any toast: []
|
||||
P8 toast display: "none"
|
||||
✔ probes (3409.079539ms)
|
||||
ℹ tests 1
|
||||
ℹ suites 0
|
||||
ℹ pass 1
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 3480.865928
|
||||
@@ -0,0 +1,204 @@
|
||||
# Row 53, console tokens and shell restyle, round 1 review (Darkwing)
|
||||
|
||||
Issue #1542, request comment 27138, packet comment 27139, queue revs
|
||||
358-359. Base `8a7871ff`. Candidate manifest sha256
|
||||
`75569953c1a2cd7b7266208d6e6607290335f1bfe0cf94d96ed224e480a1dda8`, 16
|
||||
files under `packages/webui`. The packet manifest and the snapshot I took
|
||||
from the checkout both check 16 OK.
|
||||
|
||||
Verdict: **request changes**. The restyle itself is good. Tokens and the
|
||||
sprite are byte copies, the fonts match the upstream archive, every suite
|
||||
is green, and 13 of 20 mutants die on assertions. The problem is the
|
||||
refusal state. The packet says a board 403 "fails closed (kept rows
|
||||
hidden)" and a bus refusal never shows kept rows. The main table and the
|
||||
bus view do that. Five other places still show data read before the
|
||||
refusal: the inspector, the project tree, the footer and the scan line on
|
||||
the board, and the Inbox count and the Ctrl+K palette on the bus. The
|
||||
fix is small and listed under "Required".
|
||||
|
||||
## Method
|
||||
|
||||
- Detached worktrees at `8a7871ff`: `base`, `cand` and `mutwt`. The last
|
||||
two hold the 16 candidate files, staged, and check 16 OK. `mutwt` still
|
||||
checks 16 OK after the mutant runs (`r1/mut/manifest-after.txt`).
|
||||
- `r1/gate.sh`: the `packages/webui` suite, `build-tokens.mjs --check`,
|
||||
then every `scripts/test-*.sh` with `DOCKER_HOST=unix:///nonexistent.sock`,
|
||||
17:31:49Z to 17:34:30Z.
|
||||
- 20 mutants (`r1/mut/mutate.py`, `r1/mut/run.sh`), each against the full
|
||||
webui suite, 17:37:26Z to 17:56:15Z.
|
||||
- `test-release` with Docker, finished 17:56:43Z.
|
||||
- Font provenance: I downloaded `JetBrainsMono-2.304.zip` from the URL in
|
||||
`jetbrains-mono-sources.txt` into an empty directory and compared hashes
|
||||
(`r1/fonts/check.txt`).
|
||||
- Probes in Chromium through the candidate's own `tests/browser.mjs`,
|
||||
with a fake board and fake bus verbs, no tracker request
|
||||
(`r1/probes/probe.test.mjs`, output `r1/probes/probes-cand.txt`).
|
||||
- Read through `bus.js`, `app.js`, `index.html`, `shell.css`, `serve.mjs`
|
||||
and `shell.test.mjs` against the brief and `IMPLEMENTING.md`.
|
||||
|
||||
Node v26.8.1, `TMPDIR=~/darkwing-scratch/r53a/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 |
|
||||
|
||||
I didn't run test-task with real Docker, because it makes live model
|
||||
calls. The candidate changes nothing outside `packages/webui`, and
|
||||
Dewey's run gave 98/0.
|
||||
|
||||
## Copies and fonts
|
||||
|
||||
`tokens.css` and `icons.svg` are byte-equal to `docs/design`. The archive
|
||||
hashes to `6f6376c6…7bbf`, the value in the sources file. The Regular,
|
||||
Medium and Bold woff2 files and `OFL.txt` from the archive hash the same
|
||||
as the shipped files (`a9cb1cd8…`, `086c48df…`, `c503cc5e…`, `30f0c136…`).
|
||||
|
||||
## Probes
|
||||
|
||||
Fixture: one board with two sessions (project `secretproj`, task
|
||||
"Kept fixture task"), one inbox decision ("Kept question?") and one task
|
||||
("Kept task title"). Each probe reads once, then makes the read refuse.
|
||||
|
||||
| Probe | Candidate |
|
||||
|---|---|
|
||||
| P1 board 403 with the inspector open | `#board-view` is `display:none`, but the inspector stays open with agent1's state, project `secretproj` and task "Kept fixture task" |
|
||||
| P2 board 403 | the project tree shows "All projects 2 / secretproj 2"; the footer shows "waiting 1 · working 1"; `#status` shows "Scanned <time> · refresh every 10s" |
|
||||
| P3 bus `human-required` on `#/inbox`, after `#/tasks` was read | the palette lists "Kept question?" and "#7 Kept task title" |
|
||||
| P4 the same refusal | the section list shows Inbox "1" and "1 BLOCKING" |
|
||||
| P4b the same on the board page | same as P4 |
|
||||
| P6 `not-configured` after a good read | `banner ref`, no task rows. Correct |
|
||||
| P7 refusal, then `outcome-unknown` | the rows from before the refusal come back under the stale banner, "1 s ago". Fine by the brief, see note 6 |
|
||||
| P8 the toast before any copy | `display:none` |
|
||||
|
||||
P1 and P2 come from `body.board-refused #board-view{display:none}`: it
|
||||
hides the table and nothing else. The inspector, the tree, the footer and
|
||||
`#status` are outside `#board-view`. P3 and P4 come from the kept cache.
|
||||
`pkItems()` builds from `last.get('inbox')` and `last.get('tasks')`, and
|
||||
`pkOpen` refetches with `Promise.allSettled`, so a refused refetch leaves
|
||||
the old rows in `last`. The Inbox count keeps its last value, because on
|
||||
the board route a failed `fetchRead('inbox')` lands in `catch {}`.
|
||||
|
||||
Base does none of this either. There, every failure showed kept data
|
||||
under a stale banner, so this isn't a regression. It does contradict the
|
||||
row's own claim and `IMPLEMENTING.md` line 122 ("refusal (fail closed: the
|
||||
refusal code in mono and the file or rule that is missing)"). The project
|
||||
name and the task title in P1 are exactly what a refusal is supposed to
|
||||
stop showing.
|
||||
|
||||
## Mutants
|
||||
|
||||
13 of 20 killed (`r1/mut/summary.txt`). Every kill is an assertion or a
|
||||
wait timeout in the new tests, not a load error.
|
||||
|
||||
| Mutant | Change | Result |
|
||||
|---|---|---|
|
||||
| M01 | `refusal()` drops `not-configured` and `no-bus-host` | **survived** |
|
||||
| M02 | `app.js` `error()`: `refused = false` | killed |
|
||||
| M03 | no `body.board-refused` toggle | killed |
|
||||
| M04 | the `refused:` code not in `<code>` | survived, equivalent: `why()` still puts the same code in `<code>` |
|
||||
| M05 | no stale words in the bus freshness line | killed |
|
||||
| M06 | System sets `data-mode` | killed |
|
||||
| M07 | toast text not escaped | **survived** |
|
||||
| M08 | palette label not escaped | **survived** |
|
||||
| M09 | `:focus-visible` offset 0 | survived |
|
||||
| M10 | focus outline 1px | killed |
|
||||
| M11 | the section list below 760px loses `flex-wrap` and `overflow-x` | survived |
|
||||
| M12 | no section icons | killed |
|
||||
| M13 | `accept()` doesn't clear `board-refused` | killed |
|
||||
| M14 | task-link ↑/↓ reversed | killed |
|
||||
| M15 | `/icons.svg` served as `text/plain` | killed |
|
||||
| M16 | no `tabular-nums` | survived |
|
||||
| M17 | storage key changed | killed |
|
||||
| M18 | no `body.board-refused #board-view` rule | killed |
|
||||
| M19 | refusal shows kept rows (Dewey's "refusal") | killed |
|
||||
| M20 | board refusal uses `banner err` | killed |
|
||||
|
||||
M01 matters most. Both browser tests refuse with `human-required` only,
|
||||
so nothing checks that `not-configured` or `no-bus-host` fail closed over
|
||||
kept rows. My P6 shows the candidate does it, but no test holds it.
|
||||
|
||||
M08 is the palette label, which is bus text (`d.question`, the task
|
||||
title). The code escapes it; no test feeds it markup. M07 is the toast,
|
||||
whose text is `Copied: <command>`; the commands come from validated refs,
|
||||
so M07 is lower risk.
|
||||
|
||||
## Required
|
||||
|
||||
1. Board refusal hides everything read from the board, not only
|
||||
`#board-view`: close the inspector (or hide it under
|
||||
`body.board-refused`), and hide or blank the project tree counts, the
|
||||
footer counts and the "Scanned" line in `#status`.
|
||||
2. Bus refusal drops the kept bus data outside the view: the Inbox count
|
||||
and BLOCKING chip in the section list, and the palette's decisions and
|
||||
tasks. Clearing `last` for `inbox` and `tasks` on a refused read
|
||||
would cover both, including a refused refetch in `pkOpen` and the
|
||||
board route's `fetchRead('inbox')`.
|
||||
3. Tests for 1 and 2, with the inspector open when the board refuses.
|
||||
4. A refusal over kept rows with `not-configured` or `no-bus-host`, so M01
|
||||
dies.
|
||||
5. A palette test whose question or task title holds markup, so M08 dies.
|
||||
|
||||
## Notes (not blocking)
|
||||
|
||||
1. Below 760px the section list wraps. `IMPLEMENTING.md` asks for "a
|
||||
horizontal strip that scrolls inside itself". The packet lists it as a
|
||||
deviation; Sage should rule on it, and M11 shows no test pins either
|
||||
form.
|
||||
2. Below 760px the freshness line is `display:none`, so a phone shows no
|
||||
read time in the command bar. The stale banner still says it in the
|
||||
view.
|
||||
3. No test checks the focus offset (M09), and table rows use
|
||||
`outline-offset:-2px`. Inset rings on rows are reasonable; the brief
|
||||
says 2px offset.
|
||||
4. The toast is the only live region for copy, and it is `display:none`
|
||||
until the first copy. A live region that is out of the accessibility
|
||||
tree when its text arrives may not be announced the first time. I
|
||||
couldn't confirm it with a screen reader, so treat it as a risk. The
|
||||
usual fix is to keep the region rendered and empty, and hide it with
|
||||
the visually-hidden pattern.
|
||||
5. The board refusal sets the server's message in `<code>` ("refused:
|
||||
<code>board-refused</code>" in the test, "non-local Host refused" from
|
||||
control-board). That is prose in mono. A Seen POST that fails also
|
||||
goes through `error()`, so a 403 on Seen would say "The board refused
|
||||
the read". That 403 only comes from control-board's Host/Origin check,
|
||||
which refuses the read too, so the wording is wrong only in name.
|
||||
6. After a refusal, the next non-refusal failure shows the rows from
|
||||
before the refusal as stale (P7). They carry their read time, which is
|
||||
what the brief asks of the error state. Clearing `last` (Required 2)
|
||||
would remove them too; either is fine.
|
||||
7. No `tabular-nums` test (M16), no business pill (row 54), and
|
||||
`#copy-status` lost `role="status"` (the packet explains why).
|
||||
|
||||
## Filbert's review
|
||||
|
||||
Filbert posted request changes in comment 27143 at 17:52Z, while my
|
||||
mutants ran. I read it after writing the above and before posting. Their
|
||||
C1 and C2 are my Required 1 and 2, found separately with their own probe,
|
||||
and their T1 is my Required 4 (my M01, their `refusal-403-only`). I agree
|
||||
with their C3: the board freshness line should say the board wasn't read,
|
||||
not "stale", which fits under Required 1. I didn't check their N1
|
||||
(board time local, bus time UTC). It is cheap to settle in the same
|
||||
round. My Required 5 (M08, the palette escape) isn't in their list.
|
||||
|
||||
## Files
|
||||
|
||||
- `r1/candidate-manifest.sha256`: copy of Dewey's.
|
||||
- `r1/gate.sh`, `r1/out/`: suite runs, `summary.txt` and
|
||||
`test-release-docker.txt`.
|
||||
- `r1/mut/`: mutant definitions, runner, diffs, outputs, `summary.txt` and
|
||||
the manifest check after the runs.
|
||||
- `r1/probes/`: the probe test and its output.
|
||||
- `r1/fonts/check.txt`: the archive and file hashes, and the two copy
|
||||
checks.
|
||||
Reference in New Issue
Block a user