diff --git a/agents/darkwing/work/queue-56-review/r1/candidate-manifest.sha256 b/agents/darkwing/work/queue-56-review/r1/candidate-manifest.sha256 new file mode 100644 index 00000000..0aee8828 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/candidate-manifest.sha256 @@ -0,0 +1,15 @@ +1afe07062349b097b955f0391bffb839b083492d02644421def6c39cc19ff4a4 agents/rocko/work/queue-56/byte-check.sh +96416ea2eb84490b79e98b9aa0f95673e76070f15ba2876f83dbf1bdaa919f97 agents/rocko/work/queue-56/delta-check.sh +15d575cc45313906114f7edda9379b66af7624d9e894bb98812deb7acf5d87ba agents/rocko/work/queue-56/seed.sh +146b236a37bf665979e28f1794c4c4437b6e85feb43b892e8d9d697506fc453f packages/runs/package.json +594eb42518f73c94608320ce381868026aca69d8f5104711c9685ebdd8df41c9 packages/runs/README.md +f686212fa10e8541a1d8055fe30d65558a516245276aa53ecefd97bd7ca0a20c packages/runs/src/errors.mjs +eb7063a8ee0417699b45f4bfec69c3ffcde8b3b276956ca4fea266ec0abd6b23 packages/runs/src/index.mjs +3f9d025f0615a08edd440bb2aa6cea48f21cafa1f680332fffca3c7ee586cc65 packages/runs/src/paths.mjs +ba64e50c3a63e693fc313278ff6cf440234649a6719dd9229bce20272a518ec1 packages/runs/src/runs.mjs +c013ed1912bb97cbfb5209170741d9a20c2955a9acbd1fff9e397fac1fab742a packages/runs/src/state.mjs +7c941596020b14d8627ccb09b66e0e51195318e86add60eba9d2c4409e6f8dd6 packages/runs/tests/helpers.mjs +4125ffc8787f3cd9441bc2a557f42fde6948b884b8b870b503acef6eee6b3913 packages/runs/tests/runs.test.mjs +7857d2c8c94011df328dbf5013626dbcdd577945781d104dff533f08b1859130 packages/runs/tests/state.test.mjs +6bf3e758c191e23fddec6bcf30d881cdda1bb37d4e3ed1cd4ef47be79fb36bd8 packages/runs/tests/task-cli.test.mjs +4873187609897c643e62acf7f1d074fa3c03369fe6702b9b0c7776138e776401 scripts/mosaic-task.mjs diff --git a/agents/darkwing/work/queue-56-review/r1/gate.sh b/agents/darkwing/work/queue-56-review/r1/gate.sh new file mode 100755 index 00000000..83c4439e --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/gate.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Row 56 gate: packages/runs node suite, then every scripts/test-*.sh with Docker unreachable. +export TMPDIR=~/darkwing-scratch/r56a/tmp DOCKER_HOST=unix:///nonexistent.sock +cd ~/darkwing-scratch/r56a/cand +O=~/darkwing-scratch/r56a/out +: > $O/summary.txt +echo "start $(date -u +%FT%TZ)" >> $O/summary.txt +env -u NODE_TEST_CONTEXT node --test packages/runs/tests/*.test.mjs > $O/node-runs.txt 2>&1; e=$? +echo "node-runs exit=$e $(grep -E '^ℹ (pass|fail)' $O/node-runs.txt | tr '\n' ' ')" >> $O/summary.txt +for f in scripts/test-*.sh; do + s=$(basename $f .sh) + $f > $O/$s.txt 2>&1; e=$? + echo "$s exit=$e $(grep -E 'passed, [0-9]+ failed' $O/$s.txt | tail -1)" >> $O/summary.txt +done +echo "end $(date -u +%FT%TZ)" >> $O/summary.txt +echo DONE >> $O/summary.txt diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D01.diff b/agents/darkwing/work/queue-56-review/r1/mut/D01.diff new file mode 100644 index 00000000..96b8bdc7 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D01.diff @@ -0,0 +1,13 @@ +diff --git a/scripts/mosaic-task.mjs b/scripts/mosaic-task.mjs +index cf8399a0..b5a9564e 100755 +--- a/scripts/mosaic-task.mjs ++++ b/scripts/mosaic-task.mjs +@@ -486,7 +486,7 @@ function listRuns() { + } + + function showRun(runId) { +- if (!isRunId(runId)) { ++ if (false) { + fail(4, `invalid run id: ${JSON.stringify(runId)} (expected r-)`); + } + const resolved = loadConfig(); diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D01.txt b/agents/darkwing/work/queue-56-review/r1/mut/D01.txt new file mode 100644 index 00000000..735f8e97 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D01.txt @@ -0,0 +1,45 @@ +✔ isRunId accepts the run id shape and nothing else (1.129303ms) +✔ a missing data root or runs directory lists nothing (2.363755ms) +✔ runs as a regular file lists nothing, as before (0.81288ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.872847ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.892326ms) +✔ readRunRecord returns documents and artifacts in directory order (1.545032ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (0.947125ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.861621ms) +✔ readRunDocument reads only the three run documents (0.744194ms) +✔ a link inside the data root is followed (2.213785ms) +✔ a data root that is itself a link is trusted as configured (0.840807ms) +✔ a run directory linked out of the data root is never read (0.832753ms) +✔ a document linked out of the data root reads as null (1.088125ms) +✔ a runs directory linked out of the data root refuses (0.797926ms) +✔ a relative link that climbs out of the data root refuses (0.741627ms) +✔ a sibling whose name starts with the data root's name is outside it (0.847544ms) +✔ a link loop refuses instead of reading as missing (1.021958ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.767933ms) +✔ an unreadable run directory refuses instead of reading as missing (0.687222ms) +✔ a link to the data root's parent is outside it (0.483537ms) +✔ listRunIds sorts whatever order the directory returns (1.065985ms) +✔ the readers write nothing (3.274403ms) +✔ no pointer is null (2.908017ms) +✔ the pointer release.sh writes reads back (1.898894ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.141146ms) +✔ a pointer that is a directory refuses with exit 4 (0.931434ms) +✔ a state file linked out of the data root refuses (2.22612ms) +✔ a state directory linked out of the data root refuses (0.984988ms) +✔ a missing log is empty (0.69135ms) +✔ the log reads oldest first and counts malformed lines (1.524874ms) +✔ last must be a positive integer (1.101485ms) +✔ the state readers write nothing (1.595899ms) +✔ list prints each run in the established format (102.108158ms) +✔ show prints the run in the established format (98.414356ms) +✔ show of a missing run and an invalid id exit 4 as before (161.801585ms) +✔ list and show refuse a runs directory linked out of the data root (218.443475ms) +✔ show refuses a run linked out of the data root; list reports it unknown (197.170014ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 37 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 845.97083 diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D03.diff b/agents/darkwing/work/queue-56-review/r1/mut/D03.diff new file mode 100644 index 00000000..1a33b122 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D03.diff @@ -0,0 +1,14 @@ +diff --git a/packages/runs/src/paths.mjs b/packages/runs/src/paths.mjs +index 1dbb5539..f7c5f4ea 100644 +--- a/packages/runs/src/paths.mjs ++++ b/packages/runs/src/paths.mjs +@@ -43,7 +43,8 @@ export function readJsonObject(dataRoot, ...parts) { + if (file === null) return null; + const value = JSON.parse(fs.readFileSync(file, "utf8")); + return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null; +- } catch { ++ } catch (error) { ++ if (error instanceof RunsError) throw error; + return null; + } + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D03.txt b/agents/darkwing/work/queue-56-review/r1/mut/D03.txt new file mode 100644 index 00000000..5768ff89 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D03.txt @@ -0,0 +1,117 @@ +✔ isRunId accepts the run id shape and nothing else (1.956544ms) +✔ a missing data root or runs directory lists nothing (2.725076ms) +✔ runs as a regular file lists nothing, as before (1.059244ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.387509ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.768494ms) +✔ readRunRecord returns documents and artifacts in directory order (1.559464ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.211241ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.141838ms) +✔ readRunDocument reads only the three run documents (0.910973ms) +✔ a link inside the data root is followed (1.969226ms) +✔ a data root that is itself a link is trusted as configured (1.360016ms) +✖ a run directory linked out of the data root is never read (2.59955ms) +✖ a document linked out of the data root reads as null (1.129541ms) +✔ a runs directory linked out of the data root refuses (2.924601ms) +✔ a relative link that climbs out of the data root refuses (0.900903ms) +✔ a sibling whose name starts with the data root's name is outside it (0.987308ms) +✖ a link loop refuses instead of reading as missing (1.102282ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.771326ms) +✔ an unreadable run directory refuses instead of reading as missing (1.015364ms) +✔ a link to the data root's parent is outside it (2.042409ms) +✔ listRunIds sorts whatever order the directory returns (1.683733ms) +✔ the readers write nothing (3.50432ms) +✔ no pointer is null (3.237439ms) +✔ the pointer release.sh writes reads back (2.002114ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.94932ms) +✔ a pointer that is a directory refuses with exit 4 (1.676768ms) +✔ a state file linked out of the data root refuses (1.657011ms) +✔ a state directory linked out of the data root refuses (1.062717ms) +✔ a missing log is empty (0.687978ms) +✔ the log reads oldest first and counts malformed lines (1.731535ms) +✔ last must be a positive integer (0.797464ms) +✔ the state readers write nothing (1.515893ms) +✔ list prints each run in the established format (142.248626ms) +✔ show prints the run in the established format (102.945184ms) +✔ show of a missing run and an invalid id exit 4 as before (148.67361ms) +✔ list and show refuse a runs directory linked out of the data root (192.921615ms) +✖ show refuses a run linked out of the data root; list reports it unknown (213.400604ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 33 +ℹ fail 4 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 871.096655 + +✖ failing tests: + +test at packages/runs/tests/runs.test.mjs:119:1 +✖ a run directory linked out of the data root is never read (2.59955ms) + Error [RunsError]: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-PvDpe8/data/runs/r-20260101T000000Z-aaaaaa/result.json resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-PvDpe8/data) + at resolveInside (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:33:11) + at readJsonObject (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:42:18) + at file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:46:13 + at Array.map () + at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:44:31) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:125:20) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) { + exitCode: 4 + } + +test at packages/runs/tests/runs.test.mjs:129:1 +✖ a document linked out of the data root reads as null (1.129541ms) + Error [RunsError]: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-WcZej3/data/runs/r-20260101T000000Z-aaaaaa/result.json resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-WcZej3/data) + at resolveInside (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:33:11) + at readJsonObject (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:42:18) + at readRunDocument (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:37:10) + at readRunRecord (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:67:13) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:136:18) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) { + exitCode: 4 + } + +test at packages/runs/tests/runs.test.mjs:168:1 +✖ a link loop refuses instead of reading as missing (1.102282ms) + Error [RunsError]: cannot resolve /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-x1gAr0/data/runs/r-20260101T000000Z-aaaaaa/result.json: ELOOP + at resolveInside (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:30:11) + at readJsonObject (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:42:18) + at file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:46:13 + at Array.map () + at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:44:31) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:174:20) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) { + exitCode: 4 + } + +test at packages/runs/tests/task-cli.test.mjs:82:1 +✖ show refuses a run linked out of the data root; list reports it unknown (213.400604ms) + AssertionError [ERR_ASSERTION]: mosaic-task: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-223gdI/data/runs/r-20260101T000000Z-aaaaaa/result.json resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-223gdI/data) + + + 4 !== 0 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/task-cli.test.mjs:92:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: 4, + expected: 0, + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D04.diff b/agents/darkwing/work/queue-56-review/r1/mut/D04.diff new file mode 100644 index 00000000..1ae95fe2 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D04.diff @@ -0,0 +1,12 @@ +diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs +index 03730c33..5096f921 100644 +--- a/packages/runs/src/runs.mjs ++++ b/packages/runs/src/runs.mjs +@@ -52,7 +52,6 @@ export function listRunRecords(dataRoot) { + export function readRunRecord(dataRoot, runId) { + requireRunId(runId); + // The runs directory first, so a refusal names the link that escapes. +- if (resolveInside(dataRoot, RUNS_DIRNAME) === null) return null; + const dir = resolveInside(dataRoot, RUNS_DIRNAME, runId); + if (dir === null) return null; + let artifacts; diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D04.txt b/agents/darkwing/work/queue-56-review/r1/mut/D04.txt new file mode 100644 index 00000000..b7c8f285 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D04.txt @@ -0,0 +1,99 @@ +✔ isRunId accepts the run id shape and nothing else (1.68092ms) +✔ a missing data root or runs directory lists nothing (3.048389ms) +✔ runs as a regular file lists nothing, as before (0.963654ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.872482ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.199887ms) +✔ readRunRecord returns documents and artifacts in directory order (1.277031ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (0.810683ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.290617ms) +✔ readRunDocument reads only the three run documents (0.831152ms) +✔ a link inside the data root is followed (1.288609ms) +✔ a data root that is itself a link is trusted as configured (0.929194ms) +✔ a run directory linked out of the data root is never read (1.220122ms) +✔ a document linked out of the data root reads as null (1.495058ms) +✖ a runs directory linked out of the data root refuses (1.812269ms) +✔ a relative link that climbs out of the data root refuses (0.695909ms) +✔ a sibling whose name starts with the data root's name is outside it (0.712215ms) +✔ a link loop refuses instead of reading as missing (0.934066ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.655307ms) +✔ an unreadable run directory refuses instead of reading as missing (0.742938ms) +✔ a link to the data root's parent is outside it (0.576201ms) +✔ listRunIds sorts whatever order the directory returns (1.174841ms) +✔ the readers write nothing (2.73421ms) +✔ no pointer is null (2.202006ms) +✔ the pointer release.sh writes reads back (1.472039ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.816169ms) +✔ a pointer that is a directory refuses with exit 4 (1.423693ms) +✔ a state file linked out of the data root refuses (1.147291ms) +✔ a state directory linked out of the data root refuses (0.647667ms) +✔ a missing log is empty (1.318528ms) +✔ the log reads oldest first and counts malformed lines (1.349691ms) +✔ last must be a positive integer (0.767877ms) +✔ the state readers write nothing (1.128232ms) +✔ list prints each run in the established format (118.264972ms) +✔ show prints the run in the established format (82.606742ms) +✔ show of a missing run and an invalid id exit 4 as before (129.149189ms) +✖ list and show refuse a runs directory linked out of the data root (187.309472ms) +✔ show refuses a run linked out of the data root; list reports it unknown (222.898306ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 35 +ℹ fail 2 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 812.977588 + +✖ failing tests: + +test at packages/runs/tests/runs.test.mjs:143:1 +✖ a runs directory linked out of the data root refuses (1.812269ms) + AssertionError [ERR_ASSERTION]: The input did not match the regular expression /runs resolves outside the data root/. Input: + + 'RunsError: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-zX0oF7/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-zX0oF7/data)' + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:149:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: RunsError: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-zX0oF7/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-zX0oF7/data) + at resolveInside (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:33:11) + at readRunRecord (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:55:15) + at file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:149:23 + at getActual (node:assert:580:5) + at strict.throws (node:assert:728:24) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:149:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19), + expected: /runs resolves outside the data root/, + operator: 'throws', + diff: 'simple' + } + +test at packages/runs/tests/task-cli.test.mjs:70:1 +✖ list and show refuse a runs directory linked out of the data root (187.309472ms) + AssertionError [ERR_ASSERTION]: The input did not match the regular expression /^mosaic-task: .*runs resolves outside the data root/. Input: + + 'mosaic-task: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-v5t5hA/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-v5t5hA/data)\n' + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/task-cli.test.mjs:78:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'mosaic-task: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-v5t5hA/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-v5t5hA/data)\n', + expected: /^mosaic-task: .*runs resolves outside the data root/, + operator: 'match', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D05.diff b/agents/darkwing/work/queue-56-review/r1/mut/D05.diff new file mode 100644 index 00000000..6b54b320 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D05.diff @@ -0,0 +1,11 @@ +diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs +index a92c8713..c32758bc 100644 +--- a/packages/runs/src/state.mjs ++++ b/packages/runs/src/state.mjs +@@ -78,5 +78,5 @@ export function readActivationLog(dataRoot, { last } = {}) { + if (entry === null) malformed += 1; + else entries.push(entry); + } +- return { entries: last === undefined ? entries : entries.slice(-last), malformed }; ++ return { entries: last === undefined ? entries : entries.slice(0, last), malformed }; + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D05.txt b/agents/darkwing/work/queue-56-review/r1/mut/D05.txt new file mode 100644 index 00000000..950cbd66 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D05.txt @@ -0,0 +1,94 @@ +✔ isRunId accepts the run id shape and nothing else (1.680565ms) +✔ a missing data root or runs directory lists nothing (1.794757ms) +✔ runs as a regular file lists nothing, as before (0.731147ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.864372ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.326643ms) +✔ readRunRecord returns documents and artifacts in directory order (1.783473ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.188716ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.093319ms) +✔ readRunDocument reads only the three run documents (0.846733ms) +✔ a link inside the data root is followed (1.17458ms) +✔ a data root that is itself a link is trusted as configured (0.781634ms) +✔ a run directory linked out of the data root is never read (0.777016ms) +✔ a document linked out of the data root reads as null (1.278597ms) +✔ a runs directory linked out of the data root refuses (0.649479ms) +✔ a relative link that climbs out of the data root refuses (0.502717ms) +✔ a sibling whose name starts with the data root's name is outside it (0.58152ms) +✔ a link loop refuses instead of reading as missing (0.775651ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.659139ms) +✔ an unreadable run directory refuses instead of reading as missing (1.013293ms) +✔ a link to the data root's parent is outside it (0.653539ms) +✔ listRunIds sorts whatever order the directory returns (1.135619ms) +✔ the readers write nothing (2.823246ms) +✔ no pointer is null (2.918785ms) +✔ the pointer release.sh writes reads back (1.860026ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.823183ms) +✔ a pointer that is a directory refuses with exit 4 (1.736666ms) +✔ a state file linked out of the data root refuses (1.677527ms) +✔ a state directory linked out of the data root refuses (0.987759ms) +✔ a missing log is empty (0.672303ms) +✖ the log reads oldest first and counts malformed lines (3.332551ms) +✔ last must be a positive integer (0.804321ms) +✔ the state readers write nothing (2.095782ms) +✔ list prints each run in the established format (98.447736ms) +✔ show prints the run in the established format (94.546953ms) +✔ show of a missing run and an invalid id exit 4 as before (141.127685ms) +✔ list and show refuse a runs directory linked out of the data root (186.311477ms) +✔ show refuses a run linked out of the data root; list reports it unknown (200.292033ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 810.059294 + +✖ failing tests: + +test at packages/runs/tests/state.test.mjs:80:1 +✖ the log reads oldest first and counts malformed lines (3.332551ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + { + entries: [ + { + + at: '2026-09-03T20:57:00Z', + + event: 'package', + + imageTag: 'mosaic-poc-agent:0.84.4-r0.0.12', + + release: '0.0.12' + - at: '2026-09-03T20:57:50Z', + - event: 'refused', + - imageTag: 'mosaic-poc-agent:0.84.4-r0.0.11', + - note: 'health check failed (fault-injected)', + - release: '0.0.11' + }, + { + + at: '2026-09-03T20:57:47Z', + + event: 'activate', + + imageTag: 'mosaic-poc-agent:0.84.4-r0.0.12', + + release: '0.0.12' + - at: '2026-09-03T20:58:15Z', + - event: 'rollback', + - imageTag: 'mosaic-poc-agent:0.84.4-r0.0.11', + - release: '0.0.11' + } + ], + malformed: 5 + } + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:102:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: { entries: [ [Object], [Object] ], malformed: 5 }, + expected: { entries: [ [Object], [Object] ], malformed: 5 }, + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D06.diff b/agents/darkwing/work/queue-56-review/r1/mut/D06.diff new file mode 100644 index 00000000..888fcb2f --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D06.diff @@ -0,0 +1,12 @@ +diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs +index a92c8713..1002fb94 100644 +--- a/packages/runs/src/state.mjs ++++ b/packages/runs/src/state.mjs +@@ -56,7 +56,6 @@ function logEntry(line) { + if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return null; + if (Object.keys(entry).some((key) => !LOG_KEYS.includes(key))) return null; + if (!["at", "event", "release", "imageTag"].every((key) => typeof entry[key] === "string")) return null; +- if (entry.note !== undefined && typeof entry.note !== "string") return null; + return entry; + } + diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D06.txt b/agents/darkwing/work/queue-56-review/r1/mut/D06.txt new file mode 100644 index 00000000..8de767ee --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D06.txt @@ -0,0 +1,93 @@ +✔ isRunId accepts the run id shape and nothing else (1.849966ms) +✔ a missing data root or runs directory lists nothing (1.966701ms) +✔ runs as a regular file lists nothing, as before (1.044085ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.404037ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.671713ms) +✔ readRunRecord returns documents and artifacts in directory order (1.978123ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.320202ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.202015ms) +✔ readRunDocument reads only the three run documents (0.982657ms) +✔ a link inside the data root is followed (1.840354ms) +✔ a data root that is itself a link is trusted as configured (1.271595ms) +✔ a run directory linked out of the data root is never read (1.363834ms) +✔ a document linked out of the data root reads as null (1.561635ms) +✔ a runs directory linked out of the data root refuses (0.727258ms) +✔ a relative link that climbs out of the data root refuses (0.670099ms) +✔ a sibling whose name starts with the data root's name is outside it (0.641573ms) +✔ a link loop refuses instead of reading as missing (0.934577ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.850297ms) +✔ an unreadable run directory refuses instead of reading as missing (0.87724ms) +✔ a link to the data root's parent is outside it (0.770198ms) +✔ listRunIds sorts whatever order the directory returns (1.036885ms) +✔ the readers write nothing (3.831769ms) +✔ no pointer is null (2.316454ms) +✔ the pointer release.sh writes reads back (1.598365ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.175811ms) +✔ a pointer that is a directory refuses with exit 4 (0.778144ms) +✔ a state file linked out of the data root refuses (2.517371ms) +✔ a state directory linked out of the data root refuses (0.870816ms) +✔ a missing log is empty (0.611372ms) +✖ the log reads oldest first and counts malformed lines (2.862969ms) +✔ last must be a positive integer (0.64267ms) +✔ the state readers write nothing (1.472105ms) +✔ list prints each run in the established format (103.761545ms) +✔ show prints the run in the established format (97.443115ms) +✔ show of a missing run and an invalid id exit 4 as before (161.288152ms) +✔ list and show refuse a runs directory linked out of the data root (176.117228ms) +✔ show refuses a run linked out of the data root; list reports it unknown (238.782496ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 865.082532 + +✖ failing tests: + +test at packages/runs/tests/state.test.mjs:80:1 +✖ the log reads oldest first and counts malformed lines (2.862969ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + ... Skipped lines + + { + entries: [ + { + at: '2026-09-03T20:57:00Z', + event: 'package', + ... + { + + at: '2026-09-03T20:57:47Z', + + event: 'activate', + + imageTag: 'mosaic-poc-agent:0.84.4-r0.0.12', + + note: null, + + release: '0.0.12' + + }, + + { + at: '2026-09-03T20:57:50Z', + event: 'refused', + imageTag: 'mosaic-poc-agent:0.84.4-r0.0.11', + note: 'health check failed (fault-injected)', + release: '0.0.11' + ... + ], + + malformed: 4 + - malformed: 5 + } + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:101:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: { entries: [ [Object], [Object], [Object], [Object], [Object] ], malformed: 4 }, + expected: { entries: [ [Object], [Object], [Object], [Object] ], malformed: 5 }, + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D07.diff b/agents/darkwing/work/queue-56-review/r1/mut/D07.diff new file mode 100644 index 00000000..e64be3d6 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D07.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs +index 03730c33..e02fea8e 100644 +--- a/packages/runs/src/runs.mjs ++++ b/packages/runs/src/runs.mjs +@@ -23,7 +23,7 @@ export function listRunIds(dataRoot) { + try { + names = fs.readdirSync(root); + } catch (error) { +- if (isMissing(error)) return []; ++ return []; + throw new RunsError(`cannot read ${root}: ${error.code ?? error.message}`); + } + return names.filter((name) => name.startsWith("r-")).sort(); diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D07.txt b/agents/darkwing/work/queue-56-review/r1/mut/D07.txt new file mode 100644 index 00000000..5bda3f11 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D07.txt @@ -0,0 +1,64 @@ +✔ isRunId accepts the run id shape and nothing else (1.74403ms) +✔ a missing data root or runs directory lists nothing (2.198048ms) +✔ runs as a regular file lists nothing, as before (0.749386ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.943488ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (4.593534ms) +✔ readRunRecord returns documents and artifacts in directory order (2.041033ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.316339ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.130767ms) +✔ readRunDocument reads only the three run documents (0.938903ms) +✔ a link inside the data root is followed (1.911798ms) +✔ a data root that is itself a link is trusted as configured (1.338795ms) +✔ a run directory linked out of the data root is never read (1.316168ms) +✔ a document linked out of the data root reads as null (1.553329ms) +✔ a runs directory linked out of the data root refuses (0.940651ms) +✔ a relative link that climbs out of the data root refuses (0.763816ms) +✔ a sibling whose name starts with the data root's name is outside it (0.831365ms) +✔ a link loop refuses instead of reading as missing (1.081862ms) +✖ an unreadable runs directory refuses instead of listing nothing (1.920097ms) +✔ an unreadable run directory refuses instead of reading as missing (0.910463ms) +✔ a link to the data root's parent is outside it (0.731845ms) +✔ listRunIds sorts whatever order the directory returns (1.261893ms) +✔ the readers write nothing (4.021246ms) +✔ no pointer is null (3.059529ms) +✔ the pointer release.sh writes reads back (1.661181ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.521897ms) +✔ a pointer that is a directory refuses with exit 4 (1.465131ms) +✔ a state file linked out of the data root refuses (1.638679ms) +✔ a state directory linked out of the data root refuses (0.691235ms) +✔ a missing log is empty (0.580753ms) +✔ the log reads oldest first and counts malformed lines (1.082188ms) +✔ last must be a positive integer (0.648072ms) +✔ the state readers write nothing (1.944511ms) +✔ list prints each run in the established format (135.505629ms) +✔ show prints the run in the established format (124.440305ms) +✔ show of a missing run and an invalid id exit 4 as before (139.637014ms) +✔ list and show refuse a runs directory linked out of the data root (207.914443ms) +✔ show refuses a run linked out of the data root; list reports it unknown (222.421367ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 912.133056 + +✖ failing tests: + +test at packages/runs/tests/runs.test.mjs:177:1 +✖ an unreadable runs directory refuses instead of listing nothing (1.920097ms) + AssertionError [ERR_ASSERTION]: Missing expected exception. + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:183:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + operator: 'throws', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D08.diff b/agents/darkwing/work/queue-56-review/r1/mut/D08.diff new file mode 100644 index 00000000..9e8298fc --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D08.diff @@ -0,0 +1,12 @@ +diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs +index a92c8713..1c7c4378 100644 +--- a/packages/runs/src/state.mjs ++++ b/packages/runs/src/state.mjs +@@ -18,6 +18,7 @@ function readStateFile(dataRoot, name) { + try { + return { file, text: fs.readFileSync(file, "utf8") }; + } catch (error) { ++ return null; + throw new RunsError(`cannot read ${file}: ${error.code ?? error.message}`); + } + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D08.txt b/agents/darkwing/work/queue-56-review/r1/mut/D08.txt new file mode 100644 index 00000000..884b8303 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D08.txt @@ -0,0 +1,64 @@ +✔ isRunId accepts the run id shape and nothing else (2.461841ms) +✔ a missing data root or runs directory lists nothing (4.122833ms) +✔ runs as a regular file lists nothing, as before (1.049435ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.484169ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (5.953769ms) +✔ readRunRecord returns documents and artifacts in directory order (2.533866ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.781628ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.272589ms) +✔ readRunDocument reads only the three run documents (1.222564ms) +✔ a link inside the data root is followed (2.349315ms) +✔ a data root that is itself a link is trusted as configured (4.990435ms) +✔ a run directory linked out of the data root is never read (1.847834ms) +✔ a document linked out of the data root reads as null (1.825285ms) +✔ a runs directory linked out of the data root refuses (1.095073ms) +✔ a relative link that climbs out of the data root refuses (0.798642ms) +✔ a sibling whose name starts with the data root's name is outside it (0.914727ms) +✔ a link loop refuses instead of reading as missing (2.417719ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.968089ms) +✔ an unreadable run directory refuses instead of reading as missing (1.041544ms) +✔ a link to the data root's parent is outside it (0.822282ms) +✔ listRunIds sorts whatever order the directory returns (1.693855ms) +✔ the readers write nothing (4.240004ms) +✔ no pointer is null (4.711471ms) +✔ the pointer release.sh writes reads back (3.19144ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.698419ms) +✖ a pointer that is a directory refuses with exit 4 (2.271643ms) +✔ a state file linked out of the data root refuses (3.820894ms) +✔ a state directory linked out of the data root refuses (1.328242ms) +✔ a missing log is empty (0.757558ms) +✔ the log reads oldest first and counts malformed lines (3.341732ms) +✔ last must be a positive integer (1.01732ms) +✔ the state readers write nothing (2.075785ms) +✔ list prints each run in the established format (134.172955ms) +✔ show prints the run in the established format (111.604381ms) +✔ show of a missing run and an invalid id exit 4 as before (176.970683ms) +✔ list and show refuse a runs directory linked out of the data root (212.899331ms) +✔ show refuses a run linked out of the data root; list reports it unknown (174.178303ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 930.307733 + +✖ failing tests: + +test at packages/runs/tests/state.test.mjs:51:1 +✖ a pointer that is a directory refuses with exit 4 (2.271643ms) + AssertionError [ERR_ASSERTION]: Missing expected exception. + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:54:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + operator: 'throws', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D09.diff b/agents/darkwing/work/queue-56-review/r1/mut/D09.diff new file mode 100644 index 00000000..5a7e0dbb --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D09.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs +index a92c8713..9e424f9f 100644 +--- a/packages/runs/src/state.mjs ++++ b/packages/runs/src/state.mjs +@@ -37,7 +37,7 @@ export function readActivePointer(dataRoot) { + const invalid = (why) => new RunsError(`release pointer ${why} (${state.file})`, 2); + if (typeof pointer !== "object" || pointer === null || Array.isArray(pointer)) throw invalid("must be a JSON object"); + for (const key of Object.keys(pointer)) { +- if (!POINTER_KEYS.includes(key)) throw invalid(`has an unsupported key: "${key}"`); ++ if (false) throw invalid(`has an unsupported key: "${key}"`); + } + if (pointer.pointerVersion !== 1) throw invalid(`has unsupported pointerVersion ${JSON.stringify(pointer.pointerVersion)}`); + for (const key of ["release", "imageTag", "activatedAt"]) { diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D09.txt b/agents/darkwing/work/queue-56-review/r1/mut/D09.txt new file mode 100644 index 00000000..452449fa --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D09.txt @@ -0,0 +1,64 @@ +✔ isRunId accepts the run id shape and nothing else (1.76778ms) +✔ a missing data root or runs directory lists nothing (2.441016ms) +✔ runs as a regular file lists nothing, as before (0.970565ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.262129ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.361776ms) +✔ readRunRecord returns documents and artifacts in directory order (1.832576ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.389704ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.129822ms) +✔ readRunDocument reads only the three run documents (0.922434ms) +✔ a link inside the data root is followed (1.811731ms) +✔ a data root that is itself a link is trusted as configured (1.209871ms) +✔ a run directory linked out of the data root is never read (1.162347ms) +✔ a document linked out of the data root reads as null (1.753983ms) +✔ a runs directory linked out of the data root refuses (0.898425ms) +✔ a relative link that climbs out of the data root refuses (0.561041ms) +✔ a sibling whose name starts with the data root's name is outside it (0.862277ms) +✔ a link loop refuses instead of reading as missing (0.825058ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.584625ms) +✔ an unreadable run directory refuses instead of reading as missing (0.750071ms) +✔ a link to the data root's parent is outside it (0.445297ms) +✔ listRunIds sorts whatever order the directory returns (0.954512ms) +✔ the readers write nothing (2.660378ms) +✔ no pointer is null (2.198032ms) +✔ the pointer release.sh writes reads back (1.29844ms) +✖ a pointer that isn't the version 1 shape refuses with exit 2 (8.313848ms) +✔ a pointer that is a directory refuses with exit 4 (1.040667ms) +✔ a state file linked out of the data root refuses (2.188204ms) +✔ a state directory linked out of the data root refuses (0.785082ms) +✔ a missing log is empty (0.511055ms) +✔ the log reads oldest first and counts malformed lines (1.260842ms) +✔ last must be a positive integer (0.5446ms) +✔ the state readers write nothing (1.511675ms) +✔ list prints each run in the established format (106.978183ms) +✔ show prints the run in the established format (82.075624ms) +✔ show of a missing run and an invalid id exit 4 as before (150.338163ms) +✔ list and show refuse a runs directory linked out of the data root (213.344597ms) +✔ show refuses a run linked out of the data root; list reports it unknown (189.567749ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 817.276399 + +✖ failing tests: + +test at packages/runs/tests/state.test.mjs:32:1 +✖ a pointer that isn't the version 1 shape refuses with exit 2 (8.313848ms) + AssertionError [ERR_ASSERTION]: Missing expected exception: /unsupported key: "extra"/ + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:47:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + operator: 'throws', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D10.diff b/agents/darkwing/work/queue-56-review/r1/mut/D10.diff new file mode 100644 index 00000000..73fbfb7d --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D10.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/paths.mjs b/packages/runs/src/paths.mjs +index 1dbb5539..fe56cb9b 100644 +--- a/packages/runs/src/paths.mjs ++++ b/packages/runs/src/paths.mjs +@@ -11,7 +11,7 @@ export function isMissing(error) { + + function isInside(root, target) { + const relative = path.relative(root, target); +- return relative === "" || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)); ++ return false || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)); + } + + // Resolves / through any symbolic links and returns the diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D10.txt b/agents/darkwing/work/queue-56-review/r1/mut/D10.txt new file mode 100644 index 00000000..e4681b94 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D10.txt @@ -0,0 +1,45 @@ +✔ isRunId accepts the run id shape and nothing else (1.51662ms) +✔ a missing data root or runs directory lists nothing (2.475089ms) +✔ runs as a regular file lists nothing, as before (1.23105ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.353463ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.784699ms) +✔ readRunRecord returns documents and artifacts in directory order (1.983165ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.313701ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.315203ms) +✔ readRunDocument reads only the three run documents (1.070086ms) +✔ a link inside the data root is followed (1.390231ms) +✔ a data root that is itself a link is trusted as configured (1.13756ms) +✔ a run directory linked out of the data root is never read (1.289428ms) +✔ a document linked out of the data root reads as null (1.707909ms) +✔ a runs directory linked out of the data root refuses (0.751734ms) +✔ a relative link that climbs out of the data root refuses (0.807517ms) +✔ a sibling whose name starts with the data root's name is outside it (0.930121ms) +✔ a link loop refuses instead of reading as missing (4.279406ms) +✔ an unreadable runs directory refuses instead of listing nothing (1.054034ms) +✔ an unreadable run directory refuses instead of reading as missing (1.037179ms) +✔ a link to the data root's parent is outside it (0.766076ms) +✔ listRunIds sorts whatever order the directory returns (1.561169ms) +✔ the readers write nothing (4.251191ms) +✔ no pointer is null (2.961101ms) +✔ the pointer release.sh writes reads back (2.02442ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (5.513029ms) +✔ a pointer that is a directory refuses with exit 4 (1.812389ms) +✔ a state file linked out of the data root refuses (1.807408ms) +✔ a state directory linked out of the data root refuses (1.064741ms) +✔ a missing log is empty (0.778107ms) +✔ the log reads oldest first and counts malformed lines (1.719825ms) +✔ last must be a positive integer (0.79633ms) +✔ the state readers write nothing (1.960078ms) +✔ list prints each run in the established format (121.641214ms) +✔ show prints the run in the established format (103.243231ms) +✔ show of a missing run and an invalid id exit 4 as before (168.245538ms) +✔ list and show refuse a runs directory linked out of the data root (247.465101ms) +✔ show refuses a run linked out of the data root; list reports it unknown (182.280266ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 37 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 914.239511 diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D11.diff b/agents/darkwing/work/queue-56-review/r1/mut/D11.diff new file mode 100644 index 00000000..7f6cfd84 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D11.diff @@ -0,0 +1,13 @@ +diff --git a/scripts/mosaic-task.mjs b/scripts/mosaic-task.mjs +index cf8399a0..7c4bfb80 100755 +--- a/scripts/mosaic-task.mjs ++++ b/scripts/mosaic-task.mjs +@@ -462,7 +462,7 @@ function readRuns(read) { + try { + return read(); + } catch (error) { +- if (error instanceof RunsError) fail(error.exitCode, error.message); ++ if (false) fail(error.exitCode, error.message); + throw error; + } + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D11.txt b/agents/darkwing/work/queue-56-review/r1/mut/D11.txt new file mode 100644 index 00000000..958e3bb1 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D11.txt @@ -0,0 +1,89 @@ +✔ isRunId accepts the run id shape and nothing else (1.335247ms) +✔ a missing data root or runs directory lists nothing (2.044238ms) +✔ runs as a regular file lists nothing, as before (0.825059ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.992615ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.448335ms) +✔ readRunRecord returns documents and artifacts in directory order (1.940595ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (0.88747ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.887944ms) +✔ readRunDocument reads only the three run documents (0.742112ms) +✔ a link inside the data root is followed (1.800967ms) +✔ a data root that is itself a link is trusted as configured (1.347045ms) +✔ a run directory linked out of the data root is never read (1.219752ms) +✔ a document linked out of the data root reads as null (1.142642ms) +✔ a runs directory linked out of the data root refuses (0.77569ms) +✔ a relative link that climbs out of the data root refuses (0.508687ms) +✔ a sibling whose name starts with the data root's name is outside it (0.818208ms) +✔ a link loop refuses instead of reading as missing (0.874875ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.617573ms) +✔ an unreadable run directory refuses instead of reading as missing (0.789617ms) +✔ a link to the data root's parent is outside it (0.744195ms) +✔ listRunIds sorts whatever order the directory returns (1.123154ms) +✔ the readers write nothing (3.640519ms) +✔ no pointer is null (2.825548ms) +✔ the pointer release.sh writes reads back (1.614689ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.000458ms) +✔ a pointer that is a directory refuses with exit 4 (0.784002ms) +✔ a state file linked out of the data root refuses (2.224001ms) +✔ a state directory linked out of the data root refuses (1.043958ms) +✔ a missing log is empty (0.707165ms) +✔ the log reads oldest first and counts malformed lines (1.568329ms) +✔ last must be a positive integer (0.801038ms) +✔ the state readers write nothing (1.64136ms) +✔ list prints each run in the established format (114.475779ms) +✔ show prints the run in the established format (92.906292ms) +✔ show of a missing run and an invalid id exit 4 as before (173.27576ms) +✖ list and show refuse a runs directory linked out of the data root (104.319544ms) +✖ show refuses a run linked out of the data root; list reports it unknown (123.359118ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 35 +ℹ fail 2 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 689.166126 + +✖ failing tests: + +test at packages/runs/tests/task-cli.test.mjs:70:1 +✖ list and show refuse a runs directory linked out of the data root (104.319544ms) + AssertionError [ERR_ASSERTION]: list + + 1 !== 4 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/task-cli.test.mjs:76:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: 1, + expected: 4, + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/runs/tests/task-cli.test.mjs:82:1 +✖ show refuses a run linked out of the data root; list reports it unknown (123.359118ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 1 !== 4 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/task-cli.test.mjs:88:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 1, + expected: 4, + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D13.diff b/agents/darkwing/work/queue-56-review/r1/mut/D13.diff new file mode 100644 index 00000000..12214802 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D13.diff @@ -0,0 +1,12 @@ +diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs +index 03730c33..943dadfa 100644 +--- a/packages/runs/src/runs.mjs ++++ b/packages/runs/src/runs.mjs +@@ -59,7 +59,6 @@ export function readRunRecord(dataRoot, runId) { + try { + artifacts = fs.readdirSync(dir); + } catch (error) { +- if (isMissing(error)) return null; + throw new RunsError(`cannot read ${dir}: ${error.code ?? error.message}`); + } + return { diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D13.txt b/agents/darkwing/work/queue-56-review/r1/mut/D13.txt new file mode 100644 index 00000000..fe2cfc5d --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D13.txt @@ -0,0 +1,61 @@ +✔ isRunId accepts the run id shape and nothing else (1.279176ms) +✔ a missing data root or runs directory lists nothing (2.009751ms) +✔ runs as a regular file lists nothing, as before (0.780142ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.907817ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.573369ms) +✔ readRunRecord returns documents and artifacts in directory order (1.415964ms) +✖ readRunRecord is null for a missing run, a dangling link or a file (1.425009ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.074088ms) +✔ readRunDocument reads only the three run documents (0.943201ms) +✔ a link inside the data root is followed (1.78009ms) +✔ a data root that is itself a link is trusted as configured (1.185862ms) +✔ a run directory linked out of the data root is never read (1.204155ms) +✔ a document linked out of the data root reads as null (1.549239ms) +✔ a runs directory linked out of the data root refuses (1.03995ms) +✔ a relative link that climbs out of the data root refuses (0.689295ms) +✔ a sibling whose name starts with the data root's name is outside it (0.923991ms) +✔ a link loop refuses instead of reading as missing (1.150588ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.729845ms) +✔ an unreadable run directory refuses instead of reading as missing (0.891325ms) +✔ a link to the data root's parent is outside it (1.221017ms) +✔ listRunIds sorts whatever order the directory returns (1.108483ms) +✔ the readers write nothing (3.377499ms) +✔ no pointer is null (2.369876ms) +✔ the pointer release.sh writes reads back (1.445943ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (4.334902ms) +✔ a pointer that is a directory refuses with exit 4 (0.757318ms) +✔ a state file linked out of the data root refuses (1.27317ms) +✔ a state directory linked out of the data root refuses (0.743687ms) +✔ a missing log is empty (0.463828ms) +✔ the log reads oldest first and counts malformed lines (1.107084ms) +✔ last must be a positive integer (0.692277ms) +✔ the state readers write nothing (1.18172ms) +✔ list prints each run in the established format (105.980567ms) +✔ show prints the run in the established format (115.012534ms) +✔ show of a missing run and an invalid id exit 4 as before (135.038631ms) +✔ list and show refuse a runs directory linked out of the data root (172.97353ms) +✔ show refuses a run linked out of the data root; list reports it unknown (197.370536ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 805.379529 + +✖ failing tests: + +test at packages/runs/tests/runs.test.mjs:75:1 +✖ readRunRecord is null for a missing run, a dangling link or a file (1.425009ms) + Error [RunsError]: cannot read /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-FPVVtO/data/runs/r-20260101T000100Z-bbbbbb: ENOTDIR + at readRunRecord (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:62:11) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:83:16) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + exitCode: 4 + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D14.diff b/agents/darkwing/work/queue-56-review/r1/mut/D14.diff new file mode 100644 index 00000000..38ce93f2 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D14.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/paths.mjs b/packages/runs/src/paths.mjs +index 1dbb5539..7ce9d52c 100644 +--- a/packages/runs/src/paths.mjs ++++ b/packages/runs/src/paths.mjs +@@ -24,7 +24,7 @@ export function resolveInside(dataRoot, ...parts) { + let real; + try { + root = fs.realpathSync(dataRoot); +- real = fs.realpathSync(target); ++ real = path.resolve(target); + } catch (error) { + if (isMissing(error)) return null; + throw new RunsError(`cannot resolve ${target}: ${error.code ?? error.message}`); diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D14.txt b/agents/darkwing/work/queue-56-review/r1/mut/D14.txt new file mode 100644 index 00000000..614b9821 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D14.txt @@ -0,0 +1,334 @@ +✔ isRunId accepts the run id shape and nothing else (2.337061ms) +✔ a missing data root or runs directory lists nothing (2.812348ms) +✔ runs as a regular file lists nothing, as before (0.989212ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.36075ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.67149ms) +✔ readRunRecord returns documents and artifacts in directory order (2.491353ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.899895ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.568632ms) +✔ readRunDocument reads only the three run documents (1.626551ms) +✔ a link inside the data root is followed (1.731397ms) +✖ a data root that is itself a link is trusted as configured (1.465017ms) +✖ a run directory linked out of the data root is never read (3.090379ms) +✖ a document linked out of the data root reads as null (1.761344ms) +✖ a runs directory linked out of the data root refuses (0.967405ms) +✖ a relative link that climbs out of the data root refuses (1.918539ms) +✖ a sibling whose name starts with the data root's name is outside it (1.08471ms) +✔ a link loop refuses instead of reading as missing (1.050719ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.697011ms) +✔ an unreadable run directory refuses instead of reading as missing (0.878691ms) +✖ a link to the data root's parent is outside it (0.945372ms) +✔ listRunIds sorts whatever order the directory returns (1.249209ms) +✔ the readers write nothing (2.766612ms) +✖ no pointer is null (3.426697ms) +✔ the pointer release.sh writes reads back (2.049083ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.05565ms) +✔ a pointer that is a directory refuses with exit 4 (1.036013ms) +✖ a state file linked out of the data root refuses (2.970028ms) +✖ a state directory linked out of the data root refuses (2.142321ms) +✖ a missing log is empty (0.990974ms) +✔ the log reads oldest first and counts malformed lines (2.655752ms) +✔ last must be a positive integer (0.876981ms) +✔ the state readers write nothing (2.744ms) +✔ list prints each run in the established format (170.137522ms) +✔ show prints the run in the established format (120.109446ms) +✔ show of a missing run and an invalid id exit 4 as before (151.012044ms) +✖ list and show refuse a runs directory linked out of the data root (124.06692ms) +✖ show refuses a run linked out of the data root; list reports it unknown (140.926544ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 24 +ℹ fail 13 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 811.148685 + +✖ failing tests: + +test at packages/runs/tests/runs.test.mjs:111:1 +✖ a data root that is itself a link is trusted as configured (1.465017ms) + Error [RunsError]: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-4NH1n7/alias/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-4NH1n7/data) + at resolveInside (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:33:11) + at listRunIds (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:20:16) + at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:44:10) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:116:20) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + exitCode: 4 + } + +test at packages/runs/tests/runs.test.mjs:119:1 +✖ a run directory linked out of the data root is never read (3.090379ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + [ + { + + result: { + + durationMs: 1000, + + exitCode: 0, + + expectedExact: null, + + finishedAt: '2026-01-01T00:00:01.000Z', + + missionId: null, + + model: 'm', + + provider: 'zai', + + reason: null, + + request: 'hi', + + response: 'hi', + + runId: 'r-20260101T000000Z-aaaaaa', + + runVersion: 1, + + session: null, + + sessionForkFrom: null, + + signal: null, + + startedAt: '2026-01-01T00:00:00.000Z', + + status: 'succeeded', + + taskId: 't-one', + + tools: null, + + workspace: null + + }, + - result: null, + runId: 'r-20260101T000000Z-aaaaaa' + } + ] + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:125:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [ { runId: 'r-20260101T000000Z-aaaaaa', result: [Object] } ], + expected: [ { runId: 'r-20260101T000000Z-aaaaaa', result: null } ], + operator: 'deepStrictEqual', + diff: 'simple' + } + +test at packages/runs/tests/runs.test.mjs:129:1 +✖ a document linked out of the data root reads as null (1.761344ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + actual - expected + + + { + + durationMs: 1000, + + exitCode: 0, + + expectedExact: null, + + finishedAt: '2026-01-01T00:00:01.000Z', + + missionId: null, + + model: 'm', + + provider: 'zai', + + reason: null, + + request: 'hi', + + response: 'hi', + + runId: 'r-20260101T000000Z-aaaaaa', + + runVersion: 1, + + session: null, + + sessionForkFrom: null, + + signal: null, + + startedAt: '2026-01-01T00:00:00.000Z', + + status: 'succeeded', + + taskId: 't-one', + + tools: null, + + workspace: null + + } + - null + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:137:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: { runVersion: 1, runId: 'r-20260101T000000Z-aaaaaa', taskId: 't-one', missionId: null, status: 'succeeded', reason: null, request: 'hi', response: 'hi', expectedExact: null, workspace: null, tools: null, session: null, sessionForkFrom: null, exitCode: 0, signal: null, provider: 'zai', model: 'm', startedAt: '2026-01-01T00:00:00.000Z', finishedAt: '2026-01-01T00:00:01.000Z', durationMs: 1000 }, + expected: null, + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/runs/tests/runs.test.mjs:143:1 +✖ a runs directory linked out of the data root refuses (0.967405ms) + AssertionError [ERR_ASSERTION]: Missing expected exception. + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:147:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + expected: /runs resolves outside the data root/, + operator: 'throws', + diff: 'simple' + } + +test at packages/runs/tests/runs.test.mjs:152:1 +✖ a relative link that climbs out of the data root refuses (1.918539ms) + AssertionError [ERR_ASSERTION]: Missing expected exception. + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:156:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + expected: /resolves outside the data root/, + operator: 'throws', + diff: 'simple' + } + +test at packages/runs/tests/runs.test.mjs:159:1 +✖ a sibling whose name starts with the data root's name is outside it (1.08471ms) + AssertionError [ERR_ASSERTION]: Missing expected exception. + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:165:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + expected: /resolves outside the data root/, + operator: 'throws', + diff: 'simple' + } + +test at packages/runs/tests/runs.test.mjs:201:1 +✖ a link to the data root's parent is outside it (0.945372ms) + AssertionError [ERR_ASSERTION]: Missing expected exception. + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:205:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + expected: /resolves outside the data root/, + operator: 'throws', + diff: 'simple' + } + +test at packages/runs/tests/state.test.mjs:18:1 +✖ no pointer is null (3.426697ms) + Error [RunsError]: cannot read /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-jLz66S/data/state/active.json: ENOENT + at readStateFile (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/state.mjs:21:11) + at readActivePointer (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/state.mjs:29:17) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:20:16) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.start (node:internal/test_runner/test:1262:17) + at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) { + exitCode: 4 + } + +test at packages/runs/tests/state.test.mjs:57:1 +✖ a state file linked out of the data root refuses (2.970028ms) + AssertionError [ERR_ASSERTION]: Missing expected exception. + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:64:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + expected: /resolves outside the data root/, + operator: 'throws', + diff: 'simple' + } + +test at packages/runs/tests/state.test.mjs:68:1 +✖ a state directory linked out of the data root refuses (2.142321ms) + AssertionError [ERR_ASSERTION]: Missing expected exception. + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:72:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + expected: /state\/active.json resolves outside the data root/, + operator: 'throws', + diff: 'simple' + } + +test at packages/runs/tests/state.test.mjs:75:1 +✖ a missing log is empty (0.990974ms) + Error [RunsError]: cannot read /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-2x3xPI/data/state/activation-log.jsonl: ENOENT + at readStateFile (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/state.mjs:21:11) + at readActivationLog (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/state.mjs:71:17) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:77:20) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + exitCode: 4 + } + +test at packages/runs/tests/task-cli.test.mjs:70:1 +✖ list and show refuse a runs directory linked out of the data root (124.06692ms) + AssertionError [ERR_ASSERTION]: list + + 0 !== 4 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/task-cli.test.mjs:76:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: 0, + expected: 4, + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/runs/tests/task-cli.test.mjs:82:1 +✖ show refuses a run linked out of the data root; list reports it unknown (140.926544ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 0 !== 4 + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/task-cli.test.mjs:88:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 0, + expected: 4, + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D15.diff b/agents/darkwing/work/queue-56-review/r1/mut/D15.diff new file mode 100644 index 00000000..34ccf6d7 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D15.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/paths.mjs b/packages/runs/src/paths.mjs +index 1dbb5539..2cbffca6 100644 +--- a/packages/runs/src/paths.mjs ++++ b/packages/runs/src/paths.mjs +@@ -23,7 +23,7 @@ export function resolveInside(dataRoot, ...parts) { + let root; + let real; + try { +- root = fs.realpathSync(dataRoot); ++ root = path.resolve(dataRoot); + real = fs.realpathSync(target); + } catch (error) { + if (isMissing(error)) return null; diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D15.txt b/agents/darkwing/work/queue-56-review/r1/mut/D15.txt new file mode 100644 index 00000000..3d0ea7e9 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D15.txt @@ -0,0 +1,63 @@ +✔ isRunId accepts the run id shape and nothing else (1.225949ms) +✔ a missing data root or runs directory lists nothing (1.892082ms) +✔ runs as a regular file lists nothing, as before (0.747282ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.931027ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.487142ms) +✔ readRunRecord returns documents and artifacts in directory order (1.153245ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (0.788032ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.781425ms) +✔ readRunDocument reads only the three run documents (0.64425ms) +✔ a link inside the data root is followed (1.443248ms) +✖ a data root that is itself a link is trusted as configured (0.723306ms) +✔ a run directory linked out of the data root is never read (0.774806ms) +✔ a document linked out of the data root reads as null (1.18996ms) +✔ a runs directory linked out of the data root refuses (0.624807ms) +✔ a relative link that climbs out of the data root refuses (0.520406ms) +✔ a sibling whose name starts with the data root's name is outside it (0.623168ms) +✔ a link loop refuses instead of reading as missing (0.641501ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.470743ms) +✔ an unreadable run directory refuses instead of reading as missing (0.559037ms) +✔ a link to the data root's parent is outside it (0.503187ms) +✔ listRunIds sorts whatever order the directory returns (16.993379ms) +✔ the readers write nothing (3.04089ms) +✔ no pointer is null (2.102694ms) +✔ the pointer release.sh writes reads back (1.420335ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (99.446402ms) +✔ a pointer that is a directory refuses with exit 4 (1.965912ms) +✔ a state file linked out of the data root refuses (1.584736ms) +✔ a state directory linked out of the data root refuses (0.926403ms) +✔ a missing log is empty (0.585862ms) +✔ the log reads oldest first and counts malformed lines (1.76685ms) +✔ last must be a positive integer (0.522534ms) +✔ the state readers write nothing (1.138156ms) +✔ list prints each run in the established format (99.14821ms) +✔ show prints the run in the established format (112.530433ms) +✔ show of a missing run and an invalid id exit 4 as before (168.188718ms) +✔ list and show refuse a runs directory linked out of the data root (200.199186ms) +✔ show refuses a run linked out of the data root; list reports it unknown (210.660658ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 877.697783 + +✖ failing tests: + +test at packages/runs/tests/runs.test.mjs:111:1 +✖ a data root that is itself a link is trusted as configured (0.723306ms) + Error [RunsError]: /home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-5lxeUT/alias/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/tmp/mosaic-runs-test-5lxeUT/alias) + at resolveInside (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/paths.mjs:33:11) + at listRunIds (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:20:16) + at listRunRecords (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/src/runs.mjs:44:10) + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:116:20) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + exitCode: 4 + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D16.diff b/agents/darkwing/work/queue-56-review/r1/mut/D16.diff new file mode 100644 index 00000000..da349b88 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D16.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs +index 03730c33..08a71fab 100644 +--- a/packages/runs/src/runs.mjs ++++ b/packages/runs/src/runs.mjs +@@ -2,7 +2,7 @@ import fs from "node:fs"; + import { RunsError } from "./errors.mjs"; + import { RUNS_DIRNAME, isMissing, readJsonObject, resolveInside } from "./paths.mjs"; + +-export const RUN_ID_PATTERN = /^r-[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/; ++export const RUN_ID_PATTERN = /^r-[A-Za-z0-9][A-Za-z0-9._-]{0,64}$/; + export const RUN_DOCUMENTS = ["result.json", "task.json", "mission.json"]; + + export function isRunId(value) { diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D16.txt b/agents/darkwing/work/queue-56-review/r1/mut/D16.txt new file mode 100644 index 00000000..a432a84c --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D16.txt @@ -0,0 +1,66 @@ +✖ isRunId accepts the run id shape and nothing else (2.621121ms) +✔ a missing data root or runs directory lists nothing (2.873428ms) +✔ runs as a regular file lists nothing, as before (0.877432ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.2193ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (4.17104ms) +✔ readRunRecord returns documents and artifacts in directory order (2.167047ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.610572ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.237909ms) +✔ readRunDocument reads only the three run documents (1.490464ms) +✔ a link inside the data root is followed (2.047317ms) +✔ a data root that is itself a link is trusted as configured (1.310886ms) +✔ a run directory linked out of the data root is never read (1.375476ms) +✔ a document linked out of the data root reads as null (1.919519ms) +✔ a runs directory linked out of the data root refuses (1.177495ms) +✔ a relative link that climbs out of the data root refuses (0.809767ms) +✔ a sibling whose name starts with the data root's name is outside it (0.918443ms) +✔ a link loop refuses instead of reading as missing (1.269903ms) +✔ an unreadable runs directory refuses instead of listing nothing (1.13428ms) +✔ an unreadable run directory refuses instead of reading as missing (1.208613ms) +✔ a link to the data root's parent is outside it (1.309226ms) +✔ listRunIds sorts whatever order the directory returns (1.665016ms) +✔ the readers write nothing (4.268303ms) +✔ no pointer is null (2.482055ms) +✔ the pointer release.sh writes reads back (1.622475ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.093312ms) +✔ a pointer that is a directory refuses with exit 4 (1.37517ms) +✔ a state file linked out of the data root refuses (1.304846ms) +✔ a state directory linked out of the data root refuses (0.707381ms) +✔ a missing log is empty (0.514771ms) +✔ the log reads oldest first and counts malformed lines (1.170055ms) +✔ last must be a positive integer (0.690868ms) +✔ the state readers write nothing (1.127808ms) +✔ list prints each run in the established format (111.188746ms) +✔ show prints the run in the established format (107.486029ms) +✔ show of a missing run and an invalid id exit 4 as before (143.908228ms) +✔ list and show refuse a runs directory linked out of the data root (191.94812ms) +✔ show refuses a run linked out of the data root; list reports it unknown (212.7919ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 858.033888 + +✖ failing tests: + +test at packages/runs/tests/runs.test.mjs:13:1 +✖ isRunId accepts the run id shape and nothing else (2.621121ms) + AssertionError [ERR_ASSERTION]: r-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + true !== false + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:16:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.start (node:internal/test_runner/test:1262:17) + at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: true, + expected: false, + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D17.diff b/agents/darkwing/work/queue-56-review/r1/mut/D17.diff new file mode 100644 index 00000000..16674d0a --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D17.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs +index 03730c33..db7d57c1 100644 +--- a/packages/runs/src/runs.mjs ++++ b/packages/runs/src/runs.mjs +@@ -43,7 +43,7 @@ export function readRunDocument(dataRoot, runId, name) { + export function listRunRecords(dataRoot) { + return listRunIds(dataRoot).map((runId) => ({ + runId, +- result: readJsonObject(dataRoot, RUNS_DIRNAME, runId, "result.json"), ++ result: readRunDocument(dataRoot, runId, "result.json"), + })); + } + diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D17.txt b/agents/darkwing/work/queue-56-review/r1/mut/D17.txt new file mode 100644 index 00000000..3031ad26 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D17.txt @@ -0,0 +1,45 @@ +✔ isRunId accepts the run id shape and nothing else (1.84367ms) +✔ a missing data root or runs directory lists nothing (2.700807ms) +✔ runs as a regular file lists nothing, as before (1.033316ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.32646ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.42376ms) +✔ readRunRecord returns documents and artifacts in directory order (1.65341ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.089868ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.018263ms) +✔ readRunDocument reads only the three run documents (2.607684ms) +✔ a link inside the data root is followed (1.72714ms) +✔ a data root that is itself a link is trusted as configured (1.101493ms) +✔ a run directory linked out of the data root is never read (1.204336ms) +✔ a document linked out of the data root reads as null (2.271677ms) +✔ a runs directory linked out of the data root refuses (0.930102ms) +✔ a relative link that climbs out of the data root refuses (0.643793ms) +✔ a sibling whose name starts with the data root's name is outside it (0.780072ms) +✔ a link loop refuses instead of reading as missing (1.056981ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.657066ms) +✔ an unreadable run directory refuses instead of reading as missing (0.82135ms) +✔ a link to the data root's parent is outside it (0.603085ms) +✔ listRunIds sorts whatever order the directory returns (1.157629ms) +✔ the readers write nothing (3.625933ms) +✔ no pointer is null (2.573356ms) +✔ the pointer release.sh writes reads back (1.601548ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.886359ms) +✔ a pointer that is a directory refuses with exit 4 (1.00578ms) +✔ a state file linked out of the data root refuses (1.827811ms) +✔ a state directory linked out of the data root refuses (0.966807ms) +✔ a missing log is empty (0.590111ms) +✔ the log reads oldest first and counts malformed lines (1.749904ms) +✔ last must be a positive integer (0.741643ms) +✔ the state readers write nothing (1.380717ms) +✔ list prints each run in the established format (109.05177ms) +✔ show prints the run in the established format (106.424344ms) +✔ show of a missing run and an invalid id exit 4 as before (151.998567ms) +✔ list and show refuse a runs directory linked out of the data root (198.84273ms) +✔ show refuses a run linked out of the data root; list reports it unknown (214.31565ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 37 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 861.341071 diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D18.diff b/agents/darkwing/work/queue-56-review/r1/mut/D18.diff new file mode 100644 index 00000000..eb1c3ba3 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D18.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs +index a92c8713..067bd09e 100644 +--- a/packages/runs/src/state.mjs ++++ b/packages/runs/src/state.mjs +@@ -73,7 +73,7 @@ export function readActivationLog(dataRoot, { last } = {}) { + const entries = []; + let malformed = 0; + for (const line of state.text.split("\n")) { +- if (line.trim() === "") continue; ++ if (line === "") continue; + const entry = logEntry(line); + if (entry === null) malformed += 1; + else entries.push(entry); diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D18.txt b/agents/darkwing/work/queue-56-review/r1/mut/D18.txt new file mode 100644 index 00000000..4ac09596 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D18.txt @@ -0,0 +1,79 @@ +✔ isRunId accepts the run id shape and nothing else (1.81005ms) +✔ a missing data root or runs directory lists nothing (3.788851ms) +✔ runs as a regular file lists nothing, as before (1.332528ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.521814ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (4.886328ms) +✔ readRunRecord returns documents and artifacts in directory order (3.564755ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (2.859036ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.951484ms) +✔ readRunDocument reads only the three run documents (1.289383ms) +✔ a link inside the data root is followed (3.726081ms) +✔ a data root that is itself a link is trusted as configured (5.725889ms) +✔ a run directory linked out of the data root is never read (2.611536ms) +✔ a document linked out of the data root reads as null (2.941983ms) +✔ a runs directory linked out of the data root refuses (1.42401ms) +✔ a relative link that climbs out of the data root refuses (0.981488ms) +✔ a sibling whose name starts with the data root's name is outside it (1.093183ms) +✔ a link loop refuses instead of reading as missing (1.426419ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.900191ms) +✔ an unreadable run directory refuses instead of reading as missing (1.392808ms) +✔ a link to the data root's parent is outside it (0.919184ms) +✔ listRunIds sorts whatever order the directory returns (1.382679ms) +✔ the readers write nothing (3.80633ms) +✔ no pointer is null (3.365628ms) +✔ the pointer release.sh writes reads back (2.160411ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (4.729941ms) +✔ a pointer that is a directory refuses with exit 4 (2.975348ms) +✔ a state file linked out of the data root refuses (1.960951ms) +✔ a state directory linked out of the data root refuses (1.362152ms) +✔ a missing log is empty (0.915277ms) +✖ the log reads oldest first and counts malformed lines (4.787537ms) +✔ last must be a positive integer (1.174335ms) +✔ the state readers write nothing (8.296235ms) +✔ list prints each run in the established format (135.967139ms) +✔ show prints the run in the established format (126.514675ms) +✔ show of a missing run and an invalid id exit 4 as before (248.881535ms) +✔ list and show refuse a runs directory linked out of the data root (178.634661ms) +✔ show refuses a run linked out of the data root; list reports it unknown (318.758144ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1106.083123 + +✖ failing tests: + +test at packages/runs/tests/state.test.mjs:80:1 +✖ the log reads oldest first and counts malformed lines (4.787537ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + ... Skipped lines + + { + entries: [ + { + at: '2026-09-03T20:57:00Z', + event: 'package', + ... + ], + + malformed: 6 + - malformed: 5 + } + + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:101:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: { entries: [ [Object], [Object], [Object], [Object] ], malformed: 6 }, + expected: { entries: [ [Object], [Object], [Object], [Object] ], malformed: 5 }, + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D19.diff b/agents/darkwing/work/queue-56-review/r1/mut/D19.diff new file mode 100644 index 00000000..ebb385f6 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D19.diff @@ -0,0 +1,12 @@ +diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs +index 03730c33..d8cb0e58 100644 +--- a/packages/runs/src/runs.mjs ++++ b/packages/runs/src/runs.mjs +@@ -32,7 +32,6 @@ export function listRunIds(dataRoot) { + // One of RUN_DOCUMENTS from a run, or null when it is missing, unreadable, + // not a JSON object or outside the data root. + export function readRunDocument(dataRoot, runId, name) { +- requireRunId(runId); + if (!RUN_DOCUMENTS.includes(name)) throw new RunsError(`unknown run document: ${JSON.stringify(name)}`); + return readJsonObject(dataRoot, RUNS_DIRNAME, runId, name); + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D19.txt b/agents/darkwing/work/queue-56-review/r1/mut/D19.txt new file mode 100644 index 00000000..693404f6 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D19.txt @@ -0,0 +1,64 @@ +✔ isRunId accepts the run id shape and nothing else (1.177262ms) +✔ a missing data root or runs directory lists nothing (2.120403ms) +✔ runs as a regular file lists nothing, as before (0.678388ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.861957ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.547546ms) +✔ readRunRecord returns documents and artifacts in directory order (1.538135ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.13107ms) +✖ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.271159ms) +✔ readRunDocument reads only the three run documents (0.654773ms) +✔ a link inside the data root is followed (1.097525ms) +✔ a data root that is itself a link is trusted as configured (0.753622ms) +✔ a run directory linked out of the data root is never read (0.834684ms) +✔ a document linked out of the data root reads as null (1.039271ms) +✔ a runs directory linked out of the data root refuses (0.69181ms) +✔ a relative link that climbs out of the data root refuses (1.855925ms) +✔ a sibling whose name starts with the data root's name is outside it (1.188475ms) +✔ a link loop refuses instead of reading as missing (1.134003ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.730721ms) +✔ an unreadable run directory refuses instead of reading as missing (0.863693ms) +✔ a link to the data root's parent is outside it (0.64587ms) +✔ listRunIds sorts whatever order the directory returns (1.228953ms) +✔ the readers write nothing (4.005022ms) +✔ no pointer is null (3.229517ms) +✔ the pointer release.sh writes reads back (2.000427ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (22.490669ms) +✔ a pointer that is a directory refuses with exit 4 (1.097015ms) +✔ a state file linked out of the data root refuses (3.625438ms) +✔ a state directory linked out of the data root refuses (1.557756ms) +✔ a missing log is empty (0.857274ms) +✔ the log reads oldest first and counts malformed lines (1.909144ms) +✔ last must be a positive integer (0.916328ms) +✔ the state readers write nothing (2.334238ms) +✔ list prints each run in the established format (112.749358ms) +✔ show prints the run in the established format (93.106249ms) +✔ show of a missing run and an invalid id exit 4 as before (149.979418ms) +✔ list and show refuse a runs directory linked out of the data root (171.947155ms) +✔ show refuses a run linked out of the data root; list reports it unknown (302.989078ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 900.360942 + +✖ failing tests: + +test at packages/runs/tests/runs.test.mjs:86:1 +✖ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.271159ms) + AssertionError [ERR_ASSERTION]: Missing expected exception (RunsError). + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/runs.test.mjs:90:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + operator: 'throws', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D20.diff b/agents/darkwing/work/queue-56-review/r1/mut/D20.diff new file mode 100644 index 00000000..fee8da7c --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D20.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/runs.mjs b/packages/runs/src/runs.mjs +index 03730c33..3814b6a5 100644 +--- a/packages/runs/src/runs.mjs ++++ b/packages/runs/src/runs.mjs +@@ -26,7 +26,7 @@ export function listRunIds(dataRoot) { + if (isMissing(error)) return []; + throw new RunsError(`cannot read ${root}: ${error.code ?? error.message}`); + } +- return names.filter((name) => name.startsWith("r-")).sort(); ++ return names.filter(isRunId).sort(); + } + + // One of RUN_DOCUMENTS from a run, or null when it is missing, unreadable, diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D20.txt b/agents/darkwing/work/queue-56-review/r1/mut/D20.txt new file mode 100644 index 00000000..8b6bee23 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D20.txt @@ -0,0 +1,45 @@ +✔ isRunId accepts the run id shape and nothing else (1.306378ms) +✔ a missing data root or runs directory lists nothing (2.195703ms) +✔ runs as a regular file lists nothing, as before (0.832745ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.032055ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.96098ms) +✔ readRunRecord returns documents and artifacts in directory order (1.386366ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.079913ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.059646ms) +✔ readRunDocument reads only the three run documents (0.919524ms) +✔ a link inside the data root is followed (1.7667ms) +✔ a data root that is itself a link is trusted as configured (1.154799ms) +✔ a run directory linked out of the data root is never read (1.194447ms) +✔ a document linked out of the data root reads as null (1.545639ms) +✔ a runs directory linked out of the data root refuses (1.012007ms) +✔ a relative link that climbs out of the data root refuses (0.840459ms) +✔ a sibling whose name starts with the data root's name is outside it (0.862225ms) +✔ a link loop refuses instead of reading as missing (1.091533ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.700403ms) +✔ an unreadable run directory refuses instead of reading as missing (0.823368ms) +✔ a link to the data root's parent is outside it (0.661858ms) +✔ listRunIds sorts whatever order the directory returns (1.208556ms) +✔ the readers write nothing (3.397935ms) +✔ no pointer is null (2.922658ms) +✔ the pointer release.sh writes reads back (1.955593ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.059019ms) +✔ a pointer that is a directory refuses with exit 4 (0.993624ms) +✔ a state file linked out of the data root refuses (2.525011ms) +✔ a state directory linked out of the data root refuses (1.000341ms) +✔ a missing log is empty (0.67567ms) +✔ the log reads oldest first and counts malformed lines (1.536433ms) +✔ last must be a positive integer (0.791281ms) +✔ the state readers write nothing (1.583337ms) +✔ list prints each run in the established format (111.618545ms) +✔ show prints the run in the established format (86.235796ms) +✔ show of a missing run and an invalid id exit 4 as before (147.991565ms) +✔ list and show refuse a runs directory linked out of the data root (221.002247ms) +✔ show refuses a run linked out of the data root; list reports it unknown (185.706284ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 37 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 897.558738 diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D21.diff b/agents/darkwing/work/queue-56-review/r1/mut/D21.diff new file mode 100644 index 00000000..6fdc9063 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D21.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs +index a92c8713..1789e568 100644 +--- a/packages/runs/src/state.mjs ++++ b/packages/runs/src/state.mjs +@@ -39,7 +39,7 @@ export function readActivePointer(dataRoot) { + for (const key of Object.keys(pointer)) { + if (!POINTER_KEYS.includes(key)) throw invalid(`has an unsupported key: "${key}"`); + } +- if (pointer.pointerVersion !== 1) throw invalid(`has unsupported pointerVersion ${JSON.stringify(pointer.pointerVersion)}`); ++ if (false) throw invalid(`has unsupported pointerVersion ${JSON.stringify(pointer.pointerVersion)}`); + for (const key of ["release", "imageTag", "activatedAt"]) { + if (!isNonEmptyString(pointer[key])) throw invalid(`needs a non-empty string "${key}"`); + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D21.txt b/agents/darkwing/work/queue-56-review/r1/mut/D21.txt new file mode 100644 index 00000000..0883f02d --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D21.txt @@ -0,0 +1,64 @@ +✔ isRunId accepts the run id shape and nothing else (1.127867ms) +✔ a missing data root or runs directory lists nothing (1.72466ms) +✔ runs as a regular file lists nothing, as before (0.646415ms) +✔ listRunIds keeps r- names only, sorted oldest first (0.82023ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.39311ms) +✔ readRunRecord returns documents and artifacts in directory order (1.164002ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (0.814071ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.453894ms) +✔ readRunDocument reads only the three run documents (0.658026ms) +✔ a link inside the data root is followed (1.155118ms) +✔ a data root that is itself a link is trusted as configured (0.793186ms) +✔ a run directory linked out of the data root is never read (0.791204ms) +✔ a document linked out of the data root reads as null (0.969944ms) +✔ a runs directory linked out of the data root refuses (0.658788ms) +✔ a relative link that climbs out of the data root refuses (0.519731ms) +✔ a sibling whose name starts with the data root's name is outside it (0.554988ms) +✔ a link loop refuses instead of reading as missing (0.740597ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.508563ms) +✔ an unreadable run directory refuses instead of reading as missing (0.585049ms) +✔ a link to the data root's parent is outside it (0.436398ms) +✔ listRunIds sorts whatever order the directory returns (0.926292ms) +✔ the readers write nothing (2.24403ms) +✔ no pointer is null (2.531076ms) +✔ the pointer release.sh writes reads back (1.633448ms) +✖ a pointer that isn't the version 1 shape refuses with exit 2 (130.614238ms) +✔ a pointer that is a directory refuses with exit 4 (0.786002ms) +✔ a state file linked out of the data root refuses (2.341036ms) +✔ a state directory linked out of the data root refuses (0.805877ms) +✔ a missing log is empty (0.47975ms) +✔ the log reads oldest first and counts malformed lines (1.125972ms) +✔ last must be a positive integer (0.54587ms) +✔ the state readers write nothing (1.23264ms) +✔ list prints each run in the established format (95.611062ms) +✔ show prints the run in the established format (94.055273ms) +✔ show of a missing run and an invalid id exit 4 as before (138.36289ms) +✔ list and show refuse a runs directory linked out of the data root (184.218135ms) +✔ show refuses a run linked out of the data root; list reports it unknown (314.21614ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 897.837373 + +✖ failing tests: + +test at packages/runs/tests/state.test.mjs:32:1 +✖ a pointer that isn't the version 1 shape refuses with exit 2 (130.614238ms) + AssertionError [ERR_ASSERTION]: Missing expected exception: /unsupported pointerVersion 2/ + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:47:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + operator: 'throws', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D22.diff b/agents/darkwing/work/queue-56-review/r1/mut/D22.diff new file mode 100644 index 00000000..e6cf24d2 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D22.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs +index a92c8713..c76edde2 100644 +--- a/packages/runs/src/state.mjs ++++ b/packages/runs/src/state.mjs +@@ -55,7 +55,7 @@ function logEntry(line) { + } + if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return null; + if (Object.keys(entry).some((key) => !LOG_KEYS.includes(key))) return null; +- if (!["at", "event", "release", "imageTag"].every((key) => typeof entry[key] === "string")) return null; ++ if (!["at", "event", "release"].every((key) => typeof entry[key] === "string")) return null; + if (entry.note !== undefined && typeof entry.note !== "string") return null; + return entry; + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D22.txt b/agents/darkwing/work/queue-56-review/r1/mut/D22.txt new file mode 100644 index 00000000..cbbbf443 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D22.txt @@ -0,0 +1,45 @@ +✔ isRunId accepts the run id shape and nothing else (1.834258ms) +✔ a missing data root or runs directory lists nothing (2.636105ms) +✔ runs as a regular file lists nothing, as before (2.901636ms) +✔ listRunIds keeps r- names only, sorted oldest first (3.100526ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (6.571513ms) +✔ readRunRecord returns documents and artifacts in directory order (3.744909ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (2.315471ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (2.654758ms) +✔ readRunDocument reads only the three run documents (1.530565ms) +✔ a link inside the data root is followed (3.351352ms) +✔ a data root that is itself a link is trusted as configured (3.308438ms) +✔ a run directory linked out of the data root is never read (1.199258ms) +✔ a document linked out of the data root reads as null (4.723514ms) +✔ a runs directory linked out of the data root refuses (2.543252ms) +✔ a relative link that climbs out of the data root refuses (0.642465ms) +✔ a sibling whose name starts with the data root's name is outside it (0.865087ms) +✔ a link loop refuses instead of reading as missing (2.746857ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.67741ms) +✔ an unreadable run directory refuses instead of reading as missing (0.735708ms) +✔ a link to the data root's parent is outside it (0.592559ms) +✔ listRunIds sorts whatever order the directory returns (2.772116ms) +✔ the readers write nothing (5.349486ms) +✔ no pointer is null (6.038816ms) +✔ the pointer release.sh writes reads back (2.191058ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (4.422889ms) +✔ a pointer that is a directory refuses with exit 4 (3.41713ms) +✔ a state file linked out of the data root refuses (2.798861ms) +✔ a state directory linked out of the data root refuses (2.478415ms) +✔ a missing log is empty (1.394344ms) +✔ the log reads oldest first and counts malformed lines (1.455927ms) +✔ last must be a positive integer (2.396006ms) +✔ the state readers write nothing (1.735056ms) +✔ list prints each run in the established format (131.488575ms) +✔ show prints the run in the established format (92.166358ms) +✔ show of a missing run and an invalid id exit 4 as before (158.462467ms) +✔ list and show refuse a runs directory linked out of the data root (170.034985ms) +✔ show refuses a run linked out of the data root; list reports it unknown (201.838401ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 37 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 872.50546 diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D23.diff b/agents/darkwing/work/queue-56-review/r1/mut/D23.diff new file mode 100644 index 00000000..f25f1d02 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D23.diff @@ -0,0 +1,13 @@ +diff --git a/packages/runs/src/state.mjs b/packages/runs/src/state.mjs +index a92c8713..49d8c1fd 100644 +--- a/packages/runs/src/state.mjs ++++ b/packages/runs/src/state.mjs +@@ -65,7 +65,7 @@ function logEntry(line) { + // release.sh rollback skips them. A missing log is empty. With last, only + // the newest last well-formed entries are returned. + export function readActivationLog(dataRoot, { last } = {}) { +- if (last !== undefined && (!Number.isInteger(last) || last < 1)) { ++ if (last !== undefined && (!Number.isInteger(last) || last < 0)) { + throw new RunsError(`last must be a positive integer (got ${JSON.stringify(last)})`); + } + const state = readStateFile(dataRoot, ACTIVATION_LOG_FILE); diff --git a/agents/darkwing/work/queue-56-review/r1/mut/D23.txt b/agents/darkwing/work/queue-56-review/r1/mut/D23.txt new file mode 100644 index 00000000..fa677896 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/D23.txt @@ -0,0 +1,65 @@ +✔ isRunId accepts the run id shape and nothing else (2.040623ms) +✔ a missing data root or runs directory lists nothing (3.167511ms) +✔ runs as a regular file lists nothing, as before (1.148056ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.529862ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (4.035385ms) +✔ readRunRecord returns documents and artifacts in directory order (2.356077ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.382285ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.21881ms) +✔ readRunDocument reads only the three run documents (1.081942ms) +✔ a link inside the data root is followed (1.529533ms) +✔ a data root that is itself a link is trusted as configured (1.029457ms) +✔ a run directory linked out of the data root is never read (1.182624ms) +✔ a document linked out of the data root reads as null (1.55228ms) +✔ a runs directory linked out of the data root refuses (0.964271ms) +✔ a relative link that climbs out of the data root refuses (0.735934ms) +✔ a sibling whose name starts with the data root's name is outside it (0.835571ms) +✔ a link loop refuses instead of reading as missing (1.106386ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.726369ms) +✔ an unreadable run directory refuses instead of reading as missing (0.851219ms) +✔ a link to the data root's parent is outside it (0.763768ms) +✔ listRunIds sorts whatever order the directory returns (1.218202ms) +✔ the readers write nothing (3.280544ms) +✔ no pointer is null (2.733337ms) +✔ the pointer release.sh writes reads back (1.378784ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (5.183544ms) +✔ a pointer that is a directory refuses with exit 4 (1.322104ms) +✔ a state file linked out of the data root refuses (1.28962ms) +✔ a state directory linked out of the data root refuses (0.633332ms) +✔ a missing log is empty (0.439431ms) +✔ the log reads oldest first and counts malformed lines (0.988303ms) +✖ last must be a positive integer (1.077906ms) +✔ the state readers write nothing (1.24199ms) +✔ list prints each run in the established format (110.647803ms) +✔ show prints the run in the established format (110.994361ms) +✔ show of a missing run and an invalid id exit 4 as before (129.235851ms) +✔ list and show refuse a runs directory linked out of the data root (177.07234ms) +✔ show refuses a run linked out of the data root; list reports it unknown (199.262239ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 36 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 806.760074 + +✖ failing tests: + +test at packages/runs/tests/state.test.mjs:106:1 +✖ last must be a positive integer (1.077906ms) + AssertionError [ERR_ASSERTION]: Missing expected exception: 0 + at TestContext. (file:///home/jwoltje/darkwing-scratch/r56a/mutwt/packages/runs/tests/state.test.mjs:109:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: undefined, + expected: /last must be a positive integer/, + operator: 'throws', + diff: 'simple' + } diff --git a/agents/darkwing/work/queue-56-review/r1/mut/manifest-after.txt b/agents/darkwing/work/queue-56-review/r1/mut/manifest-after.txt new file mode 100644 index 00000000..5a406f60 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/manifest-after.txt @@ -0,0 +1,15 @@ +agents/rocko/work/queue-56/byte-check.sh: OK +agents/rocko/work/queue-56/delta-check.sh: OK +agents/rocko/work/queue-56/seed.sh: OK +packages/runs/package.json: OK +packages/runs/README.md: OK +packages/runs/src/errors.mjs: OK +packages/runs/src/index.mjs: OK +packages/runs/src/paths.mjs: OK +packages/runs/src/runs.mjs: OK +packages/runs/src/state.mjs: OK +packages/runs/tests/helpers.mjs: OK +packages/runs/tests/runs.test.mjs: OK +packages/runs/tests/state.test.mjs: OK +packages/runs/tests/task-cli.test.mjs: OK +scripts/mosaic-task.mjs: OK diff --git a/agents/darkwing/work/queue-56-review/r1/mut/mutate.py b/agents/darkwing/work/queue-56-review/r1/mut/mutate.py new file mode 100644 index 00000000..59da85f1 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/mutate.py @@ -0,0 +1,32 @@ +# mutate.py : apply one named mutant to the candidate (exact text, must match once). Run from the tree root. +import sys +P, R, T, X = "packages/runs/src/paths.mjs", "packages/runs/src/runs.mjs", "packages/runs/src/state.mjs", "scripts/mosaic-task.mjs" +M = { + "D01": [(X, " if (!isRunId(runId)) {\n fail(4, `invalid run id", " if (false) {\n fail(4, `invalid run id")], + "D03": [(P, " } catch {\n return null;\n }\n}", " } catch (error) {\n if (error instanceof RunsError) throw error;\n return null;\n }\n}")], + "D04": [(R, " if (resolveInside(dataRoot, RUNS_DIRNAME) === null) return null;\n", "")], + "D05": [(T, "entries.slice(-last)", "entries.slice(0, last)")], + "D06": [(T, ' if (entry.note !== undefined && typeof entry.note !== "string") return null;\n', "")], + "D07": [(R, " if (isMissing(error)) return [];\n throw new RunsError(`cannot read ${root}", " return [];\n throw new RunsError(`cannot read ${root}")], + "D08": [(T, " } catch (error) {\n throw new RunsError(`cannot read ${file}", " } catch (error) {\n return null;\n throw new RunsError(`cannot read ${file}")], + "D09": [(T, "if (!POINTER_KEYS.includes(key))", "if (false)")], + "D10": [(P, 'return relative === "" ||', "return false ||")], + "D11": [(X, "if (error instanceof RunsError) fail(error.exitCode, error.message);\n throw error;\n }\n}\n\nfunction listRuns", "if (false) fail(error.exitCode, error.message);\n throw error;\n }\n}\n\nfunction listRuns")], + "D13": [(R, " if (isMissing(error)) return null;\n throw new RunsError(`cannot read ${dir}", " throw new RunsError(`cannot read ${dir}")], + "D14": [(P, "real = fs.realpathSync(target);", "real = path.resolve(target);")], + "D15": [(P, "root = fs.realpathSync(dataRoot);", "root = path.resolve(dataRoot);")], + "D16": [(R, "{0,63}$/", "{0,64}$/")], + "D17": [(R, ' result: readJsonObject(dataRoot, RUNS_DIRNAME, runId, "result.json"),', ' result: readRunDocument(dataRoot, runId, "result.json"),')], + "D18": [(T, 'if (line.trim() === "") continue;', 'if (line === "") continue;')], + "D19": [(R, " requireRunId(runId);\n if (!RUN_DOCUMENTS", " if (!RUN_DOCUMENTS")], + "D20": [(R, 'filter((name) => name.startsWith("r-")).sort()', "filter(isRunId).sort()")], + "D21": [(T, "if (pointer.pointerVersion !== 1)", "if (false)")], + "D22": [(T, '["at", "event", "release", "imageTag"].every', '["at", "event", "release"].every')], + "D23": [(T, "last < 1)", "last < 0)")], +} +for f, old, new in M[sys.argv[1]]: + s = open(f).read() + n = s.count(old) + if n != 1: sys.exit(f"{sys.argv[1]}: {n} matches in {f}") + open(f, "w").write(s.replace(old, new)) +print(sys.argv[1], "applied") diff --git a/agents/darkwing/work/queue-56-review/r1/mut/probes.txt b/agents/darkwing/work/queue-56-review/r1/mut/probes.txt new file mode 100644 index 00000000..46e0aff0 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/probes.txt @@ -0,0 +1,59 @@ + +== P1 show ../x with no config file (mutwt carries D01 when run by this script) + base: exit 4 + err| mosaic-task: invalid run id: "../x" (expected r-) + cand: exit 4 + err| mosaic-task: invalid run id: "../x" (expected r-) + mutwt: exit 3 + err| mosaic-task: configuration problem (exit 3); run scripts/bootstrap.sh or fix config.json + +== P2 show of a run directory with mode 000 + base: exit 1 + out| run: r-20260101T000000Z-aaaaaa + out| result.json: (missing or unreadable) + err| node:fs:1954 + cand: exit 4 + err| mosaic-task: cannot read /home/jwoltje/darkwing-scratch/r56a/probes/p2/data/runs/r-20260101T000000Z-aaaaaa: EACCES + mutwt: exit 4 + err| mosaic-task: cannot read /home/jwoltje/darkwing-scratch/r56a/probes/p2/data/runs/r-20260101T000000Z-aaaaaa: EACCES + +== P3 list with r- names that aren't valid run ids + base: exit 0 + out| r- unknown task=- ws=- session=- + out| r-.bad succeeded task=t ws=- session=- + cand: exit 0 + out| r- unknown task=- ws=- session=- + out| r-.bad succeeded task=t ws=- session=- + mutwt: exit 0 + out| r- unknown task=- ws=- session=- + out| r-.bad succeeded task=t ws=- session=- + +== P4 runs/ is a link inside the data root + base: exit 0 + out| r-20260101T000000Z-aaaaaa succeeded task=t ws=- session=- + out| r-self unknown task=- ws=- session=- + cand: exit 0 + out| r-20260101T000000Z-aaaaaa succeeded task=t ws=- session=- + out| r-self unknown task=- ws=- session=- + mutwt: exit 0 + out| r-20260101T000000Z-aaaaaa succeeded task=t ws=- session=- + out| r-self unknown task=- ws=- session=- + +== P5 state/ linked out of the data root, no active.json or log there + readActivePointer: null + readActivationLog: {"entries":[],"malformed":0} + +== P5b same, with active.json outside + readActivePointer: RunsError 4 /state/active.json resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/probes/p5/data) + +== P6 log lines release.sh rollback would still use (an extra key, a non-string imageTag) + {"entries":[],"malformed":2} + +DONE + +== P3 list under D17 + | mosaic-task: invalid run id: "r-" (expected r-) + exit 4 + +== P3 list under D20 + exit 0 diff --git a/agents/darkwing/work/queue-56-review/r1/mut/run.sh b/agents/darkwing/work/queue-56-review/r1/mut/run.sh new file mode 100755 index 00000000..6c01fc9f --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/run.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Each mutant against the packages/runs suite in a second candidate worktree, then restores from the index. +export TMPDIR=~/darkwing-scratch/r56a/tmp +S=~/darkwing-scratch/r56a; 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"\"(D\d\d)\"", open("'$M'/mutate.py").read())))))'); do + (cd $W && git checkout -q -- packages scripts && python3 $M/mutate.py $v > /dev/null && git diff > $M/$v.diff) || { echo "$v APPLY-FAILED" >> $M/summary.txt; continue; } + (cd $W && env -u NODE_TEST_CONTEXT node --test packages/runs/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 scripts && sha256sum -c $S/pkt/candidate-manifest.sha256) > $M/manifest-after.txt 2>&1 +echo "end $(date -u +%FT%TZ)" >> $M/summary.txt +echo DONE >> $M/summary.txt diff --git a/agents/darkwing/work/queue-56-review/r1/mut/summary.txt b/agents/darkwing/work/queue-56-review/r1/mut/summary.txt new file mode 100644 index 00000000..efe94619 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/mut/summary.txt @@ -0,0 +1,24 @@ +start 2026-10-10T16:57:19Z +D01 SURVIVED exit=0 ℹ pass 37 ℹ fail 0 +D03 killed exit=1 ℹ pass 33 ℹ fail 4 +D04 killed exit=1 ℹ pass 35 ℹ fail 2 +D05 killed exit=1 ℹ pass 36 ℹ fail 1 +D06 killed exit=1 ℹ pass 36 ℹ fail 1 +D07 killed exit=1 ℹ pass 36 ℹ fail 1 +D08 killed exit=1 ℹ pass 36 ℹ fail 1 +D09 killed exit=1 ℹ pass 36 ℹ fail 1 +D10 SURVIVED exit=0 ℹ pass 37 ℹ fail 0 +D11 killed exit=1 ℹ pass 35 ℹ fail 2 +D13 killed exit=1 ℹ pass 36 ℹ fail 1 +D14 killed exit=1 ℹ pass 24 ℹ fail 13 +D15 killed exit=1 ℹ pass 36 ℹ fail 1 +D16 killed exit=1 ℹ pass 36 ℹ fail 1 +D17 SURVIVED exit=0 ℹ pass 37 ℹ fail 0 +D18 killed exit=1 ℹ pass 36 ℹ fail 1 +D19 killed exit=1 ℹ pass 36 ℹ fail 1 +D20 SURVIVED exit=0 ℹ pass 37 ℹ fail 0 +D21 killed exit=1 ℹ pass 36 ℹ fail 1 +D22 SURVIVED exit=0 ℹ pass 37 ℹ fail 0 +D23 killed exit=1 ℹ pass 36 ℹ fail 1 +end 2026-10-10T16:57:40Z +DONE diff --git a/agents/darkwing/work/queue-56-review/r1/out/byte-check.txt b/agents/darkwing/work/queue-56-review/r1/out/byte-check.txt new file mode 100644 index 00000000..483b79c9 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/byte-check.txt @@ -0,0 +1,2 @@ +byte-check: 16 cases, stdout, stderr and exit identical +byte-check: data root unchanged diff --git a/agents/darkwing/work/queue-56-review/r1/out/delta-check.txt b/agents/darkwing/work/queue-56-review/r1/out/delta-check.txt new file mode 100644 index 00000000..1de533ec --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/delta-check.txt @@ -0,0 +1,110 @@ + +== run directory linked out of the data root: list + base: exit 0 + out| r-20260101T000000Z-aaaaaa succeeded task=t-out ws=- session=- + cand: exit 0 + out| r-20260101T000000Z-aaaaaa unknown task=- ws=- session=- + +== run directory linked out of the data root: show + base: exit 0 + out| run: r-20260101T000000Z-aaaaaa + out| status: succeeded + out| task: t-out + out| adapter: (see config) provider=p model=m + out| request: "r" + out| response: "s" + out| timing: a -> b (1 ms) + out| exit: 0 + out| artifacts: result.json + cand: exit 4 + err| mosaic-task: /home/jwoltje/darkwing-scratch/r56a/deltacheck/run-link/data/runs/r-20260101T000000Z-aaaaaa resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/deltacheck/run-link/data) + +== result.json linked out of the data root: list + base: exit 0 + out| r-20260101T000000Z-aaaaaa succeeded task=t-out ws=- session=- + cand: exit 0 + out| r-20260101T000000Z-aaaaaa unknown task=- ws=- session=- + +== result.json linked out of the data root: show + base: exit 0 + out| run: r-20260101T000000Z-aaaaaa + out| status: succeeded + out| task: t-out + out| adapter: (see config) provider=p model=m + out| request: "r" + out| response: "s" + out| timing: a -> b (1 ms) + out| exit: 0 + out| artifacts: result.json + cand: exit 0 + out| run: r-20260101T000000Z-aaaaaa + out| result.json: (missing or unreadable) + out| artifacts: result.json + +== runs directory linked out of the data root: list + base: exit 0 + out| r-20260101T000000Z-aaaaaa succeeded task=t-out ws=- session=- + cand: exit 4 + err| mosaic-task: /home/jwoltje/darkwing-scratch/r56a/deltacheck/runs-link/data/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/deltacheck/runs-link/data) + +== runs directory linked out of the data root: show + base: exit 0 + out| run: r-20260101T000000Z-aaaaaa + out| status: succeeded + out| task: t-out + out| adapter: (see config) provider=p model=m + out| request: "r" + out| response: "s" + out| timing: a -> b (1 ms) + out| exit: 0 + out| artifacts: result.json + cand: exit 4 + err| mosaic-task: /home/jwoltje/darkwing-scratch/r56a/deltacheck/runs-link/data/runs resolves outside the data root (/home/jwoltje/darkwing-scratch/r56a/deltacheck/runs-link/data) + +== result.json is 5 and task.json is []: list + base: exit 1 + err| file:///home/jwoltje/darkwing-scratch/r56a/base/scripts/mosaic-task.mjs:483 + cand: exit 0 + out| r-20260101T000000Z-aaaaaa unknown task=- ws=- session=- + +== result.json is 5 and task.json is []: show + base: exit 0 + out| run: r-20260101T000000Z-aaaaaa + out| status: undefined + out| task: undefined + out| adapter: (see config) provider=undefined model=undefined + out| request: undefined + out| response: undefined + out| timing: undefined -> undefined (undefined ms) + out| exit: undefined + out| task snapshot: task.json present + out| artifacts: result.json, task.json + cand: exit 0 + out| run: r-20260101T000000Z-aaaaaa + out| result.json: (missing or unreadable) + out| artifacts: result.json, task.json + +== run is a regular file: show + base: exit 1 + out| run: r-20260101T000000Z-aaaaaa + out| result.json: (missing or unreadable) + err| node:fs:1954 + cand: exit 4 + err| mosaic-task: run not found: r-20260101T000000Z-aaaaaa (under /home/jwoltje/darkwing-scratch/r56a/deltacheck/run-file/data/runs) + +== run is a link loop: show + base: exit 4 + err| mosaic-task: run not found: r-20260101T000000Z-aaaaaa (under /home/jwoltje/darkwing-scratch/r56a/deltacheck/loop/data/runs) + cand: exit 4 + err| mosaic-task: cannot resolve /home/jwoltje/darkwing-scratch/r56a/deltacheck/loop/data/runs/r-20260101T000000Z-aaaaaa: ELOOP + +== runs directory unreadable: list + base: exit 0 + cand: exit 4 + err| mosaic-task: cannot read /home/jwoltje/darkwing-scratch/r56a/deltacheck/unreadable/data/runs: EACCES + +== runs directory unreadable: show + base: exit 4 + err| mosaic-task: run not found: r-20260101T000000Z-aaaaaa (under /home/jwoltje/darkwing-scratch/r56a/deltacheck/unreadable/data/runs) + cand: exit 4 + err| mosaic-task: cannot resolve /home/jwoltje/darkwing-scratch/r56a/deltacheck/unreadable/data/runs/r-20260101T000000Z-aaaaaa: EACCES diff --git a/agents/darkwing/work/queue-56-review/r1/out/node-runs.txt b/agents/darkwing/work/queue-56-review/r1/out/node-runs.txt new file mode 100644 index 00000000..0f264b69 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/node-runs.txt @@ -0,0 +1,45 @@ +✔ isRunId accepts the run id shape and nothing else (1.748725ms) +✔ a missing data root or runs directory lists nothing (2.62682ms) +✔ runs as a regular file lists nothing, as before (0.946792ms) +✔ listRunIds keeps r- names only, sorted oldest first (1.233291ms) +✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.291242ms) +✔ readRunRecord returns documents and artifacts in directory order (1.713813ms) +✔ readRunRecord is null for a missing run, a dangling link or a file (1.29214ms) +✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.833633ms) +✔ readRunDocument reads only the three run documents (0.879084ms) +✔ a link inside the data root is followed (1.653918ms) +✔ a data root that is itself a link is trusted as configured (1.299716ms) +✔ a run directory linked out of the data root is never read (3.611395ms) +✔ a document linked out of the data root reads as null (4.654578ms) +✔ a runs directory linked out of the data root refuses (1.553974ms) +✔ a relative link that climbs out of the data root refuses (0.913072ms) +✔ a sibling whose name starts with the data root's name is outside it (0.956986ms) +✔ a link loop refuses instead of reading as missing (1.278185ms) +✔ an unreadable runs directory refuses instead of listing nothing (0.756923ms) +✔ an unreadable run directory refuses instead of reading as missing (0.953906ms) +✔ a link to the data root's parent is outside it (0.694287ms) +✔ listRunIds sorts whatever order the directory returns (2.201433ms) +✔ the readers write nothing (3.639856ms) +✔ no pointer is null (2.887848ms) +✔ the pointer release.sh writes reads back (2.51019ms) +✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.716029ms) +✔ a pointer that is a directory refuses with exit 4 (0.96141ms) +✔ a state file linked out of the data root refuses (2.368395ms) +✔ a state directory linked out of the data root refuses (1.703149ms) +✔ a missing log is empty (0.58268ms) +✔ the log reads oldest first and counts malformed lines (1.176573ms) +✔ last must be a positive integer (0.542446ms) +✔ the state readers write nothing (1.947461ms) +✔ list prints each run in the established format (113.565222ms) +✔ show prints the run in the established format (82.167185ms) +✔ show of a missing run and an invalid id exit 4 as before (136.70629ms) +✔ list and show refuse a runs directory linked out of the data root (178.235466ms) +✔ show refuses a run linked out of the data root; list reports it unknown (191.565769ms) +ℹ tests 37 +ℹ suites 0 +ℹ pass 37 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 777.874059 diff --git a/agents/darkwing/work/queue-56-review/r1/out/summary.txt b/agents/darkwing/work/queue-56-review/r1/out/summary.txt new file mode 100644 index 00000000..1fb85c8b --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/summary.txt @@ -0,0 +1,13 @@ +start 2026-10-10T16:55:29Z +node-runs exit=0 ℹ pass 37 ℹ fail 0 +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-10T16:57:50Z +DONE diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-auth.txt b/agents/darkwing/work/queue-56-review/r1/out/test-auth.txt new file mode 100644 index 00000000..ac228760 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-auth.txt @@ -0,0 +1,17 @@ +OK status with missing harness credential exits 3 and still lists accounts +OK status reports harness credential (read-only) + mosaic accounts +OK api key material never reaches output +OK oauth token material never reaches output +OK unparseable credential file exits 2 +OK symlinked credential file exits 4 +OK env-side credential names reported +OK env var values never reach output +OK accounts without an accounts dir reports none and creates nothing +OK accounts lists files and marks the active one +OK loose account perms flagged in listing +OK agent --auth with missing account file refuses (exit 4) +OK agent --auth with non-0600 account file refuses +OK agent --auth with invalid account name refuses +OK auth.sh without valid config refuses + +selftest: 15 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-conductor.txt b/agents/darkwing/work/queue-56-review/r1/out/test-conductor.txt new file mode 100644 index 00000000..c345187f --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-conductor.txt @@ -0,0 +1,55 @@ +Note: switching to 'dc96f87b1776cc74d0ea5ba7701db418cc21e1b8'. + +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 + +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 'dc96f87b1776cc74d0ea5ba7701db418cc21e1b8'. + +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 + +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 diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-config.txt b/agents/darkwing/work/queue-56-review/r1/out/test-config.txt new file mode 100644 index 00000000..76c05ef7 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-config.txt @@ -0,0 +1,26 @@ +OK absent adapter defaults to pi +OK adapter mock validates (exit 0) +OK unsupported adapter exits 2 (exit 2) +OK env exports adapter +OK bootstrap creates default when absent (exit 0) +OK bootstrap wrote config file +OK bootstrap is idempotent on existing config (exit 0) +OK bootstrap did not rewrite existing config +OK validate missing config exits 3 (exit 3) +OK malformed JSON exits 2 (exit 2) +OK unsupported configVersion exits 2 (exit 2) +OK unknown top-level key exits 2 (exit 2) +OK unknown execution key exits 2 (exit 2) +OK unsupported backend exits 2 (exit 2) +OK unsupported environment exits 2 (exit 2) +OK relative dataRoot exits 2 (exit 2) +OK non-canonical dataRoot exits 2 (exit 2) +OK filesystem root dataRoot exits 2 (exit 2) +OK home directory dataRoot exits 2 (exit 2) +OK dataRoot containing config dir exits 2 (exit 2) +OK control character in provider exits 2 (exit 2) +OK symlinked config file exits 2 (exit 2) +OK env exports resolve correctly +OK failed validation modified nothing + +selftest: 24 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-discord.txt b/agents/darkwing/work/queue-56-review/r1/out/test-discord.txt new file mode 100644 index 00000000..b013f9ff --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-discord.txt @@ -0,0 +1,70 @@ +toolchain: node v26.8.1 + +OK syntax: packages/discord/src/approvals.mjs +OK syntax: packages/discord/src/authorize.mjs +OK syntax: packages/discord/src/binding.mjs +OK syntax: packages/discord/src/cli.mjs +OK syntax: packages/discord/src/connector.mjs +OK syntax: packages/discord/src/context.mjs +OK syntax: packages/discord/src/engine-pi.mjs +OK syntax: packages/discord/src/errors.mjs +OK syntax: packages/discord/src/gateway.mjs +OK syntax: packages/discord/src/git.mjs +OK syntax: packages/discord/src/journal.mjs +OK syntax: packages/discord/src/notify.mjs +OK syntax: packages/discord/src/rest.mjs +OK syntax: packages/discord/src/setspark.mjs +OK syntax: packages/discord/src/tools.mjs +OK syntax: packages/discord/src/web.mjs +OK syntax: packages/discord/bin/git-credential.mjs +OK syntax: packages/discord/extension/tools.mjs +OK syntax: packages/discord/tests/approvals.test.mjs +OK syntax: packages/discord/tests/authorize.test.mjs +OK syntax: packages/discord/tests/binding.test.mjs +OK syntax: packages/discord/tests/connector.test.mjs +OK syntax: packages/discord/tests/context.test.mjs +OK syntax: packages/discord/tests/engine.test.mjs +OK syntax: packages/discord/tests/fake-pi.mjs +OK syntax: packages/discord/tests/gateway.test.mjs +OK syntax: packages/discord/tests/git.test.mjs +OK syntax: packages/discord/tests/helpers.mjs +OK syntax: packages/discord/tests/journal.test.mjs +OK syntax: packages/discord/tests/notify.test.mjs +OK syntax: packages/discord/tests/recover.test.mjs +OK syntax: packages/discord/tests/rest.test.mjs +OK syntax: packages/discord/tests/setspark.test.mjs +OK syntax: packages/discord/tests/tools.test.mjs +OK syntax: packages/discord/tests/web.test.mjs +OK syntax: packages/discord/fixtures/claim-worker.mjs +OK syntax: packages/discord/fixtures/legacy-owner-worker.mjs +OK syntax: scripts/discord.sh +OK syntax: scripts/discord-service.sh +OK packages/discord declares no dependencies +OK no bot-token-shaped string in packages/discord +OK fixture binding uses placeholder ids only +OK fixture binding validates +OK real pi with the extension exposes exactly list_dir, read_file, search and no built-in tool +OK real pi with a writable root exposes exactly the three reads plus write_file and edit_file, and writes nothing at start +OK real pi with a web key exposes the three reads plus web_fetch and web_search, and no write tool without a writable root +OK real pi with a git root exposes the reads, writes and the four git verbs, commits nothing at start, and never shows the token +OK real pi with protocol vault adds reserve_id to the git verbs +OK real pi with a setspark key exposes the reads and the eight record verbs, no counters, and never shows the key +OK real pi refuses a git key on a read-only root (fail closed) +OK real pi with the pilot flags (--no-tools) exposes no tool at all +OK real pi exits non-zero without MOSAIC_DISCORD_TOOLS: no session, no tools (fail closed) +OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT +OK node --test packages/discord/tests/ (ℹ pass 178) +OK scripts/discord.sh --help exits 0 +OK scripts/discord.sh check without a binding exits 4 +OK scripts/discord.sh recover without a binding exits 4 +OK scripts/discord.sh reload without a binding exits 4 +OK scripts/discord-service.sh without a command exits 4 +OK service unit renders with the repository path, a supervised run as the main process, exit 3 never retried, and reload as SIGHUP +OK service install writes the rendered unit (0644) and leaves no temp file +OK service install a second time reports unchanged +OK systemd-analyze verify accepts the rendered unit +OK service uninstall removes the unit file +OK service install with an unknown flag exits 4 +OK service install with USER unset finishes and names the account for lingering + +discord suite: 66 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-extension-package.txt b/agents/darkwing/work/queue-56-review/r1/out/test-extension-package.txt new file mode 100644 index 00000000..deb3daf4 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-extension-package.txt @@ -0,0 +1,21 @@ +OK initial ordinary-file install +OK installed tree matches canonical source +OK installed tree has no symlinks +OK check detects installation drift +OK sync refuses to overwrite installation drift +OK check detects an extra destination file +OK check detects an extra destination directory +OK check rejects a destination symlink +OK sync accepts a canonical source update +OK updated installation matches canonical source +scripts/test-extension-package.sh: line 14: 778025 Killed "$@" > /dev/null 2>&1 +OK forced interruption kills the replacing process +OK next invocation recovers old consistent installation +OK interrupted replacement rolled back +OK sync succeeds after interruption recovery +OK unlocked stale lock file does not block +OK active lock refuses a concurrent sync +OK source symlink fails closed +OK nested second entrypoint fails closed + +extension package selftest: 18 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-foundation.txt b/agents/darkwing/work/queue-56-review/r1/out/test-foundation.txt new file mode 100644 index 00000000..6338e1e6 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-foundation.txt @@ -0,0 +1,53 @@ +toolchain: node v26.8.1, python 3.12.8, jsonschema 4.26.0 + +OK syntax: scripts/foundation-inspect.mjs +OK syntax: scripts/foundation/strict-json.mjs +OK syntax: scripts/foundation/canonical.mjs +OK syntax: scripts/foundation/resolve.mjs +OK syntax: scripts/foundation/validate-record.mjs +OK syntax: scripts/foundation/fixtures/build-fixtures.mjs +OK syntax: scripts/foundation/canonical.test.mjs +OK syntax: scripts/foundation/cli.test.mjs +OK syntax: scripts/foundation/fixtures.test.mjs +OK syntax: scripts/foundation/resolve.test.mjs +OK syntax: scripts/foundation/strict-json.test.mjs +OK syntax: scripts/foundation/verify-schema.py (ast only; no bytecode written) +OK fixture generator runs +OK checked-in fixtures/bundles equal a fresh generation +OK checked-in fixtures/raw equal a fresh generation +OK checked-in fixtures/index.json equal a fresh generation +OK checked-in demo bundles equal a fresh generation +OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT +OK node --test scripts/foundation/ (ℹ pass 80) +OK differential schema oracle: PASS: differential schema oracle (finite corpus; compatibility evidence, not equivalence proof) + platform witness: strftime('%Y') for year 999 -> '999' (pinned checker refuses years 0001..0999) + node v26.8.1; corpus 1568 records (38 pinned fixtures, 478 unique bundle records, 1052 typeCase/mutation/lexical cases) + schema column: agree-valid 540, agree-invalid 991, DISAGREEMENTS 0; strict-only (parser-bound) cases: 27; unsupported-kind records not schema-assessed by the inspector: 10 + profile column (schema-valid records only): profile-valid 510, profile-invalid 30 + profile refusals asserted: 30 schema-agreed-valid records refused only by the strict typed-string profile (rule profile-pattern-mismatch), 12 declared by name; 73 named probes verified against declared schema/profile columns +OK oracle: zero schema-column disagreements with the pinned checker +OK oracle: strict-only profile refusals are counted and asserted +OK demo: permitted read preview exits 0 (exit 0) +OK demo: permitted file.change preview exits 0 (exit 0) +OK demo: assignment.change proposal is unresolved (exit 3) (exit 3) +OK demo: revoked registration is refused (exit 3) (exit 3) +OK demo: message is not authority (exit 3) (exit 3) +OK usage: no arguments exits 2 (exit 2) +OK io: missing file exits 4 (exit 4) +OK io: directory exits 4 (exit 4) +OK io: symlink exits 4 (O_NOFOLLOW) (exit 4) +OK bound: oversize fixture exits 2 (exit 2) +OK profile: one final LF in a typed selection id is refused before admission (exit 2) (exit 2) +OK profile: two final LFs fail the schema pattern itself (exit 2) (exit 2) +OK profile: escaped newlines in free-form text stay allowed (exit 0) (exit 0) +OK profile refusal is invalid-request/profile-pattern-mismatch with selection and operation withheld, value not echoed +OK text output starts with the disclaimer +OK json output is valid JSON with result allowed and exactly the charter §7 fields +OK json golden matches byte-for-byte +OK sandboxed bundle run (env -i, PATH=/nonexistent) produced the unresolved proposal +OK sandbox inventory (path/type/size/mode/uid/gid/inode/mtime/sha256) unchanged by runs +OK canary never printed (bundle run and credential-file run) +OK a non-bundle JSON file is refused at the shape gate, not read into output +OK no field of the non-bundle file is echoed + +selftest: 44 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-queue.txt b/agents/darkwing/work/queue-56-review/r1/out/test-queue.txt new file mode 100644 index 00000000..fa8f92b1 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-queue.txt @@ -0,0 +1,35 @@ +toolchain: node v26.8.1, git version 2.55.0 + +OK syntax: packages/queue/src/cli.mjs +OK syntax: packages/queue/src/errors.mjs +OK syntax: packages/queue/src/io.mjs +OK syntax: packages/queue/src/lock.mjs +OK syntax: packages/queue/src/queue.mjs +OK syntax: packages/queue/src/review.mjs +OK syntax: packages/queue/src/store.mjs +OK syntax: packages/queue/tests/commit.test.mjs +OK syntax: packages/queue/tests/data.test.mjs +OK syntax: packages/queue/tests/dispatch.test.mjs +OK syntax: packages/queue/tests/helpers.mjs +OK syntax: packages/queue/tests/lock.test.mjs +OK syntax: packages/queue/tests/migration.test.mjs +OK syntax: packages/queue/tests/review.test.mjs +OK syntax: packages/queue/tests/store.test.mjs +OK syntax: packages/queue/tests/write.test.mjs +OK syntax: packages/queue/tests/fixtures/fake-gitea.mjs +OK syntax: packages/queue/tests/fixtures/kill-at.mjs +OK syntax: packages/queue/tests/fixtures/lock-child.mjs +OK syntax: packages/queue/tests/fixtures/mosaic-pre-a2.sh +OK syntax: scripts/queue-commit.sh +OK syntax: scripts/git-hooks/pre-commit +OK syntax: scripts/mosaic +OK queue-commit.sh, the guard and scripts/mosaic are executable +OK packages/queue declares no dependencies +ℹ tests 148 +ℹ pass 148 +ℹ fail 0 +OK node --test packages/queue/tests/ +OK scripts/mosaic queue help +skip queue verify and render --check: this checkout (/home/jwoltje/darkwing-scratch/r56a/cand) is not the queue's canonical root (/mnt/storage/src/mosaic-stack) + +queue suite: 27 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-release-docker.txt b/agents/darkwing/work/queue-56-review/r1/out/test-release-docker.txt new file mode 100644 index 00000000..7202b85d --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-release-docker.txt @@ -0,0 +1,16 @@ +OK valid RELEASE resolves (exit 0) +OK invalid RELEASE exits 1 (exit 1) +OK missing RELEASE exits 1 (exit 1) +OK valid RELEASE leaves image tag consistent with version +OK status safe on empty state (exit 0) +OK status created no pointer +OK fault-injected activation refuses (exit 1) +OK refused activation wrote no pointer +OK refusal logged exactly once with valid fields +OK healthy activation succeeds (exit 0) +OK pointer written with valid fields +OK repeat activation succeeds (log grows) (exit 0) +OK log is append-only across activations +OK rollback without previous refuses (exit 1) + +selftest: 14 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-release.txt b/agents/darkwing/work/queue-56-review/r1/out/test-release.txt new file mode 100644 index 00000000..1d6ed050 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-release.txt @@ -0,0 +1,7 @@ +OK valid RELEASE resolves (exit 0) +OK invalid RELEASE exits 1 (exit 1) +OK missing RELEASE exits 1 (exit 1) +OK valid RELEASE leaves image tag consistent with version +skip state-machine cases (docker daemon unavailable) + +selftest: 4 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/out/test-task.txt b/agents/darkwing/work/queue-56-review/r1/out/test-task.txt new file mode 100644 index 00000000..cd89fe9b --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/out/test-task.txt @@ -0,0 +1,32 @@ +OK valid task validates (exit 0) +OK unknown task key exits 2 (exit 2) +OK unsupported taskVersion exits 2 (exit 2) +OK invalid task id exits 2 (exit 2) +OK empty prompt exits 2 (exit 2) +OK NUL in expectExact exits 2 (exit 2) +OK out-of-range timeout exits 2 (exit 2) +OK missing mission file exits 4 (exit 4) +OK task with valid mission validates (exit 0) +OK invalid mission exits 2 (exit 2) +OK validate missing task exits 4 (exit 4) +OK validation does not modify the task file +OK prune dry-run exits 0 (exit 0) +OK dry-run deleted nothing +OK prune --keep=2 --yes removes oldest (exit 0) +OK kept exactly 2 newest runs +OK newest run kept, oldest pruned +OK append-only receipt written (3 entries) +OK sessions/workspaces untouched by prune +OK prune with invalid keep exits 4 (exit 4) +skip adapter seam cases (docker daemon unavailable) +skip workspace/capability cases (docker daemon unavailable) +skip live task cases (docker unavailable) +OK onboard without name exits 4 (non-interactive) (exit 4) +OK onboard --name renders profile (exit 0) +OK profile written +OK canon structure: required filled, optional placeholdered +OK canon sections present +skip live recall pair: user recall run, recalled user name (docker daemon unavailable) +OK no agent identity on headless run + +selftest: 26 passed, 0 failed diff --git a/agents/darkwing/work/queue-56-review/r1/probes.sh b/agents/darkwing/work/queue-56-review/r1/probes.sh new file mode 100755 index 00000000..55a52316 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/r1/probes.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Row 56 probes: edge cases outside Rocko's byte-check and delta-check, base against candidate. +export TMPDIR=~/darkwing-scratch/r56a/tmp +S=~/darkwing-scratch/r56a; W=$S/probes; rm -rf $W; mkdir -p $W +A=r-20260101T000000Z-aaaaaa +RESULT='{"runVersion":1,"taskId":"t","status":"succeeded","request":"r","response":"s","provider":"p","model":"m","startedAt":"a","finishedAt":"b","durationMs":1,"exitCode":0,"signal":null}' +root() { mkdir -p "$W/$1/data" "$W/$1/outside"; printf '{"configVersion":1,"environment":"development","dataRoot":"%s","execution":{"backend":"docker","provider":"zai","model":"m"}}\n' "$W/$1/data" > "$W/$1/config.json"; echo "$W/$1/data"; } +run_case() { local name="$1" cfg="$2"; shift 2 + for tree in base cand mutwt; do + local rc=0 out + out="$(cd $S/$tree && env -u NODE_TEST_CONTEXT MOSAIC_CONFIG="$cfg" node scripts/mosaic-task.mjs "$@" 2>"$W/$name.$tree.err")" || rc=$? + printf ' %s: exit %s\n' "$tree" "$rc"; [ -z "$out" ] || printf '%s\n' "$out" | sed 's/^/ out| /' + [ -s "$W/$name.$tree.err" ] && head -1 "$W/$name.$tree.err" | sed 's/^/ err| /' + done; } +hdr() { printf '\n== %s\n' "$*"; } + +hdr "P1 show ../x with no config file (mutwt carries D01 when run by this script)" +run_case p1 "$W/no-such-config.json" show ../x + +D="$(root p2)"; mkdir -p "$D/runs/$A"; printf '%s\n' "$RESULT" > "$D/runs/$A/result.json"; chmod 000 "$D/runs/$A" +hdr "P2 show of a run directory with mode 000"; run_case p2 "$W/p2/config.json" show "$A" +chmod 755 "$D/runs/$A" + +D="$(root p3)"; mkdir -p "$D/runs/r-.bad" "$D/runs/r-"; printf '%s\n' "$RESULT" > "$D/runs/r-.bad/result.json" +hdr "P3 list with r- names that aren't valid run ids"; run_case p3 "$W/p3/config.json" list + +D="$(root p4)"; mkdir -p "$D/runs/$A"; printf '%s\n' "$RESULT" > "$D/runs/$A/result.json"; ln -s . "$D/runs/r-self"; mv "$D/runs" "$D/real-runs"; ln -s real-runs "$D/runs" +hdr "P4 runs/ is a link inside the data root"; run_case p4 "$W/p4/config.json" list + +D="$(root p5)"; ln -s "$W/p5/outside" "$D/state" +hdr "P5 state/ linked out of the data root, no active.json or log there" +(cd $S/cand && node -e ' +import("./packages/runs/src/index.mjs").then((m) => { + for (const f of ["readActivePointer", "readActivationLog"]) { + try { console.log(" " + f + ": " + JSON.stringify(m[f](process.argv[1]))); } catch (e) { console.log(" " + f + ": " + e.name + " " + e.exitCode + " " + e.message); } + } +});' "$D") +printf '{"pointerVersion":1,"release":"x","imageTag":"y","activatedAt":"z"}\n' > "$W/p5/outside/active.json" +hdr "P5b same, with active.json outside" +(cd $S/cand && node -e ' +import("./packages/runs/src/index.mjs").then((m) => { + try { console.log(" readActivePointer: " + JSON.stringify(m.readActivePointer(process.argv[1]))); } catch (e) { console.log(" readActivePointer: " + e.name + " " + e.exitCode + " " + e.message.replace(process.argv[1], "")); } +});' "$D") + +D="$(root p6)"; mkdir -p "$D/state" +printf '%s\n' '{"at":"a","event":"activate","release":"0.0.1","imageTag":"t1","from":"0.0.0"}' '{"at":"b","event":"rollback","release":"0.0.0","imageTag":5}' > "$D/state/activation-log.jsonl" +hdr "P6 log lines release.sh rollback would still use (an extra key, a non-string imageTag)" +(cd $S/cand && node -e ' +import("./packages/runs/src/index.mjs").then((m) => console.log(" " + JSON.stringify(m.readActivationLog(process.argv[1]))));' "$D") +echo; echo DONE diff --git a/agents/darkwing/work/queue-56-review/review-r1.md b/agents/darkwing/work/queue-56-review/review-r1.md new file mode 100644 index 00000000..8193bf95 --- /dev/null +++ b/agents/darkwing/work/queue-56-review/review-r1.md @@ -0,0 +1,131 @@ +# Row 56, runs and releases reader, round 1 review (Darkwing) + +Issue #1545, packet comment 27109, request comment 27113, queue revs +343-347. Brief: `docs/plans/2026-10-10_design-implementation.md`, section +"Runs and releases reader module". Base `dc96f87b`. Candidate manifest +sha256 `ed3c5392ae43e1c3541c6bab6a2f25826514124f5f68536e5cc330a39cc5d7a3`, +`build.patch` sha256 `dd7b469b…`. Both match comment 27109, and the +packet manifest checks clean. + +Verdict: **approve**. The module reads and never writes, nothing it +returns comes from outside the data root, and `list` and `show` print the +same bytes as before on Rocko's seeded data root. Every suite is green. +Nothing blocks. The notes below are test gaps and README wording, plus +one disagreement with the packet: mutant M31 is not equivalent. + +## Method + +- I read the whole patch: the five `src/` files, the three test files, + the README, the `mosaic-task.mjs` change, and Rocko's `seed.sh`, + `byte-check.sh` and `delta-check.sh`. I compared the pointer and log + readers against `scripts/release.sh` (`append_log`, the `activate` + printf, `rollback`'s log scan and `status`). +- Detached worktrees at `dc96f87b`: `base` unchanged, `cand` with + `git apply --index build.patch`, then `sha256sum -c` on the manifest, + 15 OK. A third worktree, built the same way, for mutants. It checks 15 + OK after the runs (`r1/mut/manifest-after.txt`). +- `grep` for any write, mkdir, rename, unlink, chmod, open or symlink call + in `packages/runs/src`: none. The patch touches no Q14-frozen path. +- Rocko's `byte-check.sh` and `delta-check.sh`, base against candidate, + with work directories in my scratch rather than `/tmp`. +- 22 mutants of my own (`r1/mut/mutate.py`, exact text that must match + once), each run against the `packages/runs` suite. +- Six probes for cases the packet doesn't cover (`r1/probes.sh`, output + in `r1/mut/probes.txt`), run against base, candidate and a candidate + carrying mutant D01. + +Node v26.8.1, `TMPDIR=~/darkwing-scratch/r56a/tmp`. `gate.sh` with +`DOCKER_HOST=unix:///nonexistent.sock` ran 16:55:29Z to 16:57:50Z. +Mutants ran 16:57:19Z to 16:57:40Z in the other worktree, then probes, +then `test-release` with Docker, which finished at 16:58:33Z. + +## Suites + +| Suite | Result | +|---|---| +| packages/runs (node) | 37/0 | +| 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-release-docker.txt`) | +| test-task, Docker unreachable | 26/0, four skip lines | +| byte-check.sh | 16 cases identical, data root unchanged | +| delta-check.sh | same output as Rocko's apart from the scratch path in one stack trace | + +I didn't run test-task with real Docker, because it makes live model +calls. Rocko's gate ran it at 98/0, and the change to `mosaic-task.mjs` is +limited to `list` and `show`, which the package's CLI tests and the byte +check cover. + +## Mutants + +17 of 22 killed (`r1/mut/summary.txt`). The five survivors: + +| Mutant | Change | Observable? | +|---|---|---| +| D01 | the CLI's `isRunId` check before `loadConfig` removed (Rocko's M31) | yes, probe P1 | +| D10 | `isInside` treats a path equal to the data root as outside | only when a link resolves to the data root itself | +| D17 | `listRunRecords` reads through `readRunDocument`, which checks the id | yes, probe P3: `list` exits 4 on a run named `r-` | +| D20 | `listRunIds` keeps `isRunId` names only | yes, probe P3: `list` hides `r-` and `r-.bad` | +| D22 | a log entry without `imageTag` accepted | yes, by reading the log | + +## Probes + +| Probe | Base | Candidate | +|---|---|---| +| P1 `show ../x` with no config file | exit 4, `invalid run id` | the same. With D01: exit 3, `configuration problem` | +| P2 `show` of a run directory with mode 000 | prints two lines, then a stack trace, exit 1 | `cannot read ...: EACCES`, exit 4 | +| P3 `list` with runs named `r-` and `r-.bad` | lists both | the same | +| P4 `runs/` a link inside the data root, plus a run linked to `.` | lists both | the same | +| P5 `state/` linked out, no files there | not in base | pointer `null`, log empty. With `active.json` there: refuses, exit 4 | +| P6 log lines with an extra key, and a numeric `imageTag` | not in base | both counted in `malformed` | + +## Notes (not blocking) + +1. M31 isn't equivalent. The `isRunId` check in `showRun` is the only id + check that runs before `loadConfig`, so it decides the exit code and + message when the config is bad (P1: 4 against 3). The candidate keeps + the base order, so nothing regresses, but a test of `show ../x` with + `MOSAIC_CONFIG` pointing at a missing file would pin it. I agree that + M04 can't be reached on POSIX. +2. No test lists a run whose name starts with `r-` but isn't a valid id, + so D17 and D20 survive. `runs.mjs` says such names are still listed, + and base does list them. One `listRunRecords` case with `r-` or + `r-.bad` would kill both. +3. `logEntry` accepts an entry with no `imageTag` (D22). The malformed + cases test a wrong type, a null `note` and an extra key, but not a + missing key. +4. README wording, three places: + - "`runs/` or `state/` resolving outside refuses" holds for `runs/`. + For `state/`, the module resolves only the file, so a `state/` link + out with no files behind it reads as no release and an empty log + (P5). Nothing outside is read, so the invariant holds and only the + sentence is wrong. + - "the way `release.sh rollback` skips them": rollback skips only lines + that don't parse. P6's two lines would still be used by rollback and + are counted malformed here. `append_log` writes only the five keys, + so real logs don't hit this. The stricter reader is fine. The + comparison in the README and in `state.mjs` isn't accurate. + - The delta table has no row for P2. `show` of a run directory it + can't read used to crash after printing two lines. It now refuses + with exit 4. That's an improvement and the package test covers it, + but `delta-check.sh` doesn't record it. +5. D10 needs no test. It matters only for a link that resolves to the + data root itself, which is inside by any reading. +6. The `padEnd` crash in `list` that Rocko reported is still there and + still predates this row. Sage files it as a follow-up. + +## Files + +- `r1/candidate-manifest.sha256`: copy of Rocko's. +- `r1/gate.sh`, `r1/out/`: suite runs, `summary.txt`, byte and delta + checks, test-release with Docker. +- `r1/mut/`: mutant definitions, runner, diffs, outputs, `summary.txt` + and the manifest check after the runs. +- `r1/probes.sh`, `r1/mut/probes.txt`: the six probes. In that run the + third tree (`mutwt`) carries D01, and the D17 and D20 runs of P3 follow + at the end.