packet(rocko): row 82 round 2 candidate dbf36e92, packet manifest 2afecca7, BUILD-LOG entry (#1551)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -4352,3 +4352,9 @@ After (3780e05d): Rocko's round 1, 4 files +7 -9. Approved by Dewey (27611) on m
|
||||
Correction: the close comment 27613 said rev 598; the done move is rev 599, and comment 27614 corrects it. c9ff939b also carries rev 598, Darkwing's row 76 round 1 approve (27612).
|
||||
|
||||
Correction to the row 79 entry above and Sage's row 79 SESSIONS line: the rev correction on #1573 is comment 27615, not 27614.
|
||||
|
||||
### 2026-10-12 — Rocko, row 82 round 2 candidate: runs list survives a damaged run record (#1551)
|
||||
|
||||
Before (876f1ffe): `mosaic-task.mjs list` called `padEnd` on `result.status` and `result.taskId` without a type check, so a `result.json` like `{}` crashed it with a TypeError at line 484 and hid every run after the damaged one. A `workspace` or `session` that was neither a string nor `null` printed through `String`.
|
||||
|
||||
After (round 2 candidate, uncommitted packet `agents/rocko/work/queue-82/`, candidate manifest dbf36e92, build.patch ddb6bc2e, packet manifest 2afecca7): `listRuns` takes each of the four fields only when it's a string, and the defaults stay `unknown` and `-`. The check sits in `listRuns` because it's the only caller of `listRunRecords`, `show` reads through `readRunRecord`, and the package README and `runs.test.mjs:225` keep records unvalidated beyond being objects. `packages/runs/src/runs.mjs` is unchanged. There are two new tests in `task-cli.test.mjs` and one README table row. Mutants: 4 of 4 survive with the base tests and 4 of 4 are killed with the candidate's. byte-check.sh shows the base and candidate give the same output for a seeded well-formed root (list plus 5 shows) and this host's real data root (list plus 6 shows). On the damaged root, the base gives rc 1 and 1 line, and the candidate gives rc 0 and 3 lines. Gate 01:31:06Z to 01:37:34Z: runs 43, tasks 71, bus 94, business 60, harness 59, cli 114, webui 62, seat 27, and the nine `scripts/test-*.sh` 0 failed. Round 1 (candidate c8cbc227, in-review revs 604-605, request failed without a credential) was never posted. Its packet flagged that the README paragraph above the table no longer held for a non-string workspace or session. Sage amended the brief to own that paragraph (09a8e0ee, blob fb9da977, rev 606). Round 2 adds the wrong-field-type clause to the paragraph's conditions and changes nothing else. The README is now +4 -1, and the candidate totals 3 files +40 -7. Round 2's runs suite (43 pass) and byte-check.sh (exit 0, same results) were rerun on the round 2 tree. The full gate above is round 1's: Sage ruled the paragraph documentation only, and Sage's gate rerun covers it. Round 2 moves: rev 607 back to in-progress, revs 608-609 in-review, request failed without a credential, as expected.
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
# Row 82 (#1551): runs list survives a damaged run record, candidate packet, round 2
|
||||
|
||||
Author: Rocko. Reviewer: Filbert. Brief:
|
||||
`docs/plans/2026-10-12_runs-list-damaged-record.md`, section "Runs list
|
||||
survives a damaged run record" (blob fb9da977, re-pinned at rev 606;
|
||||
first briefed as e9c7b769 at rev 601). Base:
|
||||
`876f1ffe` (`base.txt`). The packet is uncommitted. I made no commits,
|
||||
pushes or Gitea calls and read no token or private binding.
|
||||
|
||||
## Files (`files.txt`, `candidate-manifest.sha256`)
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `scripts/mosaic-task.mjs` | `listRuns` only: each of `status`, `taskId`, `workspace` and `session` is used only if it's a string |
|
||||
| `packages/runs/tests/task-cli.test.mjs` | +2 tests: a `{}` run between two good ones; one run per field with a value that isn't a string |
|
||||
| `packages/runs/README.md` | one row in the damaged-records table, and one clause in the paragraph above it |
|
||||
| `agents/rocko/work/queue-82/mutants.sh` | the mutant rerun: `mutants.sh <tree>` |
|
||||
| `agents/rocko/work/queue-82/byte-check.sh` | the base-against-candidate output check: `byte-check.sh <base> <candidate> <out>` |
|
||||
|
||||
`packages/runs/src/runs.mjs` is unchanged.
|
||||
|
||||
## Where the check sits: `listRuns`
|
||||
|
||||
`listRuns` is the right place, for three reasons:
|
||||
|
||||
- `listRuns` is the only caller of `listRunRecords` (`git grep
|
||||
listRunRecords`). `show` goes through
|
||||
`readRunRecord` instead, so a fix in `listRuns` can't change `show` at
|
||||
all.
|
||||
- The package README says run records "are never validated beyond" being
|
||||
a JSON object, "because older records carry older shapes".
|
||||
`runs.test.mjs:225` pins that: `listRunRecords` returns `{}` as `{}`.
|
||||
A field check in `listRunRecords` would have to replace the object with
|
||||
`null` (which loses the good fields of a half-damaged record) or rewrite
|
||||
fields. Either change is a contract change to the package, for a
|
||||
problem that only exists in one caller's formatting.
|
||||
- `padEnd` is the crash and `listRuns` is what calls it. The check sits
|
||||
next to the code that needs strings.
|
||||
|
||||
## The change
|
||||
|
||||
```js
|
||||
if (result) {
|
||||
if (typeof result.status === "string") status = result.status;
|
||||
if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
if (typeof result.session === "string") session = result.session;
|
||||
}
|
||||
```
|
||||
|
||||
The defaults stay `unknown` and `-`. `String(workspace)` in the print line
|
||||
became `workspace`, since `workspace` is now always a string.
|
||||
|
||||
Why a well-formed record prints the same: a run writes `workspace` and
|
||||
`session` from the task, so each is a string or `null`
|
||||
(`scripts/mosaic-task.mjs:442-444`). The base mapped `null` through
|
||||
`?? "-"` to `-`, and the candidate's default is `-`. A string passes
|
||||
through unchanged in both. `status` and `taskId` are always strings in a
|
||||
well-formed record. Anything else crashed the base.
|
||||
|
||||
The only output change for a record that didn't crash is a `workspace` or
|
||||
`session` that is neither a string nor `null`. The base printed it
|
||||
through `String` (`7`, `[object Object]`) and the candidate prints `-`.
|
||||
That's the brief's rule, and the README row says so.
|
||||
|
||||
## Tests (`packages/runs/tests/task-cli.test.mjs`)
|
||||
|
||||
1. "list prints a damaged result.json as unknown and keeps listing the
|
||||
runs after it". The runs are a good `A` (`ws1`, `s1`), `{}`, and a good
|
||||
`B` (`t-two`, `:run`, `null` session). The good lines are in the same
|
||||
format the existing "established format" test pins.
|
||||
2. "list prints each result field that isn't a string as unknown or -".
|
||||
Four runs, each a good result with one field damaged: `status: 5`,
|
||||
`taskId: null`, `workspace: 7` and `session: {name: "s1"}`.
|
||||
|
||||
Between them they cover the brief's `{}`, numeric `status`, `null`
|
||||
`taskId`, and a damaged run between two good ones. The second test gives
|
||||
each of the four checks its own case.
|
||||
|
||||
Runs suite: 43 pass on the candidate, against 41 on the base.
|
||||
|
||||
## Mutants (`out/mutants-candidate.txt`, `out/mutants-base.txt`)
|
||||
|
||||
Each mutant drops one check and puts that field's base line back:
|
||||
|
||||
| Mutant | Line becomes | Base tests | Candidate tests |
|
||||
|---|---|---|---|
|
||||
| `status-unchecked` | `status = result.status;` | **survived** | killed (tests 1 and 2) |
|
||||
| `taskid-unchecked` | `taskId = result.taskId;` | **survived** | killed (tests 1 and 2) |
|
||||
| `workspace-unchecked` | `workspace = String(result.workspace ?? "-");` | **survived** | killed (test 2) |
|
||||
| `session-unchecked` | `session = result.session ?? "-";` | **survived** | killed (test 2) |
|
||||
|
||||
The base has no checks to drop, so "survives on the base" means this:
|
||||
the candidate's `listRuns` with the base's tests. I built that as a
|
||||
detached worktree at `876f1ffe` with only the candidate
|
||||
`scripts/mosaic-task.mjs` copied in, and removed it afterwards. The
|
||||
`workspace-unchecked` mutant keeps the base's `String()`. Without it,
|
||||
`7.padEnd` would crash, and the mutant would test the crash instead of
|
||||
the check.
|
||||
|
||||
The script saves the file, applies the sed and checks it changed
|
||||
something. It then runs `packages/runs/tests/*.test.mjs` and restores the
|
||||
file. It exits 1 on the base-tests tree, as it should when a mutant
|
||||
survives.
|
||||
|
||||
## Byte check (`out/byte-check.txt`, `out/byte-check/`)
|
||||
|
||||
`byte-check.sh` runs base and candidate `scripts/mosaic-task.mjs` on the
|
||||
same data roots and compares stdout, stderr and exit status:
|
||||
|
||||
- **Seeded well-formed root:** `list` and five `show`s are the same. It
|
||||
holds string and `null` workspace and session, a missing workspace and
|
||||
session, a task id over 18 characters, a run with only `task.json`, and
|
||||
`r-.bad`.
|
||||
- **This host's real data root** (`~/.mosaic-dev`, read-only, through my
|
||||
own config): `list` and all six `show`s are the same. The real records
|
||||
hold only strings and `null` in the four fields.
|
||||
- **Seeded damaged root, recorded only:** the base printed one line and
|
||||
crashed with `TypeError: Cannot read properties of undefined (reading
|
||||
'padEnd')`, exit 1. The candidate printed all three lines, exit 0.
|
||||
|
||||
I removed the real-root output files from `out/byte-check/` before
|
||||
packing, because they carry real runs' requests and responses.
|
||||
`out/byte-check.txt` keeps the result line for each.
|
||||
|
||||
## Round 2: the paragraph above the table
|
||||
|
||||
Round 1 (candidate c8cbc227) never went to review. Its packet said the
|
||||
paragraph above the table claimed `list` and `show` print exactly what
|
||||
they printed before, apart from links, non-object documents and
|
||||
unreadable directories. That claim became false for a `workspace` or
|
||||
`session` that is neither a string nor `null`, and the paragraph was
|
||||
outside the first brief. Sage amended the brief in 09a8e0ee (blob
|
||||
fb9da977, rev 606). The README entry now owns the "How mosaic-task.mjs
|
||||
uses it" section, and the paragraph has to name the wrong-field-type case.
|
||||
|
||||
Round 2 adds one clause to the conditions: "no `result.json` with a field
|
||||
of the wrong type (a `status` or `taskId` that isn't a string, or a
|
||||
`workspace` or `session` that is neither a string nor `null`)". The
|
||||
wording matches the table row below it. Nothing else changed from round
|
||||
1. Sage ruled that a documentation-only change needs just the runs suite
|
||||
and byte-check.sh rerun, so I reran both on the round 2 tree
|
||||
(`out/r2/`). Runs suite: 43 pass, 0 fail. byte-check.sh: exit 0, every
|
||||
seeded and real comparison the same, and the damaged list unchanged (base
|
||||
rc 1 and 1 line, candidate rc 0 and 3 lines). As in round 1, I left the
|
||||
real-root output files out of the packet. The gate below is round 1's, on
|
||||
code identical to round 2's.
|
||||
|
||||
## Gate, round 1 (`out/gate/`, sequential, scratch worktree at 876f1ffe with the candidate, `node_modules` linked)
|
||||
|
||||
2026-10-12T01:31:06Z to 01:37:34Z. Every suite exited 0. `out/gate.sh`
|
||||
is the script, `out/gate/summary.txt` the summary, and `out/gate/*.log`
|
||||
the full logs.
|
||||
|
||||
| Suite | Result |
|
||||
|---|---|
|
||||
| `packages/runs` | 43 pass, 0 fail |
|
||||
| `packages/tasks` | 71 pass, 0 fail |
|
||||
| `packages/bus` | 94 pass, 0 fail |
|
||||
| `packages/business` | 60 pass, 0 fail |
|
||||
| `packages/harness` | 59 pass, 0 fail |
|
||||
| `packages/cli` | 114 pass, 0 fail |
|
||||
| `packages/webui` | 62 pass, 0 fail |
|
||||
| `packages/seat` | 27 pass, 0 fail |
|
||||
| `test-auth.sh` | 15 passed, 0 failed |
|
||||
| `test-conductor.sh` | 17 passed, 0 failed |
|
||||
| `test-config.sh` | 24 passed, 0 failed |
|
||||
| `test-discord.sh` | 66 passed, 0 failed |
|
||||
| `test-extension-package.sh` | 18 passed, 0 failed |
|
||||
| `test-foundation.sh` | 44 passed, 0 failed |
|
||||
| `test-queue.sh` | 27 passed, 0 failed |
|
||||
| `test-release.sh` | 14 passed, 0 failed |
|
||||
| `test-task.sh` | 98 passed, 0 failed |
|
||||
|
||||
Those are all nine `scripts/test-*.sh` at the base. Afterwards I removed
|
||||
the `rocko-r82_default` network.
|
||||
@@ -0,0 +1 @@
|
||||
876f1ffe0931e589c29d4e633d2f957f02c39fd4
|
||||
@@ -0,0 +1,217 @@
|
||||
diff --git a/agents/rocko/work/queue-82/byte-check.sh b/agents/rocko/work/queue-82/byte-check.sh
|
||||
new file mode 100755
|
||||
index 00000000..4ec3c721
|
||||
--- /dev/null
|
||||
+++ b/agents/rocko/work/queue-82/byte-check.sh
|
||||
@@ -0,0 +1,67 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# Row 82 (#1551): compare `list` and `show` from two trees, byte for byte.
|
||||
+# Usage: byte-check.sh <base-tree> <candidate-tree> <out-dir>.
|
||||
+# Part 1 seeds a scratch data root with well-formed records only; part 2
|
||||
+# reads the data root of the caller's own config (read-only: list and show
|
||||
+# never write). Each command's stdout, stderr and exit status must match.
|
||||
+# Part 3 seeds damaged records and only records both outputs, because the
|
||||
+# base crashes there and the candidate shouldn't.
|
||||
+set -euo pipefail
|
||||
+BASE="$(cd "${1:?usage}" && pwd)"; CAND="$(cd "${2:?usage}" && pwd)"; OUT="${3:?usage}"
|
||||
+mkdir -p "$OUT"
|
||||
+S="$(mktemp -d)"; trap 'rm -rf "$S"' EXIT
|
||||
+fail=0
|
||||
+
|
||||
+run() { # run TREE TAG CONFIG ARGS... -> $OUT/TAG.{out,err,rc}
|
||||
+ local tree=$1 tag=$2 config=$3; shift 3
|
||||
+ set +e
|
||||
+ if [ -n "$config" ]; then MOSAIC_CONFIG="$config" node "$tree/scripts/mosaic-task.mjs" "$@" >"$OUT/$tag.out" 2>"$OUT/$tag.err"
|
||||
+ else node "$tree/scripts/mosaic-task.mjs" "$@" >"$OUT/$tag.out" 2>"$OUT/$tag.err"; fi
|
||||
+ echo $? >"$OUT/$tag.rc"
|
||||
+ set -e
|
||||
+}
|
||||
+same() { # same NAME CONFIG ARGS...
|
||||
+ local name=$1 config=$2; shift 2
|
||||
+ run "$BASE" "$name.base" "$config" "$@"; run "$CAND" "$name.cand" "$config" "$@"
|
||||
+ local x
|
||||
+ for x in out err rc; do
|
||||
+ if ! cmp -s "$OUT/$name.base.$x" "$OUT/$name.cand.$x"; then echo "DIFFERS $name ($x)"; fail=1; return; fi
|
||||
+ done
|
||||
+ echo "same $name (rc $(cat "$OUT/$name.base.rc"), $(wc -l <"$OUT/$name.base.out") lines)"
|
||||
+}
|
||||
+seed() { # seed DIR RUNID FILE JSON
|
||||
+ mkdir -p "$1/runs/$2"; printf '%s\n' "$4" >"$1/runs/$2/$3"
|
||||
+}
|
||||
+config() { # config DATAROOT -> path of a scratch config for it
|
||||
+ printf '{"configVersion":1,"environment":"development","dataRoot":"%s","execution":{"backend":"docker","provider":"zai","model":"m"}}\n' "$1" >"$1.config.json"
|
||||
+ echo "$1.config.json"
|
||||
+}
|
||||
+
|
||||
+# Part 1: well-formed records.
|
||||
+D="$S/good"; mkdir -p "$D"
|
||||
+R='"runVersion":1,"missionId":null,"reason":null,"request":"hi","response":"hi","expectedExact":null,"tools":null,"provider":"zai","model":"m","startedAt":"2026-01-01T00:00:00.000Z","finishedAt":"2026-01-01T00:00:01.000Z","durationMs":1000,"exitCode":0,"signal":null,"sessionForkFrom":null'
|
||||
+seed "$D" r-20260101T000000Z-aaaaaa result.json "{$R,\"runId\":\"r-20260101T000000Z-aaaaaa\",\"taskId\":\"t-one\",\"status\":\"succeeded\",\"workspace\":\"ws1\",\"session\":\"s1\"}"
|
||||
+seed "$D" r-20260101T000100Z-bbbbbb result.json "{$R,\"runId\":\"r-20260101T000100Z-bbbbbb\",\"taskId\":\"t-a-very-long-task-id-over-18\",\"status\":\"failed\",\"workspace\":null,\"session\":null}"
|
||||
+seed "$D" r-20260101T000200Z-cccccc result.json "{$R,\"runId\":\"r-20260101T000200Z-cccccc\",\"taskId\":\"t-three\",\"status\":\"succeeded\",\"workspace\":\":run\",\"session\":null}"
|
||||
+seed "$D" r-20260101T000300Z-dddddd result.json "{$R,\"runId\":\"r-20260101T000300Z-dddddd\",\"taskId\":\"t-four\",\"status\":\"timeout\"}"
|
||||
+seed "$D" r-20260101T000400Z-eeeeee task.json '{"id":"t-five"}'
|
||||
+seed "$D" r-.bad result.json "{$R,\"taskId\":\"t-bad\",\"status\":\"succeeded\"}"
|
||||
+C="$(config "$D")"
|
||||
+same good-list "$C" list
|
||||
+for r in r-20260101T000000Z-aaaaaa r-20260101T000100Z-bbbbbb r-20260101T000200Z-cccccc r-20260101T000300Z-dddddd r-20260101T000400Z-eeeeee; do
|
||||
+ same "good-show-$r" "$C" show "$r"
|
||||
+done
|
||||
+
|
||||
+# Part 2: the caller's real data root, through its own config.
|
||||
+same real-list "" list
|
||||
+for r in $(awk '{print $1}' "$OUT/real-list.base.out"); do same "real-show-$r" "" show "$r"; done
|
||||
+
|
||||
+# Part 3: damaged records, recorded only.
|
||||
+D="$S/damaged"; mkdir -p "$D"
|
||||
+seed "$D" r-20260101T000000Z-aaaaaa result.json "{$R,\"taskId\":\"t-one\",\"status\":\"succeeded\",\"workspace\":\"ws1\",\"session\":\"s1\"}"
|
||||
+seed "$D" r-20260101T000050Z-mmmmmm result.json '{}'
|
||||
+seed "$D" r-20260101T000100Z-bbbbbb result.json "{$R,\"taskId\":\"t-two\",\"status\":\"succeeded\",\"workspace\":7,\"session\":{\"name\":\"s\"}}"
|
||||
+C="$(config "$D")"
|
||||
+run "$BASE" damaged-list.base "$C" list; run "$CAND" damaged-list.cand "$C" list
|
||||
+echo "damaged list: base rc $(cat "$OUT/damaged-list.base.rc"), $(wc -l <"$OUT/damaged-list.base.out") lines; candidate rc $(cat "$OUT/damaged-list.cand.rc"), $(wc -l <"$OUT/damaged-list.cand.out") lines"
|
||||
+exit "$fail"
|
||||
diff --git a/agents/rocko/work/queue-82/mutants.sh b/agents/rocko/work/queue-82/mutants.sh
|
||||
new file mode 100755
|
||||
index 00000000..41ff04a8
|
||||
--- /dev/null
|
||||
+++ b/agents/rocko/work/queue-82/mutants.sh
|
||||
@@ -0,0 +1,45 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# Row 82 (#1551): rerun the listRuns mutants against a tree. Usage:
|
||||
+# mutants.sh <tree>. The tree needs the candidate's listRuns; its tests can
|
||||
+# be the candidate's or the base's. Each mutant drops one string check in
|
||||
+# listRuns (scripts/mosaic-task.mjs), putting back that field's base line,
|
||||
+# runs the runs suite, and restores the file from a saved copy, so the tree
|
||||
+# need not be committed. Prints "killed" or "SURVIVED" per mutant; exit 1 if
|
||||
+# any survives, a sed doesn't change the file, or the unmutated run fails.
|
||||
+set -euo pipefail
|
||||
+TREE="$(cd "${1:?usage: mutants.sh <tree>}" && pwd)"
|
||||
+cd "$TREE"
|
||||
+SRC=scripts/mosaic-task.mjs
|
||||
+run_tests() { node --test 'packages/runs/tests/*.test.mjs' >"$1" 2>&1; }
|
||||
+
|
||||
+# name | sed expression
|
||||
+MUTANTS=(
|
||||
+ 'status-unchecked|s/^ if (typeof result\.status === "string") status = result\.status;$/ status = result.status;/'
|
||||
+ 'taskid-unchecked|s/^ if (typeof result\.taskId === "string") taskId = result\.taskId;$/ taskId = result.taskId;/'
|
||||
+ 'workspace-unchecked|s/^ if (typeof result\.workspace === "string") workspace = result\.workspace;$/ workspace = String(result.workspace ?? "-");/'
|
||||
+ 'session-unchecked|s/^ if (typeof result\.session === "string") session = result\.session;$/ session = result.session ?? "-";/'
|
||||
+)
|
||||
+
|
||||
+OUT="${OUT:-$TREE/.mutants}"
|
||||
+mkdir -p "$OUT"
|
||||
+run_tests "$OUT/baseline.log" || { echo "baseline run failed: $OUT/baseline.log" >&2; exit 1; }
|
||||
+echo "baseline: pass"
|
||||
+status=0
|
||||
+for m in "${MUTANTS[@]}"; do
|
||||
+ IFS='|' read -r name expr <<<"$m"
|
||||
+ cp -p "$SRC" "$OUT/orig"
|
||||
+ sed -i -e "$expr" "$SRC"
|
||||
+ if cmp -s "$OUT/orig" "$SRC"; then
|
||||
+ echo "$name: NOT APPLIED (sed matched nothing)"; status=1; continue
|
||||
+ fi
|
||||
+ diff -u "$OUT/orig" "$SRC" >"$OUT/$name.diff" || true
|
||||
+ if run_tests "$OUT/$name.log"; then
|
||||
+ echo "$name: SURVIVED"; status=1
|
||||
+ else
|
||||
+ echo "$name: killed ($(grep -E '^✖' "$OUT/$name.log" | grep -v 'failing tests' | sed 's/ ([0-9.]*ms)$//' | sort -u | tr '\n' ';'))"
|
||||
+ fi
|
||||
+ cp -p "$OUT/orig" "$SRC"
|
||||
+ cmp -s "$OUT/orig" "$SRC" || { echo "restore failed: $SRC" >&2; exit 1; }
|
||||
+ rm -f "$OUT/orig"
|
||||
+done
|
||||
+exit "$status"
|
||||
diff --git a/packages/runs/README.md b/packages/runs/README.md
|
||||
index 8fd78082..9718bed4 100644
|
||||
--- a/packages/runs/README.md
|
||||
+++ b/packages/runs/README.md
|
||||
@@ -72,7 +72,10 @@ printed them.
|
||||
|
||||
`list` and `show` print exactly what they printed before this package
|
||||
existed, for any data root with no link out of it, no run document that
|
||||
-is JSON but not an object, and no unreadable directory.
|
||||
+is JSON but not an object, no `result.json` with a field of the wrong
|
||||
+type (a `status` or `taskId` that isn't a string, or a `workspace` or
|
||||
+`session` that is neither a string nor `null`), and no unreadable
|
||||
+directory.
|
||||
`agents/rocko/work/queue-56/byte-check.sh` checks that byte for byte
|
||||
against a seeded data root. Where those conditions don't hold, the
|
||||
output changes on purpose:
|
||||
@@ -82,6 +85,7 @@ output changes on purpose:
|
||||
| run directory or `result.json` linked out | read through the link | `list`: `unknown`; `show`: refuses (run directory) or `result.json: (missing or unreadable)` |
|
||||
| `runs/` linked out | read through the link | `list` and `show` refuse, exit 4 |
|
||||
| `result.json` is `5` or `[]` | `list` crashed; `show` printed `undefined` fields | `unknown`; `(missing or unreadable)` |
|
||||
+| `result.json` is an object whose `status` or `taskId` isn't a string, or whose `workspace` or `session` is neither a string nor `null` (`{}`, a numeric `status`, a `null` `taskId`) | `list` crashed on a `status` or `taskId` that isn't a string, hiding every run after it, and printed a `workspace` or `session` that is neither a string nor `null` through `String` | `list`: `unknown` for the status, `-` for each other field, and every later run still lists; `show` as before |
|
||||
| `task.json` or `mission.json` is JSON but not an object | `show` printed its snapshot line | snapshot line omitted |
|
||||
| run is a regular file | `show` crashed | `run not found`, exit 4 |
|
||||
| `runs/` unreadable | `list` printed nothing | refuses, exit 4 |
|
||||
diff --git a/packages/runs/tests/task-cli.test.mjs b/packages/runs/tests/task-cli.test.mjs
|
||||
index ed13ecde..a7c1caed 100644
|
||||
--- a/packages/runs/tests/task-cli.test.mjs
|
||||
+++ b/packages/runs/tests/task-cli.test.mjs
|
||||
@@ -32,6 +32,34 @@ test("list prints each run in the established format", (t) => {
|
||||
`${B} unknown task=- ws=- session=-\n`);
|
||||
});
|
||||
|
||||
+test("list prints a damaged result.json as unknown and keeps listing the runs after it", (t) => {
|
||||
+ const { dataRoot } = scratch(t);
|
||||
+ const M = "r-20260101T000050Z-mmmmmm";
|
||||
+ write(path.join(dataRoot, "runs", A, "result.json"), { ...RESULT, workspace: "ws1", session: "s1" });
|
||||
+ write(path.join(dataRoot, "runs", M, "result.json"), {});
|
||||
+ write(path.join(dataRoot, "runs", B, "result.json"), { ...RESULT, taskId: "t-two", workspace: ":run" });
|
||||
+ const out = task(t, dataRoot, "list");
|
||||
+ assert.equal(out.status, 0, out.stderr);
|
||||
+ assert.equal(out.stdout,
|
||||
+ `${A} succeeded task=t-one ws=ws1 session=s1\n` +
|
||||
+ `${M} unknown task=- ws=- session=-\n` +
|
||||
+ `${B} succeeded task=t-two ws=:run session=-\n`);
|
||||
+});
|
||||
+
|
||||
+test("list prints each result field that isn't a string as unknown or -", (t) => {
|
||||
+ const { dataRoot } = scratch(t);
|
||||
+ const runs = [
|
||||
+ ["r-20260101T000000Z-status", { status: 5 }, "unknown task=t-one ws=- session=-"],
|
||||
+ ["r-20260101T000001Z-taskid", { taskId: null }, "succeeded task=- ws=- session=-"],
|
||||
+ ["r-20260101T000002Z-worksp", { workspace: 7 }, "succeeded task=t-one ws=- session=-"],
|
||||
+ ["r-20260101T000003Z-sessin", { session: { name: "s1" } }, "succeeded task=t-one ws=- session=-"],
|
||||
+ ];
|
||||
+ for (const [runId, damage] of runs) write(path.join(dataRoot, "runs", runId, "result.json"), { ...RESULT, ...damage });
|
||||
+ const out = task(t, dataRoot, "list");
|
||||
+ assert.equal(out.status, 0, out.stderr);
|
||||
+ assert.equal(out.stdout, runs.map(([runId, , line]) => `${runId} ${line}\n`).join(""));
|
||||
+});
|
||||
+
|
||||
test("show prints the run in the established format", (t) => {
|
||||
const { dataRoot } = scratch(t);
|
||||
const dir = path.join(dataRoot, "runs", A);
|
||||
diff --git a/scripts/mosaic-task.mjs b/scripts/mosaic-task.mjs
|
||||
index cf8399a0..fc4e3845 100755
|
||||
--- a/scripts/mosaic-task.mjs
|
||||
+++ b/scripts/mosaic-task.mjs
|
||||
@@ -470,18 +470,19 @@ function readRuns(read) {
|
||||
function listRuns() {
|
||||
const resolved = loadConfig();
|
||||
for (const { runId, result } of readRuns(() => listRunRecords(resolved.dataRoot))) {
|
||||
- // An incomplete or unreadable run record (result null) reports as unknown.
|
||||
+ // An incomplete or unreadable run record (result null) reports as unknown,
|
||||
+ // and so does each field of a damaged one that isn't a string.
|
||||
let status = "unknown";
|
||||
let taskId = "-";
|
||||
let workspace = "-";
|
||||
let session = "-";
|
||||
if (result) {
|
||||
- status = result.status;
|
||||
- taskId = result.taskId;
|
||||
- workspace = result.workspace ?? "-";
|
||||
- session = result.session ?? "-";
|
||||
+ if (typeof result.status === "string") status = result.status;
|
||||
+ if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
+ if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
+ if (typeof result.session === "string") session = result.session;
|
||||
}
|
||||
- process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${String(workspace).padEnd(10)} session=${session}\n`);
|
||||
+ process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
# Row 82 (#1551): compare `list` and `show` from two trees, byte for byte.
|
||||
# Usage: byte-check.sh <base-tree> <candidate-tree> <out-dir>.
|
||||
# Part 1 seeds a scratch data root with well-formed records only; part 2
|
||||
# reads the data root of the caller's own config (read-only: list and show
|
||||
# never write). Each command's stdout, stderr and exit status must match.
|
||||
# Part 3 seeds damaged records and only records both outputs, because the
|
||||
# base crashes there and the candidate shouldn't.
|
||||
set -euo pipefail
|
||||
BASE="$(cd "${1:?usage}" && pwd)"; CAND="$(cd "${2:?usage}" && pwd)"; OUT="${3:?usage}"
|
||||
mkdir -p "$OUT"
|
||||
S="$(mktemp -d)"; trap 'rm -rf "$S"' EXIT
|
||||
fail=0
|
||||
|
||||
run() { # run TREE TAG CONFIG ARGS... -> $OUT/TAG.{out,err,rc}
|
||||
local tree=$1 tag=$2 config=$3; shift 3
|
||||
set +e
|
||||
if [ -n "$config" ]; then MOSAIC_CONFIG="$config" node "$tree/scripts/mosaic-task.mjs" "$@" >"$OUT/$tag.out" 2>"$OUT/$tag.err"
|
||||
else node "$tree/scripts/mosaic-task.mjs" "$@" >"$OUT/$tag.out" 2>"$OUT/$tag.err"; fi
|
||||
echo $? >"$OUT/$tag.rc"
|
||||
set -e
|
||||
}
|
||||
same() { # same NAME CONFIG ARGS...
|
||||
local name=$1 config=$2; shift 2
|
||||
run "$BASE" "$name.base" "$config" "$@"; run "$CAND" "$name.cand" "$config" "$@"
|
||||
local x
|
||||
for x in out err rc; do
|
||||
if ! cmp -s "$OUT/$name.base.$x" "$OUT/$name.cand.$x"; then echo "DIFFERS $name ($x)"; fail=1; return; fi
|
||||
done
|
||||
echo "same $name (rc $(cat "$OUT/$name.base.rc"), $(wc -l <"$OUT/$name.base.out") lines)"
|
||||
}
|
||||
seed() { # seed DIR RUNID FILE JSON
|
||||
mkdir -p "$1/runs/$2"; printf '%s\n' "$4" >"$1/runs/$2/$3"
|
||||
}
|
||||
config() { # config DATAROOT -> path of a scratch config for it
|
||||
printf '{"configVersion":1,"environment":"development","dataRoot":"%s","execution":{"backend":"docker","provider":"zai","model":"m"}}\n' "$1" >"$1.config.json"
|
||||
echo "$1.config.json"
|
||||
}
|
||||
|
||||
# Part 1: well-formed records.
|
||||
D="$S/good"; mkdir -p "$D"
|
||||
R='"runVersion":1,"missionId":null,"reason":null,"request":"hi","response":"hi","expectedExact":null,"tools":null,"provider":"zai","model":"m","startedAt":"2026-01-01T00:00:00.000Z","finishedAt":"2026-01-01T00:00:01.000Z","durationMs":1000,"exitCode":0,"signal":null,"sessionForkFrom":null'
|
||||
seed "$D" r-20260101T000000Z-aaaaaa result.json "{$R,\"runId\":\"r-20260101T000000Z-aaaaaa\",\"taskId\":\"t-one\",\"status\":\"succeeded\",\"workspace\":\"ws1\",\"session\":\"s1\"}"
|
||||
seed "$D" r-20260101T000100Z-bbbbbb result.json "{$R,\"runId\":\"r-20260101T000100Z-bbbbbb\",\"taskId\":\"t-a-very-long-task-id-over-18\",\"status\":\"failed\",\"workspace\":null,\"session\":null}"
|
||||
seed "$D" r-20260101T000200Z-cccccc result.json "{$R,\"runId\":\"r-20260101T000200Z-cccccc\",\"taskId\":\"t-three\",\"status\":\"succeeded\",\"workspace\":\":run\",\"session\":null}"
|
||||
seed "$D" r-20260101T000300Z-dddddd result.json "{$R,\"runId\":\"r-20260101T000300Z-dddddd\",\"taskId\":\"t-four\",\"status\":\"timeout\"}"
|
||||
seed "$D" r-20260101T000400Z-eeeeee task.json '{"id":"t-five"}'
|
||||
seed "$D" r-.bad result.json "{$R,\"taskId\":\"t-bad\",\"status\":\"succeeded\"}"
|
||||
C="$(config "$D")"
|
||||
same good-list "$C" list
|
||||
for r in r-20260101T000000Z-aaaaaa r-20260101T000100Z-bbbbbb r-20260101T000200Z-cccccc r-20260101T000300Z-dddddd r-20260101T000400Z-eeeeee; do
|
||||
same "good-show-$r" "$C" show "$r"
|
||||
done
|
||||
|
||||
# Part 2: the caller's real data root, through its own config.
|
||||
same real-list "" list
|
||||
for r in $(awk '{print $1}' "$OUT/real-list.base.out"); do same "real-show-$r" "" show "$r"; done
|
||||
|
||||
# Part 3: damaged records, recorded only.
|
||||
D="$S/damaged"; mkdir -p "$D"
|
||||
seed "$D" r-20260101T000000Z-aaaaaa result.json "{$R,\"taskId\":\"t-one\",\"status\":\"succeeded\",\"workspace\":\"ws1\",\"session\":\"s1\"}"
|
||||
seed "$D" r-20260101T000050Z-mmmmmm result.json '{}'
|
||||
seed "$D" r-20260101T000100Z-bbbbbb result.json "{$R,\"taskId\":\"t-two\",\"status\":\"succeeded\",\"workspace\":7,\"session\":{\"name\":\"s\"}}"
|
||||
C="$(config "$D")"
|
||||
run "$BASE" damaged-list.base "$C" list; run "$CAND" damaged-list.cand "$C" list
|
||||
echo "damaged list: base rc $(cat "$OUT/damaged-list.base.rc"), $(wc -l <"$OUT/damaged-list.base.out") lines; candidate rc $(cat "$OUT/damaged-list.cand.rc"), $(wc -l <"$OUT/damaged-list.cand.out") lines"
|
||||
exit "$fail"
|
||||
@@ -0,0 +1,5 @@
|
||||
0eee966edb918559e94c8bc09973a45cdf9a00b1a2dfbd4ced374fc7856e0c9b agents/rocko/work/queue-82/byte-check.sh
|
||||
a9e17c947d31b55ce3ab5324a5af7dd39baa06d95c19a98fe3992c4f44460dee agents/rocko/work/queue-82/mutants.sh
|
||||
144d93f54de8a15c9609b7c1e097593f8127c7ad930a732533a9bb0dd32a2ebf packages/runs/README.md
|
||||
fdfb3a3b7cf7e14d2ae3050a004cdee3c663b168a0f9e42670a1a878da26932f packages/runs/tests/task-cli.test.mjs
|
||||
f94c22e020e8f4d573665fe3e91d84948ebe437e0b93dc31278c3fcfdaa9686b scripts/mosaic-task.mjs
|
||||
@@ -0,0 +1,5 @@
|
||||
agents/rocko/work/queue-82/byte-check.sh
|
||||
agents/rocko/work/queue-82/mutants.sh
|
||||
packages/runs/README.md
|
||||
packages/runs/tests/task-cli.test.mjs
|
||||
scripts/mosaic-task.mjs
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# Row 82 (#1551): rerun the listRuns mutants against a tree. Usage:
|
||||
# mutants.sh <tree>. The tree needs the candidate's listRuns; its tests can
|
||||
# be the candidate's or the base's. Each mutant drops one string check in
|
||||
# listRuns (scripts/mosaic-task.mjs), putting back that field's base line,
|
||||
# runs the runs suite, and restores the file from a saved copy, so the tree
|
||||
# need not be committed. Prints "killed" or "SURVIVED" per mutant; exit 1 if
|
||||
# any survives, a sed doesn't change the file, or the unmutated run fails.
|
||||
set -euo pipefail
|
||||
TREE="$(cd "${1:?usage: mutants.sh <tree>}" && pwd)"
|
||||
cd "$TREE"
|
||||
SRC=scripts/mosaic-task.mjs
|
||||
run_tests() { node --test 'packages/runs/tests/*.test.mjs' >"$1" 2>&1; }
|
||||
|
||||
# name | sed expression
|
||||
MUTANTS=(
|
||||
'status-unchecked|s/^ if (typeof result\.status === "string") status = result\.status;$/ status = result.status;/'
|
||||
'taskid-unchecked|s/^ if (typeof result\.taskId === "string") taskId = result\.taskId;$/ taskId = result.taskId;/'
|
||||
'workspace-unchecked|s/^ if (typeof result\.workspace === "string") workspace = result\.workspace;$/ workspace = String(result.workspace ?? "-");/'
|
||||
'session-unchecked|s/^ if (typeof result\.session === "string") session = result\.session;$/ session = result.session ?? "-";/'
|
||||
)
|
||||
|
||||
OUT="${OUT:-$TREE/.mutants}"
|
||||
mkdir -p "$OUT"
|
||||
run_tests "$OUT/baseline.log" || { echo "baseline run failed: $OUT/baseline.log" >&2; exit 1; }
|
||||
echo "baseline: pass"
|
||||
status=0
|
||||
for m in "${MUTANTS[@]}"; do
|
||||
IFS='|' read -r name expr <<<"$m"
|
||||
cp -p "$SRC" "$OUT/orig"
|
||||
sed -i -e "$expr" "$SRC"
|
||||
if cmp -s "$OUT/orig" "$SRC"; then
|
||||
echo "$name: NOT APPLIED (sed matched nothing)"; status=1; continue
|
||||
fi
|
||||
diff -u "$OUT/orig" "$SRC" >"$OUT/$name.diff" || true
|
||||
if run_tests "$OUT/$name.log"; then
|
||||
echo "$name: SURVIVED"; status=1
|
||||
else
|
||||
echo "$name: killed ($(grep -E '^✖' "$OUT/$name.log" | grep -v 'failing tests' | sed 's/ ([0-9.]*ms)$//' | sort -u | tr '\n' ';'))"
|
||||
fi
|
||||
cp -p "$OUT/orig" "$SRC"
|
||||
cmp -s "$OUT/orig" "$SRC" || { echo "restore failed: $SRC" >&2; exit 1; }
|
||||
rm -f "$OUT/orig"
|
||||
done
|
||||
exit "$status"
|
||||
@@ -0,0 +1,14 @@
|
||||
same good-list (rc 0, 6 lines)
|
||||
same good-show-r-20260101T000000Z-aaaaaa (rc 0, 11 lines)
|
||||
same good-show-r-20260101T000100Z-bbbbbb (rc 0, 9 lines)
|
||||
same good-show-r-20260101T000200Z-cccccc (rc 0, 10 lines)
|
||||
same good-show-r-20260101T000300Z-dddddd (rc 0, 9 lines)
|
||||
same good-show-r-20260101T000400Z-eeeeee (rc 0, 4 lines)
|
||||
same real-list (rc 0, 6 lines)
|
||||
same real-show-r-20260903T193847Z-b0cdc5 (rc 0, 13 lines)
|
||||
same real-show-r-20260903T193926Z-00bbba (rc 0, 13 lines)
|
||||
same real-show-r-20260903T205744Z-44485b (rc 0, 13 lines)
|
||||
same real-show-r-20260903T205750Z-f444a2 (rc 0, 13 lines)
|
||||
same real-show-r-20260903T205812Z-384152 (rc 0, 13 lines)
|
||||
same real-show-r-20260906T024609Z-68ee7f (rc 0, 11 lines)
|
||||
damaged list: base rc 1, 1 lines; candidate rc 0, 3 lines
|
||||
@@ -0,0 +1,13 @@
|
||||
file:///mnt/storage/scratch/rocko-r82-base/scripts/mosaic-task.mjs:484
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${String(workspace).padEnd(10)} session=${session}\n`);
|
||||
^
|
||||
|
||||
TypeError: Cannot read properties of undefined (reading 'padEnd')
|
||||
at listRuns (file:///mnt/storage/scratch/rocko-r82-base/scripts/mosaic-task.mjs:484:46)
|
||||
at file:///mnt/storage/scratch/rocko-r82-base/scripts/mosaic-task.mjs:644:5
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:569:25)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async node:internal/modules/esm/loader:650:26
|
||||
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
|
||||
|
||||
Node.js v26.8.1
|
||||
@@ -0,0 +1 @@
|
||||
r-20260101T000000Z-aaaaaa succeeded task=t-one ws=ws1 session=s1
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,3 @@
|
||||
r-20260101T000000Z-aaaaaa succeeded task=t-one ws=ws1 session=s1
|
||||
r-20260101T000050Z-mmmmmm unknown task=- ws=- session=-
|
||||
r-20260101T000100Z-bbbbbb succeeded task=t-two ws=- session=-
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,6 @@
|
||||
r-.bad succeeded task=t-bad ws=- session=-
|
||||
r-20260101T000000Z-aaaaaa succeeded task=t-one ws=ws1 session=s1
|
||||
r-20260101T000100Z-bbbbbb failed task=t-a-very-long-task-id-over-18 ws=- session=-
|
||||
r-20260101T000200Z-cccccc succeeded task=t-three ws=:run session=-
|
||||
r-20260101T000300Z-dddddd timeout task=t-four ws=- session=-
|
||||
r-20260101T000400Z-eeeeee unknown task=- ws=- session=-
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,6 @@
|
||||
r-.bad succeeded task=t-bad ws=- session=-
|
||||
r-20260101T000000Z-aaaaaa succeeded task=t-one ws=ws1 session=s1
|
||||
r-20260101T000100Z-bbbbbb failed task=t-a-very-long-task-id-over-18 ws=- session=-
|
||||
r-20260101T000200Z-cccccc succeeded task=t-three ws=:run session=-
|
||||
r-20260101T000300Z-dddddd timeout task=t-four ws=- session=-
|
||||
r-20260101T000400Z-eeeeee unknown task=- ws=- session=-
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
run: r-20260101T000000Z-aaaaaa
|
||||
status: succeeded
|
||||
task: t-one
|
||||
workspace: ws1
|
||||
session: s1
|
||||
adapter: (see config) provider=zai model=m
|
||||
request: "hi"
|
||||
response: "hi"
|
||||
timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)
|
||||
exit: 0
|
||||
artifacts: result.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
run: r-20260101T000000Z-aaaaaa
|
||||
status: succeeded
|
||||
task: t-one
|
||||
workspace: ws1
|
||||
session: s1
|
||||
adapter: (see config) provider=zai model=m
|
||||
request: "hi"
|
||||
response: "hi"
|
||||
timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)
|
||||
exit: 0
|
||||
artifacts: result.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,9 @@
|
||||
run: r-20260101T000100Z-bbbbbb
|
||||
status: failed
|
||||
task: t-a-very-long-task-id-over-18
|
||||
adapter: (see config) provider=zai model=m
|
||||
request: "hi"
|
||||
response: "hi"
|
||||
timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)
|
||||
exit: 0
|
||||
artifacts: result.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,9 @@
|
||||
run: r-20260101T000100Z-bbbbbb
|
||||
status: failed
|
||||
task: t-a-very-long-task-id-over-18
|
||||
adapter: (see config) provider=zai model=m
|
||||
request: "hi"
|
||||
response: "hi"
|
||||
timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)
|
||||
exit: 0
|
||||
artifacts: result.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
run: r-20260101T000200Z-cccccc
|
||||
status: succeeded
|
||||
task: t-three
|
||||
workspace: :run
|
||||
adapter: (see config) provider=zai model=m
|
||||
request: "hi"
|
||||
response: "hi"
|
||||
timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)
|
||||
exit: 0
|
||||
artifacts: result.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
run: r-20260101T000200Z-cccccc
|
||||
status: succeeded
|
||||
task: t-three
|
||||
workspace: :run
|
||||
adapter: (see config) provider=zai model=m
|
||||
request: "hi"
|
||||
response: "hi"
|
||||
timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)
|
||||
exit: 0
|
||||
artifacts: result.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,9 @@
|
||||
run: r-20260101T000300Z-dddddd
|
||||
status: timeout
|
||||
task: t-four
|
||||
adapter: (see config) provider=zai model=m
|
||||
request: "hi"
|
||||
response: "hi"
|
||||
timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)
|
||||
exit: 0
|
||||
artifacts: result.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,9 @@
|
||||
run: r-20260101T000300Z-dddddd
|
||||
status: timeout
|
||||
task: t-four
|
||||
adapter: (see config) provider=zai model=m
|
||||
request: "hi"
|
||||
response: "hi"
|
||||
timing: 2026-01-01T00:00:00.000Z -> 2026-01-01T00:00:01.000Z (1000 ms)
|
||||
exit: 0
|
||||
artifacts: result.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,4 @@
|
||||
run: r-20260101T000400Z-eeeeee
|
||||
result.json: (missing or unreadable)
|
||||
task snapshot: task.json present
|
||||
artifacts: task.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,4 @@
|
||||
run: r-20260101T000400Z-eeeeee
|
||||
result.json: (missing or unreadable)
|
||||
task snapshot: task.json present
|
||||
artifacts: task.json
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -u
|
||||
W=/mnt/storage/scratch/rocko-r82; G=/mnt/storage/scratch/rocko-r82-out/gate
|
||||
mkdir -p $G; cd $W
|
||||
date -u +%Y-%m-%dT%H:%M:%SZ > $G/start.txt
|
||||
: > $G/summary.txt
|
||||
for p in runs tasks bus business harness cli webui seat; do
|
||||
node --test "packages/$p/tests/*.test.mjs" > $G/$p.log 2>&1; rc=$?
|
||||
echo "$p rc=$rc $(grep -E '^ℹ (pass|fail|skipped)' $G/$p.log | tr '\n' ' ')" >> $G/summary.txt
|
||||
done
|
||||
for s in scripts/test-*.sh; do
|
||||
n=$(basename $s .sh)
|
||||
bash $s > $G/$n.log 2>&1; rc=$?
|
||||
echo "$n rc=$rc $(grep -iE '[0-9]+ passed|passed.*failed|failed' $G/$n.log | tail -1)" >> $G/summary.txt
|
||||
done
|
||||
date -u +%Y-%m-%dT%H:%M:%SZ > $G/end.txt
|
||||
@@ -0,0 +1,102 @@
|
||||
✔ agents: a held role with nothing on the bus is idle; a role session gets the claim rows unchanged (35.125648ms)
|
||||
✔ agents: working counts what the holder received and has not read; routed alone is not working (37.645525ms)
|
||||
✔ agents: input needed is the role's open decisions routed to the human, gated first, then oldest (94.337261ms)
|
||||
✔ agents: working wins over waiting, and Input needed still shows (39.269694ms)
|
||||
✔ agents: a new holder doesn't inherit what the last one left unread; decisions stay with the role (53.919376ms)
|
||||
✔ agents: state reads only its own business, even for a run name both use (38.37603ms)
|
||||
✔ launch identity is stamped, payload identity is refused and stale holder cannot send (29.780881ms)
|
||||
✔ decision classes route from policy; gated resolution is human-only, choice and target must match (55.60725ms)
|
||||
✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (74.26478ms)
|
||||
✔ launch events require a human CLI capability; generic emit cannot forge authority events (40.136792ms)
|
||||
✔ within-role decisions close atomically and invalid options or blocking omissions refuse (45.83572ms)
|
||||
✔ observer capabilities read human inbox but cannot mutate or forge launch identity (30.401876ms)
|
||||
✔ task action subjects and linked decision trail are complete and ordered (41.23485ms)
|
||||
✔ launch binding is durable and reconnecting requires the identical trusted record (14.324723ms)
|
||||
✔ business isolation includes inherited object names and cross-business message references (25.992556ms)
|
||||
✔ authority never transfers between action, run, target, unresolved or replaced role holder (32.830679ms)
|
||||
✔ task projection uses schema current view, skipping earlier and equal-start polls (20.735873ms)
|
||||
✔ revocation permanently bars the old run from reclaiming first, including after broker restart (32.506966ms)
|
||||
✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (17.770565ms)
|
||||
✔ both arbiters require human resolution when their cross-role route is themselves (32.418579ms)
|
||||
✔ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (31.714095ms)
|
||||
✔ S1 adapter takes resolved limits and refs, rejects mismatched instance, never mutates input (2.775418ms)
|
||||
✔ credentials gives human and reader sessions service, account, role, date and state, and nothing else (27.457505ms)
|
||||
✔ credentials refuses a role session and any argument (31.615558ms)
|
||||
✔ credentials reads the status on each request, and a broker without one lists none (58.491251ms)
|
||||
✔ the broker process answers credentials without a token, path or variable in its output, log or store (142.796884ms)
|
||||
✔ only validated broker references load; returned data and exceptions cannot expose a known token (13.857314ms)
|
||||
✔ bad file modes, symlinks, repository/data paths, malformed tokens and missing dates refuse (9.617631ms)
|
||||
✔ expiry refuses use and env references never become client data (1.696471ms)
|
||||
✔ S1 parsed service refs work, service mismatch refuses, Gitea rotation due is a warning state (2.952212ms)
|
||||
✔ opaque tokens shorter than 16 characters refuse before use (0.681438ms)
|
||||
✔ roles lists open decisions routed to a role, and never the human inbox (56.142701ms)
|
||||
✔ recent lists closed decisions of every route, newest close first, with how each closed (80.063427ms)
|
||||
✔ recent stops at RECENT rows (186.440467ms)
|
||||
✔ every row is what trail already gives the same session for that id (42.095053ms)
|
||||
✔ a role session can't list decisions, so it can't read another role's open decisions (62.643476ms)
|
||||
✔ decisions is a read: one business, strict arguments, nothing written (51.659164ms)
|
||||
✔ endLaunch writes session.ended, releases the run claim and kills its capabilities (47.115298ms)
|
||||
✔ endLaunch refuses an unknown run, a second end and a rebind of the ended run (35.462782ms)
|
||||
✔ a restarted broker refuses to rebind an ended run; a refused rebind leaves the run unbound (32.89485ms)
|
||||
✔ endLaunch leaves a claim another run took alone (45.662087ms)
|
||||
✔ refuse records action.refused against the caller with the code only (25.038254ms)
|
||||
✔ launches off refuses role.launch with launch-revoked until launches on (36.417437ms)
|
||||
✔ broker process: launch ops authorize role.launch, record refusals and end runs (142.033814ms)
|
||||
✔ human proof binds CLI entry, process start and nonce; agents and incomplete ancestry refuse (2.895604ms)
|
||||
✔ process reader gets own kernel identity without exposing environment values (2.967503ms)
|
||||
✔ EACCES ancestor environments skip only markers; commands and registered launches still refuse (1.288504ms)
|
||||
✔ real pid 1 remains inspectable when its environment is protected (0.549593ms)
|
||||
✔ within-role sends cite an open gated launch decision without spending it or naming it in grants (62.361405ms)
|
||||
✔ missing and foreign-business citations refuse and roll back message and grant (56.524524ms)
|
||||
✔ cross-role sends still need a matching resolved decision and consume it once (50.773829ms)
|
||||
✔ broker process binds trusted launches, offers reader capabilities, refuses human mutation, closes cleanly (161.062697ms)
|
||||
✔ startup token refusal returns safe code without value or partial listening broker (100.454889ms)
|
||||
✔ loaded fixture token is absent from socket replies and SQLite, including refusal evidence (96.15826ms)
|
||||
✔ killed broker leaves an explicit stale lock; another process cannot silently reclaim it (152.406129ms)
|
||||
✔ trusted host registers later launches; socket clients never have a registration verb (88.458895ms)
|
||||
✔ runtime excludes declared project roots even when host supplies no repoRoots (59.175858ms)
|
||||
✔ a refused launch binding leaves the broker and existing capabilities alive; bad protocol stops it (74.240861ms)
|
||||
✔ v3b prototype refusals, views and append-only mutations (203.836516ms)
|
||||
✔ gated approval authorizes once, survives store reopen, and fresh approval works (84.411615ms)
|
||||
✔ another run cannot consume an approval; a failed check leaves it usable (46.433083ms)
|
||||
✔ two scheduled callers have exactly one grant and one consumed refusal (42.96404ms)
|
||||
✔ failed commit rolls consumption back; cross-role consumes and within-role stays reusable (63.979339ms)
|
||||
✔ class drift gated to cross-role refuses before consumption (30.3908ms)
|
||||
✔ class drift cross-role to gated refuses before consumption (34.687382ms)
|
||||
✔ class drift gated to within-role refuses before consumption (29.408074ms)
|
||||
✔ class drift cross-role to within-role refuses before consumption (35.55011ms)
|
||||
✔ class drift within-role to gated refuses before consumption (26.559239ms)
|
||||
✔ class drift within-role to cross-role refuses before consumption (24.538526ms)
|
||||
✔ message.send consumes approval and prevents a later send or authorize (36.075362ms)
|
||||
✔ role.revoke consumes approval and prevents a later revoke or authorize (32.411141ms)
|
||||
✔ creates private WAL store and excludes a second writer until explicit close (33.402497ms)
|
||||
✔ rollback is atomic and schema metadata is checked against trusted DDL, not just itself (32.725579ms)
|
||||
✔ existing empty database and symlink runtime directory refuse, never initialize over damage (52.894163ms)
|
||||
✔ crash during a transaction recovers no partial event after explicit fixture-only lock removal (119.872533ms)
|
||||
✔ writer refuses mixed at/read_at forms atomically, even through trusted SQL helpers (26.356351ms)
|
||||
✔ async transactions refuse before invoking their function (19.126056ms)
|
||||
✔ tasks rows carry priority and requirement for every session that reads tasks (88.534414ms)
|
||||
✔ the read model rebuilds from the ledger: a reopened bus and each trail give the same values (98.241426ms)
|
||||
✔ an empty business and one with snapshots but no task.created read cleanly (18.493864ms)
|
||||
✔ recordTask keeps sync reads and a role write apart (58.054867ms)
|
||||
✔ read_at must be one canonical UTC format, so the projection compares strings safely (28.511296ms)
|
||||
✔ a bad entry refuses the whole record (28.244054ms)
|
||||
✔ taskView reads the projection for one business (27.055647ms)
|
||||
✔ requestTask hands only a holder and a task verb to the handler, and records refusals (59.515511ms)
|
||||
✔ the server sends task verbs to the adapter with its own timeout; other verbs stay synchronous (305.08039ms)
|
||||
✔ without an adapter the server refuses every task verb (33.692005ms)
|
||||
✔ the runtime refuses an invalid adapter and closes a valid one (25.66876ms)
|
||||
✔ the process loads the S3 adapter from plain-data trackers (157.37478ms)
|
||||
✔ socket capability stamps launch identity; shared views use wire, no SQL client (71.73311ms)
|
||||
✔ two wire claims serialize; a lost reply never automatically retries (52.466688ms)
|
||||
✔ malformed, oversized and identity-forging envelopes refuse without echoing input (29.393334ms)
|
||||
✔ client preserves UTF-8 when a response divides a multibyte character (14.158797ms)
|
||||
✔ committed mutation followed by dropped reply reports unknown and is never retried (38.659928ms)
|
||||
ℹ tests 94
|
||||
ℹ suites 0
|
||||
ℹ pass 94
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 892.376079
|
||||
@@ -0,0 +1,68 @@
|
||||
✔ config directory and file path follow MOSAIC_CONFIG (2.458146ms)
|
||||
✔ the fixture business validates and comes back frozen (7.133681ms)
|
||||
✔ two instances may share a definition (2.037933ms)
|
||||
✔ top-level refusals (6.035556ms)
|
||||
✔ arbiters and projects (8.856757ms)
|
||||
✔ role instances (8.075528ms)
|
||||
✔ Vikunja bots (11.425754ms)
|
||||
✔ a role without Vikunja takes no tracker block (3.088102ms)
|
||||
✔ credential references match the definition's services (4.115636ms)
|
||||
✔ launch (13.371913ms)
|
||||
✔ loadBusiness: file checks (5.074781ms)
|
||||
✔ loadBusiness: not a regular file (120.964475ms)
|
||||
✔ loading writes nothing (1.700514ms)
|
||||
✔ names that are Object.prototype properties don't count as declared (3.824765ms)
|
||||
✔ the shipped example refuses as written and validates once filled in (0.973477ms)
|
||||
✔ usage errors exit 4 (506.839189ms)
|
||||
✔ validate: a good business exits 0 and prints instance digests (159.284029ms)
|
||||
✔ validate: project files (542.017444ms)
|
||||
✔ validate: missing files and a broken system config (511.45344ms)
|
||||
✔ validate: credential reference problems exit 2 and name each one (131.48111ms)
|
||||
✔ validate: a token file inside the repository is refused (117.4678ms)
|
||||
✔ validate: role definitions come from MOSAIC_ROLES_DIR (296.944342ms)
|
||||
✔ resolve: prints one instance's record (315.282052ms)
|
||||
✔ resolve: refusals (625.693279ms)
|
||||
✔ parse: exactly one of file or env, plus the service's date (4.263032ms)
|
||||
✔ check: a good file has no problems (1.292852ms)
|
||||
✔ check never opens the file: a write-only token passes (0.546724ms)
|
||||
✔ check: file problems (1.400397ms)
|
||||
✔ check: token files can't live in the repository or dataRoot, even through a linked directory (1.443259ms)
|
||||
✔ check: dates and environment references (0.653389ms)
|
||||
✔ path and load (3.481362ms)
|
||||
✔ refusals (1.779637ms)
|
||||
✔ systemVars flattens the validated config (2.77839ms)
|
||||
✔ precedence: system, business, project, project role, agent (7.623952ms)
|
||||
✔ limits narrow the definition and never widen it (3.723854ms)
|
||||
✔ role.launch stays within-role only for the instance the launch block names (7.689718ms)
|
||||
✔ limits.authority without role.launch leaves the launcher with no launch block (3.755099ms)
|
||||
✔ limits.authority narrows cross-role actions too (1.806401ms)
|
||||
✔ classify (1.87014ms)
|
||||
✔ the record carries what the broker and launcher need (1.287584ms)
|
||||
✔ digest: key order doesn't matter, any value change does (9.405478ms)
|
||||
✔ refusals (3.915224ms)
|
||||
✔ the four shipped version 2 roles load (4.576073ms)
|
||||
✔ shipped role scopes match addendum B section 2 and the SR runbook (1.588471ms)
|
||||
✔ shipped authority follows the note's table (0.895752ms)
|
||||
✔ version 1 files keep loading with no authority (1.566835ms)
|
||||
✔ the conductor policy isn't a role (0.45607ms)
|
||||
✔ a missing role file is exit 4, a symbolic link too (0.627864ms)
|
||||
✔ version 2 refusals (2.35214ms)
|
||||
✔ authority: closed vocabulary, no gated-only action, no overlap (4.276951ms)
|
||||
✔ credentials: Gitea scopes (1.594128ms)
|
||||
✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.876431ms)
|
||||
✔ credentials: services (1.102266ms)
|
||||
✔ contract: a non-empty regular Markdown file beside the role file (1.568489ms)
|
||||
✔ every key names known layers and a merge rule (1.412774ms)
|
||||
✔ unknown keys and wrong layers refuse (1.21608ms)
|
||||
✔ types (3.171619ms)
|
||||
✔ merge: defaults, then the most specific layer wins (0.473463ms)
|
||||
✔ merge: limits only narrow, and provenance lists each source (2.192836ms)
|
||||
✔ merge doesn't change its inputs (0.28178ms)
|
||||
ℹ tests 60
|
||||
ℹ suites 0
|
||||
ℹ pass 60
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 3300.57403
|
||||
@@ -0,0 +1,124 @@
|
||||
✔ every screen and overlay fits 120x36, 80x24 and the narrow layout, row for row (6555.819005ms)
|
||||
✔ width counts terminal cells: wide CJK and emoji 2, U+FE0F after a one-cell base 1, marks 0 (223.787808ms)
|
||||
✔ broker text is shown, never interpreted: no raw control character or bidi override reaches the terminal (321.198277ms)
|
||||
✔ NO_COLOR: no escape codes, except reverse video on the selected row (373.247329ms)
|
||||
✔ 1-9 shows the decide flow's own lines and question; only y resolves (60.349302ms)
|
||||
✔ the app shows the same decide text as mosaic decide (32.843288ms)
|
||||
✔ any key but y or Y at the question answers No; nothing is sent (266.383687ms)
|
||||
✔ below 40x10 the question is hidden, so every key answers it No, y included (Filbert R3) (85.216289ms)
|
||||
✔ a throw while answering the question goes to crash, sends nothing and leaves no job pending (26.398721ms)
|
||||
✔ type-ahead never answers the question: a paste, keys typed before it is drawn, keys inside askMs (460.107975ms)
|
||||
✔ quitting at the question answers No and sends nothing, armed or not (46.466728ms)
|
||||
✔ a timer tick reads nothing under an overlay, never answers the question, and keeps a resolved status (35.113676ms)
|
||||
✔ a long question is cut inside the question; the action, target, choice and prompt stay (Dewey B1) (52.843439ms)
|
||||
✔ a decide box too big for the terminal says so, and every key answers it No, y included (Dewey B1, round 3) (387.290303ms)
|
||||
✔ at every size the decide box shows each line y depends on, or says it is hidden (12141.133548ms)
|
||||
✔ outcome unknown: the CLI's sentence, no retry, then the trail or a re-read (73.619514ms)
|
||||
✔ refused and failed reads keep the last list, marked stale; a refused decide says refused (30.492051ms)
|
||||
✔ keys: views, moving, trail of a selection, the command line, help and quit (84.38679ms)
|
||||
✔ one option: the status line says Press 1, not 1-1 (20.813191ms)
|
||||
✔ no business: the app says so and :business picks one (11.891036ms)
|
||||
✔ mosaic with no argument: exit 3 in an agent run, exit 4 with the usage off a terminal, the app on one (2.118675ms)
|
||||
✔ scripts/mosaic with no argument reaches the app entry; the seat usage it printed before has not drifted (262.109028ms)
|
||||
✔ strings to keep exactly live once, in the decide flow and the transport; the app does not restate them (0.488795ms)
|
||||
✔ decide with --note still asks; a No sends nothing (10.627548ms)
|
||||
✔ the app's business comes from a live bus host only (1.240991ms)
|
||||
✔ runApp leaves the terminal as it found it on q, end of input, SIGTERM, SIGINT, SIGHUP and an error, the first frame's included (10.136754ms)
|
||||
✔ draw is pure: same state, same frame (1.521805ms)
|
||||
✔ inbox lists only decisions routed to the human, with what approving authorizes and how to decide (84.554788ms)
|
||||
✔ decide resolves by id prefix with --yes, and the trail shows it in broker order with the task to follow (44.884862ms)
|
||||
✔ decide refuses without a terminal or --yes, on an unknown option and on a short reference (78.201683ms)
|
||||
✔ decide prints a declining choice as declining (50.249936ms)
|
||||
✔ an unknown outcome is reported once and never resent (31.457704ms)
|
||||
✔ a decision closed before the answer arrives exits 2 and points at its trail (46.181395ms)
|
||||
✔ a prefix that matches two open decisions exits 2 and resolves neither (37.992652ms)
|
||||
✔ without --business a command uses the live host's business, and a stale host.json is not a host (62.721533ms)
|
||||
✔ every human command refuses inside an agent run before it touches the bus (35.895863ms)
|
||||
✔ usage errors exit 4; no business and no host is a usage error (76.349333ms)
|
||||
✔ agents and tasks print through the broker (34.3749ms)
|
||||
✔ notify.json: missing, loose, malformed and extra keys refuse; a binding or null passes (17.107265ms)
|
||||
✔ bootConfig builds the broker's boot message for one business, with no trackers key when no project names one (90.148444ms)
|
||||
✔ trackers come from the tracker.* variables of the one project that names a tracker project (357.48691ms)
|
||||
✔ with two projects, the one that sets tracker.project supplies the tracker and the other is no conflict (133.200932ms)
|
||||
✔ two projects that each name a tracker project refuse, since the boot shape holds one (255.218143ms)
|
||||
✔ a business without tracker.baseUrl gets no trackers entry (399.985193ms)
|
||||
✔ an unknown business and a broken system config refuse with exit 3 (400.110759ms)
|
||||
✔ empty views say so (1.748834ms)
|
||||
✔ the trail keeps the broker's order and names a decision's task without its rows (3.637307ms)
|
||||
✔ tasks print the tracker fields the snapshot carries (1.878757ms)
|
||||
✔ the host boots the broker, binds a launch in process, and the notifier DMs a blocking decision exactly once (1607.107464ms)
|
||||
✔ a notifier that dies takes the host down with exit 1, so the unit restarts the pair (791.236901ms)
|
||||
✔ a second host for the same data root refuses with exit 3 while the first runs (933.693918ms)
|
||||
✔ a broker reply that misses the wait breaks the channel: the late reply answers nothing, later requests refuse, the host exits 1 (1596.055918ms)
|
||||
✔ a broker reply with another request's id, or none, breaks the channel and the host exits 1 (998.611914ms)
|
||||
✔ a broker reply with no request waiting breaks the channel and the host exits 1 (357.26491ms)
|
||||
✔ a notifier that refuses stops the broker and the host refuses with exit 3 (540.103716ms)
|
||||
✔ a notifier that refuses after the broker died still refuses with exit 3, without a send to the dead broker (261.018205ms)
|
||||
✔ a notifier that dies before it replies, after the broker died, still refuses, without a send to the dead broker (135.221446ms)
|
||||
✔ a close send that fails with EPIPE after the notifier refuses still gives the notifier's refusal, exit 3 (209.568288ms)
|
||||
✔ a close send that fails with EPIPE after the notifier dies unanswered still gives the notifier's error (107.686103ms)
|
||||
✔ close() whose stop and close sends fail with EPIPE still finishes, with exit 1 (229.589229ms)
|
||||
✔ watchChildren reports a child that died before it was called, and one that dies later (39.758755ms)
|
||||
✔ bus stop refuses to signal a live pid that is not a bus host (204.905647ms)
|
||||
✔ bus start refuses with exit 3 and the code when the broker refuses to boot; bus status names the lock (419.037526ms)
|
||||
✔ bus start refuses with exit 3 without a notifier config (149.506963ms)
|
||||
✔ bus start runs until bus stop; status reports it while it runs (963.967544ms)
|
||||
✔ bus-service.sh renders the unit and installs it into a given directory (74.7971ms)
|
||||
✔ bus-service.sh pins the claude binary, refuses one the unit can't carry, and renders without one (118.231279ms)
|
||||
✔ bus-service.sh refuses a directory pin and keeps a symlink default unresolved (22.764374ms)
|
||||
✔ bus-service.sh refuses a default claude without the execute bit, or in a PATH dir with a space (15.08503ms)
|
||||
✔ bus start --pm: the PM runs under its own PID namespace, registered, with a manifest (1930.681169ms)
|
||||
✔ the PM launches a coder through its launch tool; the coder answers; refusals name their code (1909.149254ms)
|
||||
✔ a runner that stops at once ends its launch with the runner's reason (759.738499ms)
|
||||
✔ a host that died hard leaves its sessions to the next host, which kills them and ends their runs so the role can be launched again (2062.892198ms)
|
||||
✔ a host that died hard leaves its sessions to the next host, which finds one already exited (23) and ends their runs so the role can be launched again (3712.457502ms)
|
||||
✔ a malformed sessions.json refuses the host start with exit 3 and stays as it was (116.28754ms)
|
||||
✔ an over-long launch request is refused at once, not at the 10 s idle timeout (181.163532ms)
|
||||
✔ a launch client that never closes its side doesn't hold the host's close (134.576716ms)
|
||||
✔ a runner that ignores SIGTERM is killed when the host closes (1285.776795ms)
|
||||
✔ claudeVersion asks MOSAIC_CLAUDE_BIN when set, else claude on PATH (7.820157ms)
|
||||
✔ zoned uses the IANA zone across DST (33.209553ms)
|
||||
✔ each open blocking decision is DM'd once, across polls and a restart; non-blocking ones are not (42.447197ms)
|
||||
✔ two blocking decisions get two DMs with different nonces (60.326814ms)
|
||||
✔ the digest nonce differs per business and per day and fits Discord's 25 characters (9.534452ms)
|
||||
✔ a failed DM is journaled, backs off, and is retried until it lands (63.802172ms)
|
||||
✔ five definite refusals stop a DM: one gave-up line, one log line, and a restart keeps the count (98.052541ms)
|
||||
✔ 429s, 5xx-style unknowns and refusals without a status never count toward the limit (133.1075ms)
|
||||
✔ a crash between the fifth refusal and its gave-up line: the next poll appends it and sends nothing (92.052321ms)
|
||||
✔ polled every POLL_MS against a permanent 403, a DM is sent at 0, 30, 60, 90 and 120 min and gives up only then (596.987027ms)
|
||||
✔ a restart after the second refusal does not send before that refusal's 30 min are up (433.576921ms)
|
||||
✔ the digest goes at 08:00 Chicago once a day, with blocking ones marked as DM'd (291.163756ms)
|
||||
✔ a late start with no digest for the day sends one at once; an empty inbox gets one line (30.486406ms)
|
||||
✔ an inbox read failure is logged and the next poll retries (1.841938ms)
|
||||
✔ no Discord id reaches the journal or the log (53.674953ms)
|
||||
✔ the journal: a torn tail is copied out and truncated, so an append after it reopens cleanly (6.452765ms)
|
||||
✔ the journal: a crash between the copy and the truncate leaves a tail the next open repairs (6.722042ms)
|
||||
✔ the journal: a whole file that is one torn line truncates to empty (5.619623ms)
|
||||
✔ the journal: a malformed complete line refuses and leaves the file and any torn tail alone (10.374317ms)
|
||||
✔ the journal: a loose file mode, a loose directory or a symlinked journal refuses (16.656914ms)
|
||||
✔ the journal: a line with a wrong type refuses with exit 3 and names the field (15.027849ms)
|
||||
✔ the journal: a symlinked directory refuses and says it is a link (1.246096ms)
|
||||
✔ the journal: a dangling directory link, a parent that is a file and a journal that is a directory each refuse with exit 3 (1.177997ms)
|
||||
✔ the journal: an append after the file was swapped for a symlink refuses and writes nothing through it (1.105907ms)
|
||||
✔ the journal: a directory it cannot write or create refuses with exit 3 and names the path (1.789357ms)
|
||||
✔ digest content stays within Discord's 2000 characters (0.557187ms)
|
||||
✔ runLoop never overlaps ticks and stops after the one in flight (119.375417ms)
|
||||
task.close {} answered: invalid-request; fake saw 18 requests, first GET /info 200, GET /projects/1 200, GET /projects/1/views 200
|
||||
task.close on a missing task answered: task-not-found; it made GET /tasks/999 404
|
||||
✔ bootConfig trackers reach the S3 adapter in the real broker child, which goes ready against a fake Vikunja (1015.918166ms)
|
||||
✔ the transport writes {business, verb, args} to the child and reads its JSON (67.337237ms)
|
||||
✔ a bus code on stderr becomes the exit code; garbage and timeouts are outcome problems (2809.070219ms)
|
||||
✔ busExit and refuseInsideAgent (1.468537ms)
|
||||
✔ talk sends a REQUEST, prints and reads everything that arrives, and stops at the reply (185.23033ms)
|
||||
✔ talk --wait 0 only sends; no reply within --wait exits 1 and says where it will show (1075.885281ms)
|
||||
✔ talk, stop and launches off/on refuse inside an agent run; bad arguments are usage errors (140.908045ms)
|
||||
✔ launches off and on go to the broker and change the business's launch state (57.96829ms)
|
||||
✔ launches list reads sessions.json and marks a stale entry; stop reports it and refuses a non-runner (48.885947ms)
|
||||
ℹ tests 114
|
||||
ℹ suites 0
|
||||
ℹ pass 114
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 21831.74253
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-12T01:37:34Z
|
||||
@@ -0,0 +1,67 @@
|
||||
✔ sessionModel: agent vars win, then the system's execution settings (15.710134ms)
|
||||
✔ a pi bundle: prompt, policy, tools and manifest, 0600 in a 0700 directory (7.19641ms)
|
||||
✔ a claude-code bundle adds the wrapped gate hook and the MCP config (4.370385ms)
|
||||
✔ a bundle is written once: an existing file refuses (3.60041ms)
|
||||
✔ a path with a single quote can't go into the hook command (5.870182ms)
|
||||
✔ allow exits 0, a deny exits 2 with the reason on stderr (184.820086ms)
|
||||
✔ a missing or wrong policy, or a bad event, exits 2 (154.073013ms)
|
||||
✔ the bundle's wrapped command: a missing gate or node still blocks (1184.92167ms)
|
||||
✔ claude: typed tools through MCP, the hook blocks, builtins outside --tools don't exist (1314.353822ms)
|
||||
✔ claude: the hook alone blocks a path outside the workspace (801.328646ms)
|
||||
✔ claude: a second turn resumes the first turn's session (4378.050797ms)
|
||||
✔ claude adapter: --restricted is always passed (36.882982ms)
|
||||
✔ claude adapter: MOSAIC_CLAUDE_BIN wins over PATH and must be an absolute executable (60.393798ms)
|
||||
✔ claude adapter: a directory pin exits 2 before it runs; a pin with a space runs (25.352839ms)
|
||||
✔ claude: CLAUDE.md files and auto-memory don't reach the model; without --restricted they do (2421.168836ms)
|
||||
✔ claude: a missing hook or MCP file refuses before claude starts (14.062127ms)
|
||||
✔ pi: policy tools and typed tools pass, anything else is blocked (4.174644ms)
|
||||
✔ claude: builtins map from pi names, typed tools need the mcp prefix (1.111094ms)
|
||||
✔ file tool paths must resolve inside the workspace (1.770023ms)
|
||||
✔ pi's own path normalisation can't be used to step out (1.56933ms)
|
||||
✔ a symlink inside the workspace that points out is outside (1.171302ms)
|
||||
✔ a dangling symlink is refused at any depth, in both harnesses (5.858297ms)
|
||||
✔ read is checked under every spelling pi's read would open, in both harnesses (30.962487ms)
|
||||
✔ other spellings cover directories, dangling links and pi's cwd (3.07546ms)
|
||||
✔ a relative path climbs from the workspace's real path, in both harnesses (9.236145ms)
|
||||
✔ claude path fields per tool (1.242068ms)
|
||||
✔ glob patterns stay inside the workspace (1.096918ms)
|
||||
✔ a path that can't be checked is blocked (0.616827ms)
|
||||
✔ initialize, ping and tools/list (67.951354ms)
|
||||
✔ tools/call goes through the tool socket; a refusal is an isError result (59.919842ms)
|
||||
✔ unknown tools and methods are JSON-RPC errors and never reach the socket (43.456935ms)
|
||||
✔ a missing argument is a usage error (53.330459ms)
|
||||
✔ pi: typed tools reach the socket, the gate blocks, agent_end writes the marker (632.868257ms)
|
||||
✔ pi: a write through a dangling symlink is blocked, and nothing appears outside (614.380615ms)
|
||||
✔ pi: a read is refused when pi would open another spelling outside (651.479884ms)
|
||||
✔ pi: a relative path climbs from the real path of a workspace behind a symlink (723.032154ms)
|
||||
✔ pi: a relative path climbs from the real path of a dataRoot behind a symlink (2554.662054ms)
|
||||
✔ pi: a missing extension refuses before any model call (232.765756ms)
|
||||
✔ pi: an extension without its configuration fails pi's start (1618.744704ms)
|
||||
✔ founderCheck: founder variables, then a needed service without a usable token (1.976567ms)
|
||||
✔ turnRequest names the sender, class, reply and decision (0.299389ms)
|
||||
✔ a message becomes a turn, the answer goes back as a RESULT, SIGTERM releases and exits 0 (210.482414ms)
|
||||
✔ a SIGTERM before the claim stops the runner with exit 0 and no claim (86.085773ms)
|
||||
✔ typed tools carry the runner's capability; launch goes to the host's launch socket (446.628147ms)
|
||||
✔ a RESULT gets no automatic reply; failed turns reply with the reason (1327.24301ms)
|
||||
✔ SIGTERM during a turn kills the turn's process group and still exits 0 (181.784623ms)
|
||||
✔ founder credentials stop before the claim (20) (166.651097ms)
|
||||
✔ a refused claim exits 21; an ended run's capability exits 22 (289.938182ms)
|
||||
✔ the launch ending under a running session exits 22 (240.827767ms)
|
||||
✔ a broker that stays unreachable exits 23 after brokerRetries polls (271.861137ms)
|
||||
✔ a broker that is down at the claim exits 23, not 21 (347.033181ms)
|
||||
✔ no capability, or a malformed one, on stdin exits 2 (2809.24595ms)
|
||||
✔ a missing or malformed policy exits 2 before the claim (302.59668ms)
|
||||
✔ the PM gets launch, its task verbs and the reads (9.768128ms)
|
||||
✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (2.988792ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (3.179117ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (2.450704ms)
|
||||
✔ an action outside the instance's authority has no tool (5.732816ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (16.198564ms)
|
||||
ℹ tests 59
|
||||
ℹ suites 0
|
||||
ℹ pass 59
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 10553.327487
|
||||
@@ -0,0 +1,51 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.904844ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.74118ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.254465ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.719802ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (8.920394ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.880566ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.47994ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.237934ms)
|
||||
✔ readRunDocument reads only the three run documents (1.081653ms)
|
||||
✔ a link inside the data root is followed (2.021364ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.162407ms)
|
||||
✔ a run directory linked out of the data root is never read (1.262772ms)
|
||||
✔ a document linked out of the data root reads as null (2.30925ms)
|
||||
✔ a runs directory linked out of the data root refuses (1.007275ms)
|
||||
✔ a relative link that climbs out of the data root refuses (1.037732ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (1.144171ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.22113ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.815896ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.951148ms)
|
||||
✔ a link to the data root's parent is outside it (0.756864ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.401427ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.984287ms)
|
||||
✔ the readers write nothing (4.340578ms)
|
||||
✔ no pointer is null (3.217586ms)
|
||||
✔ the pointer release.sh writes reads back (2.084668ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.942247ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.153498ms)
|
||||
✔ a state file linked out of the data root refuses (3.242633ms)
|
||||
✔ a state directory linked out of the data root refuses (1.246227ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (1.83888ms)
|
||||
✔ a missing log is empty (0.786864ms)
|
||||
✔ the log reads oldest first and counts malformed lines (2.515689ms)
|
||||
✔ last must be a positive integer (0.926506ms)
|
||||
✔ the state readers write nothing (1.347749ms)
|
||||
✔ list prints each run in the established format (204.188393ms)
|
||||
✔ list prints a damaged result.json as unknown and keeps listing the runs after it (354.027541ms)
|
||||
✔ list prints each result field that isn't a string as unknown or - (341.299741ms)
|
||||
✔ show prints the run in the established format (386.091905ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (756.392044ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (711.535542ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (740.607612ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (195.407925ms)
|
||||
✔ show refuses an invalid id before reading the config (147.260487ms)
|
||||
ℹ tests 43
|
||||
ℹ suites 0
|
||||
ℹ pass 43
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 3978.203917
|
||||
@@ -0,0 +1,35 @@
|
||||
✔ resolveSeat: by name under --repo resolves the repo layout (1.510069ms)
|
||||
✔ resolveSeat: by path resolves the fleet layout (0.466049ms)
|
||||
✔ resolveSeat: refusals for missing dir, missing launch.sh, non-executable launch.sh, invalid name, and unknown layout (0.902569ms)
|
||||
✔ tmuxContext: outside tmux, default socket, custom socket, and exec failure (0.777167ms)
|
||||
✔ makeRegistration produces a record that validates; each shape violation throws SeatError (1.294057ms)
|
||||
✔ writeRegistration/readRegistration: round trip, permissions, absence, and malformed records (1.769352ms)
|
||||
✔ updateTask: changes task, taskSetBy and updatedAt only, and refuses appropriately (1.375444ms)
|
||||
✔ CLI launch: registers, execs the fake launch script, and passes args through (42.723486ms)
|
||||
✔ CLI launch: --harness lands in the record (42.348916ms)
|
||||
✔ CLI launch: the launch script's own exit code passes through (46.620996ms)
|
||||
✔ CLI launch: relaunching a seat rewrites the one registration record (80.069207ms)
|
||||
✔ CLI launch: omitting --task records an empty string, not null (39.442847ms)
|
||||
✔ CLI seat task: updates only the task after a launch, and refuses on an unlaunched seat (105.527602ms)
|
||||
✔ CLI refusals: no args, unknown flag, missing config, already-registered env, and exec failure (173.31401ms)
|
||||
✔ samePath: equal paths, symlinked dirs, distinct dirs, and non-strings (0.560245ms)
|
||||
✔ resolveSetBy: explicit --by wins over the environment; absent or empty environment gives unknown; invalid explicit or environment values refuse with exit 4 (0.62011ms)
|
||||
✔ validateRegistration/readRegistration: taskSetBy is optional; a record without it (written before #1511) still loads unchanged; an invalid one is refused; the version does not change (0.821444ms)
|
||||
✔ updateTask: records setBy, preserves startedAt and every unrelated field, upgrades an old record in place only when the task is set, and replaces a previous attribution (0.988514ms)
|
||||
✔ CLI seat task: --by beats MOSAIC_AGENT_NAME, the environment beats nothing, empty environment is unknown, invalid --by or environment refuses with exit 4 and leaves the record byte for byte (357.456317ms)
|
||||
✔ family: exactly one launch.max key in the model name, else null (0.772696ms)
|
||||
✔ sessionEnv passes only the allowlist, the repo's bin on PATH, and the run id (0.83855ms)
|
||||
✔ newRun: short ids, 0700 directories, and a refusal when the socket path won't fit (2.295538ms)
|
||||
✔ session file and launch log: 0600, the session file written once (1.380345ms)
|
||||
✔ endReason maps the runner's exit codes; a signal is killed (0.150624ms)
|
||||
✔ Registry mirrors to sessions.json; readSessions marks live entries; bad files refuse (1.458524ms)
|
||||
✔ stopSession refuses an unknown run, reports a stale one, and won't signal a pid that isn't a runner (1.299494ms)
|
||||
✔ a session runs under unshare as pid 1 of its namespace, claims, answers, and stops on mosaic stop (247.231007ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 959.081198
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-12T01:31:06Z
|
||||
@@ -0,0 +1,17 @@
|
||||
runs rc=0 ℹ pass 43 ℹ fail 0 ℹ skipped 0
|
||||
tasks rc=0 ℹ pass 71 ℹ fail 0 ℹ skipped 0
|
||||
bus rc=0 ℹ pass 94 ℹ fail 0 ℹ skipped 0
|
||||
business rc=0 ℹ pass 60 ℹ fail 0 ℹ skipped 0
|
||||
harness rc=0 ℹ pass 59 ℹ fail 0 ℹ skipped 0
|
||||
cli rc=0 ℹ pass 114 ℹ fail 0 ℹ skipped 0
|
||||
webui rc=0 ℹ pass 62 ℹ fail 0 ℹ skipped 0
|
||||
seat rc=0 ℹ pass 27 ℹ fail 0 ℹ skipped 0
|
||||
test-auth rc=0 selftest: 15 passed, 0 failed
|
||||
test-conductor rc=0 selftest: 17 passed, 0 failed
|
||||
test-config rc=0 selftest: 24 passed, 0 failed
|
||||
test-discord rc=0 discord suite: 66 passed, 0 failed
|
||||
test-extension-package rc=0 extension package selftest: 18 passed, 0 failed
|
||||
test-foundation rc=0 selftest: 44 passed, 0 failed
|
||||
test-queue rc=0 queue suite: 27 passed, 0 failed
|
||||
test-release rc=0 selftest: 14 passed, 0 failed
|
||||
test-task rc=0 selftest: 98 passed, 0 failed
|
||||
@@ -0,0 +1,79 @@
|
||||
✔ the boot config is checked before anything starts (30.093261ms)
|
||||
✔ a business with no tracker entry refuses task verbs (20.026864ms)
|
||||
✔ credential.expiring and .expired are recorded once per instance (64.321807ms)
|
||||
✔ a token file that changes on disk records credential.changed (23.010398ms)
|
||||
✔ autostart polls, reconciles and retries a startup the tracker was down for (57.479761ms)
|
||||
✔ a refusal a restart must clear is not retried by the poll (39.608455ms)
|
||||
✔ a poll that fires while two are queued is dropped (84.275035ms)
|
||||
✔ close waits for a running verb and refuses one that has not started (150.273733ms)
|
||||
✔ the bundled Vikunja is the pinned upstream image the runbook names (1.549835ms)
|
||||
✔ every published port is on 127.0.0.1, and no secret is in the file (0.60199ms)
|
||||
✔ the fake answers each route with the statuses and shapes Vikunja v2.7.0 sent (185.883589ms)
|
||||
✔ the project list holds recorded project objects in the recorded list envelope (40.499049ms)
|
||||
✔ the recorded task bodies pass the checks S3 applies to every read (1.130253ms)
|
||||
✔ the client works against the fake over real HTTP with the platform fetch (314.080111ms)
|
||||
✔ a correct install starts, and the first reconcile records tasks that already exist (53.738955ms)
|
||||
✔ verbs refuse while a business is starting and after startup refused it (25.529582ms)
|
||||
✔ startup refuses a token that can do more than its role needs (75.346618ms)
|
||||
✔ startup refuses an unsupported version and flags an untested one (143.730331ms)
|
||||
✔ startup refuses a board that the runbook did not install (164.257879ms)
|
||||
✔ startup refuses a project the sync bot cannot read (30.650206ms)
|
||||
✔ startup refuses a configured label the pm bot cannot see (24.651761ms)
|
||||
✔ startup refuses an expired credential and a missing sync credential (62.700219ms)
|
||||
✔ an unreachable tracker refuses with tracker-unavailable (42.711318ms)
|
||||
✔ an edit in the UI is recorded once, with the fields that changed (122.824599ms)
|
||||
✔ a move between open buckets is seen on the board, though updated does not change (76.370211ms)
|
||||
✔ a person's comment is counted and a bot's is not (270.779799ms)
|
||||
✔ the hourly reconcile catches a comment through comment_count (128.232025ms)
|
||||
✔ a task closed in the UI leaves the open view with its done bucket (241.062647ms)
|
||||
✔ a task that leaves the board is recorded as deleted, moved or out of reach (125.415782ms)
|
||||
✔ a poll that read before a verb wrote does not overwrite the verb (61.050849ms)
|
||||
✔ a tracker fault during a tick is reported and the next tick catches up (123.103962ms)
|
||||
✔ a malformed answer refuses the tick with tracker-shape (94.153162ms)
|
||||
✔ no token value reaches the database, the log or a refusal (158.778399ms)
|
||||
✔ the first look at a task counts only comments inside the window (68.416129ms)
|
||||
✔ with descendants off the adapter reads no project list and no child, as in v0 (67.621595ms)
|
||||
✔ a three-level tree is read per project, and a project outside it is not (47.087255ms)
|
||||
✔ a watch-only child keeps the business ready, and a failed child read refuses as transient (51.229268ms)
|
||||
✔ a root without the installed buckets refuses with descendants on (40.148918ms)
|
||||
✔ the project list refuses without read_all, and skips archived projects and saved filters (102.346579ms)
|
||||
✔ descendants must be true or false (52.25471ms)
|
||||
✔ a move inside the tree is a moved tombstone plus a snapshot under the new ref (142.133312ms)
|
||||
✔ a child made after startup joins the tree at the next reconcile (92.543892ms)
|
||||
✔ a child that leaves the tree has its tasks recorded missing, and the ledger keeps their history (123.444692ms)
|
||||
✔ a child deleted or hidden between reconciles drops out at the next tick, and the root still refuses (189.345489ms)
|
||||
✔ a reconcile that fails keeps the previous tree (74.501736ms)
|
||||
✔ a closed task the cursor missed takes its own project's done bucket (44.859005ms)
|
||||
✔ closed tasks read at startup take their own project's done bucket (69.948426ms)
|
||||
✔ a closed task the cursor returns takes its own project's done bucket (115.873085ms)
|
||||
✔ a task moved out of a child that leaves the tree at the same time is moved, not no-access (131.443037ms)
|
||||
✔ a task in a bucket outside the five keeps its raw bucket id (77.144523ms)
|
||||
✔ bucket 0 on a watch-only task never becomes a bucket or a state (131.669967ms)
|
||||
✔ a child whose kanban view is deleted still refuses the tick, and the reconcile reads it watch-only (104.914705ms)
|
||||
✔ a child dropped at a tick comes back at the next reconcile once the bot reads it again (85.786885ms)
|
||||
✔ task.create needs a recorded human request and a requirement id (73.960519ms)
|
||||
✔ only labels named in the business file can be written (53.360463ms)
|
||||
✔ task.schedule sets and clears a due date and relations (195.373585ms)
|
||||
✔ assign and reassign move the role bots and record task.assigned (197.949268ms)
|
||||
✔ task.update.assigned is for the assignee and records task.state (183.855991ms)
|
||||
✔ a wrong expected digest records task.conflict and writes nothing (94.818658ms)
|
||||
✔ a cross-role verb needs a resolved decision, used once (127.230154ms)
|
||||
✔ task.close needs a verdict; after it every verb refuses with task-done (62.388984ms)
|
||||
✔ a lost answer is settled by a re-read and never retried (130.390154ms)
|
||||
✔ a create whose answer is lost is reported uncertain, and the poll finds the task (114.348029ms)
|
||||
✔ a task the sync bot cannot read refuses and records nothing (107.682759ms)
|
||||
✔ verbs and polls for one business run one at a time (178.610325ms)
|
||||
✔ a due date with milliseconds is written to the second (160.616812ms)
|
||||
✔ every write landed and the final read failed: the verb succeeds and records what it wrote (87.230157ms)
|
||||
✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (44.066343ms)
|
||||
✔ a create whose final read fails succeeds and records task.created (50.779253ms)
|
||||
✔ an edit between the last write and the final read shows as external on the next poll (59.707584ms)
|
||||
✔ task.created is recorded when a later label write fails (38.460164ms)
|
||||
ℹ tests 71
|
||||
ℹ suites 0
|
||||
ℹ pass 71
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 2141.807007
|
||||
@@ -0,0 +1,17 @@
|
||||
OK status with missing harness credential exits 3 and still lists accounts
|
||||
OK status reports harness credential (read-only) + mosaic accounts
|
||||
OK api key material never reaches output
|
||||
OK oauth token material never reaches output
|
||||
OK unparseable credential file exits 2
|
||||
OK symlinked credential file exits 4
|
||||
OK env-side credential names reported
|
||||
OK env var values never reach output
|
||||
OK accounts without an accounts dir reports none and creates nothing
|
||||
OK accounts lists files and marks the active one
|
||||
OK loose account perms flagged in listing
|
||||
OK agent --auth with missing account file refuses (exit 4)
|
||||
OK agent --auth with non-0600 account file refuses
|
||||
OK agent --auth with invalid account name refuses
|
||||
OK auth.sh without valid config refuses
|
||||
|
||||
selftest: 15 passed, 0 failed
|
||||
@@ -0,0 +1,55 @@
|
||||
Note: switching to '876f1ffe0931e589c29d4e633d2f957f02c39fd4'.
|
||||
|
||||
You are in 'detached HEAD' state. You can look around, make experimental
|
||||
changes and commit them, and you can discard any commits you make in this
|
||||
state without impacting any branches by switching back to a branch.
|
||||
|
||||
If you want to create a new branch to retain commits you create, you may
|
||||
do so (now or later) by using -c with the switch command. Example:
|
||||
|
||||
git switch -c <new-branch-name>
|
||||
|
||||
Or undo this operation with:
|
||||
|
||||
git switch -
|
||||
|
||||
Turn off this advice by setting config variable advice.detachedHead to false
|
||||
|
||||
Not currently on any branch.
|
||||
nothing to commit, working tree clean
|
||||
Note: switching to '876f1ffe0931e589c29d4e633d2f957f02c39fd4'.
|
||||
|
||||
You are in 'detached HEAD' state. You can look around, make experimental
|
||||
changes and commit them, and you can discard any commits you make in this
|
||||
state without impacting any branches by switching back to a branch.
|
||||
|
||||
If you want to create a new branch to retain commits you create, you may
|
||||
do so (now or later) by using -c with the switch command. Example:
|
||||
|
||||
git switch -c <new-branch-name>
|
||||
|
||||
Or undo this operation with:
|
||||
|
||||
git switch -
|
||||
|
||||
Turn off this advice by setting config variable advice.detachedHead to false
|
||||
|
||||
OK dry-run: allowed change, exit 0, nothing committed (exit 0)
|
||||
OK dry-run committed nothing
|
||||
OK apply: allowed change exits 0 (exit 0)
|
||||
OK apply: attribution in commit subject
|
||||
OK apply: target tree clean after commit
|
||||
OK disallowed path refused (exit 1)
|
||||
OK disallowed path: target untouched
|
||||
OK syntax gate refused broken .mjs (exit 1)
|
||||
OK syntax gate: target untouched
|
||||
OK suite failure refused (exit 1)
|
||||
OK suite failure: target reverted to clean
|
||||
OK disabled policy refused (exit 2)
|
||||
OK disabled policy: target untouched
|
||||
OK failed run refused (exit 1)
|
||||
OK failed run: target untouched
|
||||
OK missing run exits 4 (exit 4)
|
||||
OK invalid policy exits 2 (exit 2)
|
||||
|
||||
selftest: 17 passed, 0 failed
|
||||
@@ -0,0 +1,26 @@
|
||||
OK absent adapter defaults to pi
|
||||
OK adapter mock validates (exit 0)
|
||||
OK unsupported adapter exits 2 (exit 2)
|
||||
OK env exports adapter
|
||||
OK bootstrap creates default when absent (exit 0)
|
||||
OK bootstrap wrote config file
|
||||
OK bootstrap is idempotent on existing config (exit 0)
|
||||
OK bootstrap did not rewrite existing config
|
||||
OK validate missing config exits 3 (exit 3)
|
||||
OK malformed JSON exits 2 (exit 2)
|
||||
OK unsupported configVersion exits 2 (exit 2)
|
||||
OK unknown top-level key exits 2 (exit 2)
|
||||
OK unknown execution key exits 2 (exit 2)
|
||||
OK unsupported backend exits 2 (exit 2)
|
||||
OK unsupported environment exits 2 (exit 2)
|
||||
OK relative dataRoot exits 2 (exit 2)
|
||||
OK non-canonical dataRoot exits 2 (exit 2)
|
||||
OK filesystem root dataRoot exits 2 (exit 2)
|
||||
OK home directory dataRoot exits 2 (exit 2)
|
||||
OK dataRoot containing config dir exits 2 (exit 2)
|
||||
OK control character in provider exits 2 (exit 2)
|
||||
OK symlinked config file exits 2 (exit 2)
|
||||
OK env exports resolve correctly
|
||||
OK failed validation modified nothing
|
||||
|
||||
selftest: 24 passed, 0 failed
|
||||
@@ -0,0 +1,70 @@
|
||||
toolchain: node v26.8.1
|
||||
|
||||
OK syntax: packages/discord/src/approvals.mjs
|
||||
OK syntax: packages/discord/src/authorize.mjs
|
||||
OK syntax: packages/discord/src/binding.mjs
|
||||
OK syntax: packages/discord/src/cli.mjs
|
||||
OK syntax: packages/discord/src/connector.mjs
|
||||
OK syntax: packages/discord/src/context.mjs
|
||||
OK syntax: packages/discord/src/engine-pi.mjs
|
||||
OK syntax: packages/discord/src/errors.mjs
|
||||
OK syntax: packages/discord/src/gateway.mjs
|
||||
OK syntax: packages/discord/src/git.mjs
|
||||
OK syntax: packages/discord/src/journal.mjs
|
||||
OK syntax: packages/discord/src/notify.mjs
|
||||
OK syntax: packages/discord/src/rest.mjs
|
||||
OK syntax: packages/discord/src/setspark.mjs
|
||||
OK syntax: packages/discord/src/tools.mjs
|
||||
OK syntax: packages/discord/src/web.mjs
|
||||
OK syntax: packages/discord/bin/git-credential.mjs
|
||||
OK syntax: packages/discord/extension/tools.mjs
|
||||
OK syntax: packages/discord/tests/approvals.test.mjs
|
||||
OK syntax: packages/discord/tests/authorize.test.mjs
|
||||
OK syntax: packages/discord/tests/binding.test.mjs
|
||||
OK syntax: packages/discord/tests/connector.test.mjs
|
||||
OK syntax: packages/discord/tests/context.test.mjs
|
||||
OK syntax: packages/discord/tests/engine.test.mjs
|
||||
OK syntax: packages/discord/tests/fake-pi.mjs
|
||||
OK syntax: packages/discord/tests/gateway.test.mjs
|
||||
OK syntax: packages/discord/tests/git.test.mjs
|
||||
OK syntax: packages/discord/tests/helpers.mjs
|
||||
OK syntax: packages/discord/tests/journal.test.mjs
|
||||
OK syntax: packages/discord/tests/notify.test.mjs
|
||||
OK syntax: packages/discord/tests/recover.test.mjs
|
||||
OK syntax: packages/discord/tests/rest.test.mjs
|
||||
OK syntax: packages/discord/tests/setspark.test.mjs
|
||||
OK syntax: packages/discord/tests/tools.test.mjs
|
||||
OK syntax: packages/discord/tests/web.test.mjs
|
||||
OK syntax: packages/discord/fixtures/claim-worker.mjs
|
||||
OK syntax: packages/discord/fixtures/legacy-owner-worker.mjs
|
||||
OK syntax: scripts/discord.sh
|
||||
OK syntax: scripts/discord-service.sh
|
||||
OK packages/discord declares no dependencies
|
||||
OK no bot-token-shaped string in packages/discord
|
||||
OK fixture binding uses placeholder ids only
|
||||
OK fixture binding validates
|
||||
OK real pi with the extension exposes exactly list_dir, read_file, search and no built-in tool
|
||||
OK real pi with a writable root exposes exactly the three reads plus write_file and edit_file, and writes nothing at start
|
||||
OK real pi with a web key exposes the three reads plus web_fetch and web_search, and no write tool without a writable root
|
||||
OK real pi with a git root exposes the reads, writes and the four git verbs, commits nothing at start, and never shows the token
|
||||
OK real pi with protocol vault adds reserve_id to the git verbs
|
||||
OK real pi with a setspark key exposes the reads and the eight record verbs, no counters, and never shows the key
|
||||
OK real pi refuses a git key on a read-only root (fail closed)
|
||||
OK real pi with the pilot flags (--no-tools) exposes no tool at all
|
||||
OK real pi exits non-zero without MOSAIC_DISCORD_TOOLS: no session, no tools (fail closed)
|
||||
OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT
|
||||
OK node --test packages/discord/tests/ (ℹ pass 178)
|
||||
OK scripts/discord.sh --help exits 0
|
||||
OK scripts/discord.sh check without a binding exits 4
|
||||
OK scripts/discord.sh recover without a binding exits 4
|
||||
OK scripts/discord.sh reload without a binding exits 4
|
||||
OK scripts/discord-service.sh without a command exits 4
|
||||
OK service unit renders with the repository path, a supervised run as the main process, exit 3 never retried, and reload as SIGHUP
|
||||
OK service install writes the rendered unit (0644) and leaves no temp file
|
||||
OK service install a second time reports unchanged
|
||||
OK systemd-analyze verify accepts the rendered unit
|
||||
OK service uninstall removes the unit file
|
||||
OK service install with an unknown flag exits 4
|
||||
OK service install with USER unset finishes and names the account for lingering
|
||||
|
||||
discord suite: 66 passed, 0 failed
|
||||
@@ -0,0 +1,21 @@
|
||||
OK initial ordinary-file install
|
||||
OK installed tree matches canonical source
|
||||
OK installed tree has no symlinks
|
||||
OK check detects installation drift
|
||||
OK sync refuses to overwrite installation drift
|
||||
OK check detects an extra destination file
|
||||
OK check detects an extra destination directory
|
||||
OK check rejects a destination symlink
|
||||
OK sync accepts a canonical source update
|
||||
OK updated installation matches canonical source
|
||||
scripts/test-extension-package.sh: line 14: 157903 Killed "$@" > /dev/null 2>&1
|
||||
OK forced interruption kills the replacing process
|
||||
OK next invocation recovers old consistent installation
|
||||
OK interrupted replacement rolled back
|
||||
OK sync succeeds after interruption recovery
|
||||
OK unlocked stale lock file does not block
|
||||
OK active lock refuses a concurrent sync
|
||||
OK source symlink fails closed
|
||||
OK nested second entrypoint fails closed
|
||||
|
||||
extension package selftest: 18 passed, 0 failed
|
||||
@@ -0,0 +1,53 @@
|
||||
toolchain: node v26.8.1, python 3.12.8, jsonschema 4.26.0
|
||||
|
||||
OK syntax: scripts/foundation-inspect.mjs
|
||||
OK syntax: scripts/foundation/strict-json.mjs
|
||||
OK syntax: scripts/foundation/canonical.mjs
|
||||
OK syntax: scripts/foundation/resolve.mjs
|
||||
OK syntax: scripts/foundation/validate-record.mjs
|
||||
OK syntax: scripts/foundation/fixtures/build-fixtures.mjs
|
||||
OK syntax: scripts/foundation/canonical.test.mjs
|
||||
OK syntax: scripts/foundation/cli.test.mjs
|
||||
OK syntax: scripts/foundation/fixtures.test.mjs
|
||||
OK syntax: scripts/foundation/resolve.test.mjs
|
||||
OK syntax: scripts/foundation/strict-json.test.mjs
|
||||
OK syntax: scripts/foundation/verify-schema.py (ast only; no bytecode written)
|
||||
OK fixture generator runs
|
||||
OK checked-in fixtures/bundles equal a fresh generation
|
||||
OK checked-in fixtures/raw equal a fresh generation
|
||||
OK checked-in fixtures/index.json equal a fresh generation
|
||||
OK checked-in demo bundles equal a fresh generation
|
||||
OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT
|
||||
OK node --test scripts/foundation/ (ℹ pass 80)
|
||||
OK differential schema oracle: PASS: differential schema oracle (finite corpus; compatibility evidence, not equivalence proof)
|
||||
platform witness: strftime('%Y') for year 999 -> '999' (pinned checker refuses years 0001..0999)
|
||||
node v26.8.1; corpus 1568 records (38 pinned fixtures, 478 unique bundle records, 1052 typeCase/mutation/lexical cases)
|
||||
schema column: agree-valid 540, agree-invalid 991, DISAGREEMENTS 0; strict-only (parser-bound) cases: 27; unsupported-kind records not schema-assessed by the inspector: 10
|
||||
profile column (schema-valid records only): profile-valid 510, profile-invalid 30
|
||||
profile refusals asserted: 30 schema-agreed-valid records refused only by the strict typed-string profile (rule profile-pattern-mismatch), 12 declared by name; 73 named probes verified against declared schema/profile columns
|
||||
OK oracle: zero schema-column disagreements with the pinned checker
|
||||
OK oracle: strict-only profile refusals are counted and asserted
|
||||
OK demo: permitted read preview exits 0 (exit 0)
|
||||
OK demo: permitted file.change preview exits 0 (exit 0)
|
||||
OK demo: assignment.change proposal is unresolved (exit 3) (exit 3)
|
||||
OK demo: revoked registration is refused (exit 3) (exit 3)
|
||||
OK demo: message is not authority (exit 3) (exit 3)
|
||||
OK usage: no arguments exits 2 (exit 2)
|
||||
OK io: missing file exits 4 (exit 4)
|
||||
OK io: directory exits 4 (exit 4)
|
||||
OK io: symlink exits 4 (O_NOFOLLOW) (exit 4)
|
||||
OK bound: oversize fixture exits 2 (exit 2)
|
||||
OK profile: one final LF in a typed selection id is refused before admission (exit 2) (exit 2)
|
||||
OK profile: two final LFs fail the schema pattern itself (exit 2) (exit 2)
|
||||
OK profile: escaped newlines in free-form text stay allowed (exit 0) (exit 0)
|
||||
OK profile refusal is invalid-request/profile-pattern-mismatch with selection and operation withheld, value not echoed
|
||||
OK text output starts with the disclaimer
|
||||
OK json output is valid JSON with result allowed and exactly the charter §7 fields
|
||||
OK json golden matches byte-for-byte
|
||||
OK sandboxed bundle run (env -i, PATH=/nonexistent) produced the unresolved proposal
|
||||
OK sandbox inventory (path/type/size/mode/uid/gid/inode/mtime/sha256) unchanged by runs
|
||||
OK canary never printed (bundle run and credential-file run)
|
||||
OK a non-bundle JSON file is refused at the shape gate, not read into output
|
||||
OK no field of the non-bundle file is echoed
|
||||
|
||||
selftest: 44 passed, 0 failed
|
||||
@@ -0,0 +1,35 @@
|
||||
toolchain: node v26.8.1, git version 2.55.0
|
||||
|
||||
OK syntax: packages/queue/src/cli.mjs
|
||||
OK syntax: packages/queue/src/errors.mjs
|
||||
OK syntax: packages/queue/src/io.mjs
|
||||
OK syntax: packages/queue/src/lock.mjs
|
||||
OK syntax: packages/queue/src/queue.mjs
|
||||
OK syntax: packages/queue/src/review.mjs
|
||||
OK syntax: packages/queue/src/store.mjs
|
||||
OK syntax: packages/queue/tests/commit.test.mjs
|
||||
OK syntax: packages/queue/tests/data.test.mjs
|
||||
OK syntax: packages/queue/tests/dispatch.test.mjs
|
||||
OK syntax: packages/queue/tests/helpers.mjs
|
||||
OK syntax: packages/queue/tests/lock.test.mjs
|
||||
OK syntax: packages/queue/tests/migration.test.mjs
|
||||
OK syntax: packages/queue/tests/review.test.mjs
|
||||
OK syntax: packages/queue/tests/store.test.mjs
|
||||
OK syntax: packages/queue/tests/write.test.mjs
|
||||
OK syntax: packages/queue/tests/fixtures/fake-gitea.mjs
|
||||
OK syntax: packages/queue/tests/fixtures/kill-at.mjs
|
||||
OK syntax: packages/queue/tests/fixtures/lock-child.mjs
|
||||
OK syntax: packages/queue/tests/fixtures/mosaic-pre-a2.sh
|
||||
OK syntax: scripts/queue-commit.sh
|
||||
OK syntax: scripts/git-hooks/pre-commit
|
||||
OK syntax: scripts/mosaic
|
||||
OK queue-commit.sh, the guard and scripts/mosaic are executable
|
||||
OK packages/queue declares no dependencies
|
||||
ℹ tests 150
|
||||
ℹ pass 150
|
||||
ℹ fail 0
|
||||
OK node --test packages/queue/tests/
|
||||
OK scripts/mosaic queue help
|
||||
skip queue verify and render --check: this checkout (/mnt/storage/scratch/rocko-r82) is not the queue's canonical root (/mnt/storage/src/mosaic-stack)
|
||||
|
||||
queue suite: 27 passed, 0 failed
|
||||
@@ -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
|
||||
@@ -0,0 +1,101 @@
|
||||
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)
|
||||
OK mock adapter: gate passes on matching mock response (exit 0)
|
||||
OK mock adapter: expect-mismatch recorded (exit 1)
|
||||
OK mismatch reason recorded
|
||||
OK unknown adapter fails closed (exit 1)
|
||||
OK mission task runs via mock adapter (exit 0)
|
||||
OK mission section injected into generated prompt
|
||||
OK retry of mission run succeeds (exit 0)
|
||||
OK retriedFrom lineage recorded
|
||||
OK mission section present after retry (relative path resolved)
|
||||
OK retry of missing run exits 4 (exit 4)
|
||||
OK skill install bundled ms-tools (exit 0)
|
||||
OK installed to skills-available
|
||||
OK double install refuses (exit 1)
|
||||
OK activate enables skill (exit 0)
|
||||
OK enabled dir populated
|
||||
OK uninstall while enabled refuses (exit 1)
|
||||
OK deactivate moves back to available (exit 0)
|
||||
OK uninstall removes from available (exit 0)
|
||||
OK seat with enabled skill launches
|
||||
OK skill path delivered to adapter
|
||||
OK shipped researcher contract resolves (ceiling + network)
|
||||
OK resolve-role refuses a non-role document (conductor policy) (exit 2)
|
||||
OK resolve-role refuses name/filename mismatch (exit 2)
|
||||
OK resolve-role refuses unknown network declaration (exit 2)
|
||||
OK resolve-role refuses duplicate role tool (exit 2)
|
||||
OK resolve-role refuses unsupported tool (exit 2)
|
||||
OK resolve-role refuses missing contract file (exit 4)
|
||||
OK version 1 role prints no contract line
|
||||
OK shipped version 2 roles resolve with their contracts (pm, cto, coder, reviewer)
|
||||
OK resolve-role accepts a minimal version 2 role (exit 0)
|
||||
OK resolve-role refuses an action outside the vocabulary (exit 2)
|
||||
OK resolve-role refuses a gated-only action in a role file (exit 2)
|
||||
OK resolve-role refuses a Vikunja verb no role may hold (exit 2)
|
||||
OK resolve-role refuses a version 2 role whose contract is missing (exit 2)
|
||||
OK resolve-role refuses a contract that is a symbolic link (exit 2)
|
||||
OK seat launches under role ceiling
|
||||
OK role ceiling narrows seat tools (read,write,bash -> read,bash)
|
||||
OK narrowing recorded loudly
|
||||
OK missing role contract refuses launch (exit 2)
|
||||
OK missing-contract refusal names the role
|
||||
OK empty ceiling intersection -> tool-free seat
|
||||
OK tool-free outcome recorded loudly
|
||||
OK overridden agents dir without seat definition refuses (exit 4)
|
||||
OK seat-resolution refusal names the seat
|
||||
OK policy: mission only -> mission tools
|
||||
OK policy: task only -> task tools
|
||||
OK policy: both -> intersection (task narrowed)
|
||||
OK policy: empty intersection -> tool-free
|
||||
OK invalid mission capabilities rejected (exit 2)
|
||||
mosaic-task: unsupported mission tool: "sudo" (supported: read, write, edit, bash, grep, find, ls)
|
||||
OK task run with user layer present (exit 0)
|
||||
OK user context dispatched into generated prompt
|
||||
OK workspace+tools task runs via mock (exit 0)
|
||||
OK workspace path + tools delivered to adapter
|
||||
OK persistent workspace created on host
|
||||
OK plain task still runs (no workspace/tools) (exit 0)
|
||||
OK workspace var present but empty when absent
|
||||
OK tools empty when absent
|
||||
OK unknown tool exits 2 (exit 2)
|
||||
OK workspace traversal exits 2 (exit 2)
|
||||
OK live hello task succeeds with exact marker
|
||||
OK result.json written in run dir
|
||||
OK result.json contents are correct
|
||||
OK wrong expectExact fails with exit 1 (reason: expect-mismatch)
|
||||
OK each run gets a distinct run dir (no clobber)
|
||||
OK list shows both runs
|
||||
OK fork base: teach succeeds (exit 0)
|
||||
OK fork child recalls ancestor context (exit 0)
|
||||
OK forked child recalled ancestor code word
|
||||
OK ancestor session untouched by fork
|
||||
OK child session dir has its own branch file
|
||||
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
|
||||
OK user recall run succeeds
|
||||
OK recalled user name (response: Jason)
|
||||
OK no agent identity on headless run
|
||||
|
||||
selftest: 98 passed, 0 failed
|
||||
@@ -0,0 +1,71 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (3807.864366ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5076.372035ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (9364.965724ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (215.317427ms)
|
||||
✔ decisions route serves the roles and recent lists from the reader view (663.829157ms)
|
||||
✔ credentials route serves the broker credential status from the reader view (20.201839ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (282.515986ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (156.326516ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (3312.969437ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (950.168768ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (552.704395ms)
|
||||
✔ serve refuses a --business value that is not a business id (866.35445ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (3824.046977ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4155.287796ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1484.452874ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (981.914795ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6841.1917ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56767.765934ms)
|
||||
✔ preview options are all three or none, and each is checked (18.597668ms)
|
||||
✔ the CLI refuses a partial or invalid preview flag set at start (4035.691177ms)
|
||||
✔ the CLI with all three flags serves the preview mode (894.089032ms)
|
||||
✔ a request for the public name needs the header equal to the user id, else 401 and nothing read (110.306513ms)
|
||||
✔ the header name matches without regard to case, and the value compare is exact (13.934912ms)
|
||||
✔ the public name with the header reads the bus views, and the Host and Origin are checked first (106.412901ms)
|
||||
✔ in preview mode every write answers 403 read-only, from the public name and loopback, and reaches nothing (60.959386ms)
|
||||
✔ loopback requests are unchanged in preview mode, and the bus views work with the board down (33.814677ms)
|
||||
✔ a proxy that rewrites Host to the loopback port gets 403 on its first request, whatever the user (72.638004ms)
|
||||
✔ a repeated Host is 400 before any other check, in preview mode and without it (29.87666ms)
|
||||
✔ without the preview flags the public name is refused and writes still reach the board (25.931148ms)
|
||||
✔ redactor: config, dataRoot, any absolute path, Discord ids and the JSON parser quote (2.879041ms)
|
||||
✔ credential state from the date alone, as the bus states it (0.300452ms)
|
||||
✔ queue: rows, one row, ids and methods, notes; no path or id from a row (3150.922901ms)
|
||||
✔ queue: a refused read fails closed with the store's text, redacted (1434.401179ms)
|
||||
✔ queue: a store that fails to load, or a child that dies, gives a fixed message with no path or stack (2694.242536ms)
|
||||
✔ business: names, vars on the allowlist, authority, credential metadata only (25.204816ms)
|
||||
✔ business: missing or invalid file refuses with the module's text, redacted (15.725235ms)
|
||||
✔ business without --business: the live bus host, else no-bus-host; no system config: not-configured (21.835333ms)
|
||||
✔ settings: release, board, loopback address, notifier binding name only (279.739926ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (6960.867284ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (25819.917352ms)
|
||||
✔ loopback host and board origin fail closed (45.784932ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (818.511562ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (398.473974ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (2521.718934ms)
|
||||
✔ render prints the unit without the preview flags (35.813217ms)
|
||||
✔ render carries every serve flag, the preview set included (25.712264ms)
|
||||
✔ a partial preview set is refused (92.887471ms)
|
||||
✔ a value the unit cannot carry is refused, for every flag (4459.173536ms)
|
||||
✔ the rendered unit names none of the human proof agent markers and sets no agent variable (85.408528ms)
|
||||
✔ install into --dir with --no-reload writes the file whole, then reports unchanged (618.68412ms)
|
||||
✔ install without --no-reload runs daemon-reload and nothing that starts the unit (312.330271ms)
|
||||
✔ uninstall refuses while the unit is active, and removes it once it is not (517.954128ms)
|
||||
✔ status prints the unit state and GET /healthz on the installed port (611.509122ms)
|
||||
✔ usage: an unknown verb or flag, and start or enable, exit 4 (240.653597ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.511009ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.941806ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (2.267964ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (9315.570761ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (2777.460193ms)
|
||||
✔ Queue, Business and Settings in their five states, with no move button (6555.882866ms)
|
||||
✔ seeded secrets, Discord ids and paths reach no response and no page; business refusals in the module's words (2238.727996ms)
|
||||
✔ the server log names no config path when the system config refuses (579.788324ms)
|
||||
ℹ tests 62
|
||||
ℹ suites 0
|
||||
ℹ pass 62
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57835.287962
|
||||
@@ -0,0 +1,5 @@
|
||||
baseline: pass
|
||||
status-unchecked: SURVIVED
|
||||
taskid-unchecked: SURVIVED
|
||||
workspace-unchecked: SURVIVED
|
||||
session-unchecked: SURVIVED
|
||||
@@ -0,0 +1,49 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.770998ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.989138ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.715163ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.840387ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.317939ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.76526ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.065639ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.984326ms)
|
||||
✔ readRunDocument reads only the three run documents (0.834364ms)
|
||||
✔ a link inside the data root is followed (1.595987ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.010003ms)
|
||||
✔ a run directory linked out of the data root is never read (1.037756ms)
|
||||
✔ a document linked out of the data root reads as null (1.641586ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.903957ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.782914ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.808601ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.029557ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.686696ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (1.001154ms)
|
||||
✔ a link to the data root's parent is outside it (0.71137ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.218126ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.870566ms)
|
||||
✔ the readers write nothing (3.448265ms)
|
||||
✔ no pointer is null (3.344725ms)
|
||||
✔ the pointer release.sh writes reads back (2.153513ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.223291ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.011091ms)
|
||||
✔ a state file linked out of the data root refuses (1.299045ms)
|
||||
✔ a state directory linked out of the data root refuses (0.646832ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.530058ms)
|
||||
✔ a missing log is empty (0.464916ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.567595ms)
|
||||
✔ last must be a positive integer (0.777274ms)
|
||||
✔ the state readers write nothing (1.438478ms)
|
||||
✔ list prints each run in the established format (119.752516ms)
|
||||
✔ show prints the run in the established format (102.354027ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (150.446742ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (160.872649ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (173.701152ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (93.332958ms)
|
||||
✔ show refuses an invalid id before reading the config (52.02463ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 926.712895
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r82-out/mutants-base/orig 2026-10-11 20:30:15.852477467 -0500
|
||||
+++ scripts/mosaic-task.mjs 2026-10-11 20:30:19.921452775 -0500
|
||||
@@ -480,7 +480,7 @@
|
||||
if (typeof result.status === "string") status = result.status;
|
||||
if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
- if (typeof result.session === "string") session = result.session;
|
||||
+ session = result.session ?? "-";
|
||||
}
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (0.966743ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.583769ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.671755ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.767585ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.014739ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.045739ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.891383ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.672891ms)
|
||||
✔ readRunDocument reads only the three run documents (0.627308ms)
|
||||
✔ a link inside the data root is followed (0.985388ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.630768ms)
|
||||
✔ a run directory linked out of the data root is never read (0.664926ms)
|
||||
✔ a document linked out of the data root reads as null (0.913555ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.528674ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.693208ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.552912ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.590648ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.422715ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.528006ms)
|
||||
✔ a link to the data root's parent is outside it (0.41202ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.801857ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.528402ms)
|
||||
✔ the readers write nothing (1.954826ms)
|
||||
✔ no pointer is null (1.909539ms)
|
||||
✔ the pointer release.sh writes reads back (1.154233ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (1.589317ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.559351ms)
|
||||
✔ a state file linked out of the data root refuses (1.660618ms)
|
||||
✔ a state directory linked out of the data root refuses (0.624989ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.467383ms)
|
||||
✔ a missing log is empty (0.384301ms)
|
||||
✔ the log reads oldest first and counts malformed lines (0.96115ms)
|
||||
✔ last must be a positive integer (0.488488ms)
|
||||
✔ the state readers write nothing (0.842149ms)
|
||||
✔ list prints each run in the established format (84.344239ms)
|
||||
✔ show prints the run in the established format (71.404103ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (106.875642ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (140.804141ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (154.028031ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (68.332071ms)
|
||||
✔ show refuses an invalid id before reading the config (38.208227ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 719.990904
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r82-out/mutants-base/orig 2026-10-11 20:30:15.852477467 -0500
|
||||
+++ scripts/mosaic-task.mjs 2026-10-11 20:30:17.166337117 -0500
|
||||
@@ -477,7 +477,7 @@
|
||||
let workspace = "-";
|
||||
let session = "-";
|
||||
if (result) {
|
||||
- if (typeof result.status === "string") status = result.status;
|
||||
+ status = result.status;
|
||||
if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
if (typeof result.session === "string") session = result.session;
|
||||
@@ -0,0 +1,49 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.150786ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.838063ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.696667ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.899935ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.141998ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.735077ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.152421ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.0922ms)
|
||||
✔ readRunDocument reads only the three run documents (0.808213ms)
|
||||
✔ a link inside the data root is followed (1.604334ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.985815ms)
|
||||
✔ a run directory linked out of the data root is never read (0.983211ms)
|
||||
✔ a document linked out of the data root reads as null (1.628056ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.927164ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.763674ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.874952ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.992915ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.646578ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.804567ms)
|
||||
✔ a link to the data root's parent is outside it (0.668181ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.249854ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.833832ms)
|
||||
✔ the readers write nothing (3.640645ms)
|
||||
✔ no pointer is null (1.898997ms)
|
||||
✔ the pointer release.sh writes reads back (1.260958ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (1.846762ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.975029ms)
|
||||
✔ a state file linked out of the data root refuses (1.949294ms)
|
||||
✔ a state directory linked out of the data root refuses (0.731428ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.515969ms)
|
||||
✔ a missing log is empty (0.481046ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.121053ms)
|
||||
✔ last must be a positive integer (0.507ms)
|
||||
✔ the state readers write nothing (0.932028ms)
|
||||
✔ list prints each run in the established format (91.560715ms)
|
||||
✔ show prints the run in the established format (79.624456ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (118.804181ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (161.035762ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (230.715511ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (135.824776ms)
|
||||
✔ show refuses an invalid id before reading the config (83.570244ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 971.672229
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r82-out/mutants-base/orig 2026-10-11 20:30:15.852477467 -0500
|
||||
+++ scripts/mosaic-task.mjs 2026-10-11 20:30:18.181711138 -0500
|
||||
@@ -478,7 +478,7 @@
|
||||
let session = "-";
|
||||
if (result) {
|
||||
if (typeof result.status === "string") status = result.status;
|
||||
- if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
+ taskId = result.taskId;
|
||||
if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
if (typeof result.session === "string") session = result.session;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.661527ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.489845ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.007024ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.227195ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.072184ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.893272ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.701173ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.050582ms)
|
||||
✔ readRunDocument reads only the three run documents (0.973167ms)
|
||||
✔ a link inside the data root is followed (1.078984ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.771344ms)
|
||||
✔ a run directory linked out of the data root is never read (0.807758ms)
|
||||
✔ a document linked out of the data root reads as null (1.271962ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.628472ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.541068ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.635437ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.794793ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.4774ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.590549ms)
|
||||
✔ a link to the data root's parent is outside it (0.468851ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.298843ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.588761ms)
|
||||
✔ the readers write nothing (2.756404ms)
|
||||
✔ no pointer is null (2.391745ms)
|
||||
✔ the pointer release.sh writes reads back (1.972215ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (3.084606ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.898546ms)
|
||||
✔ a state file linked out of the data root refuses (1.693041ms)
|
||||
✔ a state directory linked out of the data root refuses (0.64316ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.624481ms)
|
||||
✔ a missing log is empty (0.498985ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.233284ms)
|
||||
✔ last must be a positive integer (0.555806ms)
|
||||
✔ the state readers write nothing (0.903086ms)
|
||||
✔ list prints each run in the established format (116.699465ms)
|
||||
✔ show prints the run in the established format (86.595596ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (122.19983ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (163.737707ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (157.209126ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (76.12043ms)
|
||||
✔ show refuses an invalid id before reading the config (57.803996ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 865.104009
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r82-out/mutants-base/orig 2026-10-11 20:30:15.852477467 -0500
|
||||
+++ scripts/mosaic-task.mjs 2026-10-11 20:30:19.101013234 -0500
|
||||
@@ -479,7 +479,7 @@
|
||||
if (result) {
|
||||
if (typeof result.status === "string") status = result.status;
|
||||
if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
- if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
+ workspace = String(result.workspace ?? "-");
|
||||
if (typeof result.session === "string") session = result.session;
|
||||
}
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
@@ -0,0 +1,49 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.7571ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.315122ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.727252ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.919716ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.641224ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.996315ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.307456ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.262826ms)
|
||||
✔ readRunDocument reads only the three run documents (0.955215ms)
|
||||
✔ a link inside the data root is followed (1.935902ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.065828ms)
|
||||
✔ a run directory linked out of the data root is never read (4.051873ms)
|
||||
✔ a document linked out of the data root reads as null (1.136426ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.649502ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.532537ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.590157ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.690082ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.49845ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.553406ms)
|
||||
✔ a link to the data root's parent is outside it (0.400891ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.799036ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.55673ms)
|
||||
✔ the readers write nothing (2.071779ms)
|
||||
✔ no pointer is null (2.17198ms)
|
||||
✔ the pointer release.sh writes reads back (1.388282ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.046825ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.706579ms)
|
||||
✔ a state file linked out of the data root refuses (2.392355ms)
|
||||
✔ a state directory linked out of the data root refuses (1.072156ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (1.213898ms)
|
||||
✔ a missing log is empty (1.006429ms)
|
||||
✔ the log reads oldest first and counts malformed lines (4.995493ms)
|
||||
✔ last must be a positive integer (0.742142ms)
|
||||
✔ the state readers write nothing (0.996819ms)
|
||||
✔ list prints each run in the established format (92.07439ms)
|
||||
✔ show prints the run in the established format (79.941684ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (126.587614ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (169.359654ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (130.702684ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (65.283332ms)
|
||||
✔ show refuses an invalid id before reading the config (42.632922ms)
|
||||
ℹ tests 41
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 779.721194
|
||||
@@ -0,0 +1,5 @@
|
||||
baseline: pass
|
||||
status-unchecked: killed (✖ list prints a damaged result.json as unknown and keeps listing the runs after it;✖ list prints each result field that isn't a string as unknown or -;)
|
||||
taskid-unchecked: killed (✖ list prints a damaged result.json as unknown and keeps listing the runs after it;✖ list prints each result field that isn't a string as unknown or -;)
|
||||
workspace-unchecked: killed (✖ list prints each result field that isn't a string as unknown or -;)
|
||||
session-unchecked: killed (✖ list prints each result field that isn't a string as unknown or -;)
|
||||
@@ -0,0 +1,51 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.089094ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.703202ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.634478ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.961785ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.413809ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.118458ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.718063ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.73504ms)
|
||||
✔ readRunDocument reads only the three run documents (0.809058ms)
|
||||
✔ a link inside the data root is followed (1.46001ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.636328ms)
|
||||
✔ a run directory linked out of the data root is never read (0.682721ms)
|
||||
✔ a document linked out of the data root reads as null (1.219035ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.735944ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.484886ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.623447ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.693458ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.47365ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.706729ms)
|
||||
✔ a link to the data root's parent is outside it (0.459453ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.895128ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.561501ms)
|
||||
✔ the readers write nothing (2.415002ms)
|
||||
✔ no pointer is null (2.120389ms)
|
||||
✔ the pointer release.sh writes reads back (1.53396ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.35208ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.695862ms)
|
||||
✔ a state file linked out of the data root refuses (1.891929ms)
|
||||
✔ a state directory linked out of the data root refuses (0.625037ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (1.058711ms)
|
||||
✔ a missing log is empty (0.432539ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.11693ms)
|
||||
✔ last must be a positive integer (0.571264ms)
|
||||
✔ the state readers write nothing (0.896547ms)
|
||||
✔ list prints each run in the established format (87.188913ms)
|
||||
✔ list prints a damaged result.json as unknown and keeps listing the runs after it (89.285259ms)
|
||||
✔ list prints each result field that isn't a string as unknown or - (65.962497ms)
|
||||
✔ show prints the run in the established format (73.989417ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (112.795422ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (141.391925ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (130.239136ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (69.330303ms)
|
||||
✔ show refuses an invalid id before reading the config (43.449869ms)
|
||||
ℹ tests 43
|
||||
ℹ suites 0
|
||||
ℹ pass 43
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 888.478192
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r82-out/mutants-candidate/orig 2026-10-11 20:29:10.825411670 -0500
|
||||
+++ scripts/mosaic-task.mjs 2026-10-11 20:30:14.425960959 -0500
|
||||
@@ -480,7 +480,7 @@
|
||||
if (typeof result.status === "string") status = result.status;
|
||||
if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
- if (typeof result.session === "string") session = result.session;
|
||||
+ session = result.session ?? "-";
|
||||
}
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.81962ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.134922ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.482977ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.523512ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (2.405926ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (1.274728ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.784894ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.80405ms)
|
||||
✔ readRunDocument reads only the three run documents (0.690033ms)
|
||||
✔ a link inside the data root is followed (1.69734ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.717603ms)
|
||||
✔ a run directory linked out of the data root is never read (0.781243ms)
|
||||
✔ a document linked out of the data root reads as null (1.167486ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.646654ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.546468ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.657202ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.666052ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.462925ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (1.309791ms)
|
||||
✔ a link to the data root's parent is outside it (0.472631ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.851919ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.580399ms)
|
||||
✔ the readers write nothing (2.188829ms)
|
||||
✔ no pointer is null (2.01241ms)
|
||||
✔ the pointer release.sh writes reads back (1.63017ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (2.047479ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.711759ms)
|
||||
✔ a state file linked out of the data root refuses (1.921301ms)
|
||||
✔ a state directory linked out of the data root refuses (0.698342ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.557745ms)
|
||||
✔ a missing log is empty (0.403928ms)
|
||||
✔ the log reads oldest first and counts malformed lines (1.103969ms)
|
||||
✔ last must be a positive integer (0.500743ms)
|
||||
✔ the state readers write nothing (0.863101ms)
|
||||
✔ list prints each run in the established format (86.425618ms)
|
||||
✔ list prints a damaged result.json as unknown and keeps listing the runs after it (80.50387ms)
|
||||
✖ list prints each result field that isn't a string as unknown or - (80.786636ms)
|
||||
✔ show prints the run in the established format (78.733318ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (140.176796ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (153.927205ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (161.468469ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (81.637218ms)
|
||||
✔ show refuses an invalid id before reading the config (46.583449ms)
|
||||
ℹ tests 43
|
||||
ℹ suites 0
|
||||
ℹ pass 42
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 994.889694
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:49:1
|
||||
✖ list prints each result field that isn't a string as unknown or - (80.786636ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
'r-20260101T000000Z-status unknown task=t-one ws=- session=-\n' +
|
||||
'r-20260101T000001Z-taskid succeeded task=- ws=- session=-\n' +
|
||||
'r-20260101T000002Z-worksp succeeded task=t-one ws=- session=-\n' +
|
||||
+ 'r-20260101T000003Z-sessin succeeded task=t-one ws=- session=[object Object]\n'
|
||||
- 'r-20260101T000003Z-sessin succeeded task=t-one ws=- session=-\n'
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r82/packages/runs/tests/task-cli.test.mjs:60: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: 'r-20260101T000000Z-status unknown task=t-one ws=- session=-\nr-20260101T000001Z-taskid succeeded task=- ws=- session=-\nr-20260101T000002Z-worksp succeeded task=t-one ws=- session=-\nr-20260101T000003Z-sessin succeeded task=t-one ws=- session=[object Object]\n',
|
||||
expected: 'r-20260101T000000Z-status unknown task=t-one ws=- session=-\nr-20260101T000001Z-taskid succeeded task=- ws=- session=-\nr-20260101T000002Z-worksp succeeded task=t-one ws=- session=-\nr-20260101T000003Z-sessin succeeded task=t-one ws=- session=-\n',
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r82-out/mutants-candidate/orig 2026-10-11 20:29:10.825411670 -0500
|
||||
+++ scripts/mosaic-task.mjs 2026-10-11 20:30:07.365459491 -0500
|
||||
@@ -477,7 +477,7 @@
|
||||
let workspace = "-";
|
||||
let session = "-";
|
||||
if (result) {
|
||||
- if (typeof result.status === "string") status = result.status;
|
||||
+ status = result.status;
|
||||
if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
if (typeof result.session === "string") session = result.session;
|
||||
@@ -0,0 +1,119 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (0.947274ms)
|
||||
✔ a missing data root or runs directory lists nothing (1.437378ms)
|
||||
✔ runs as a regular file lists nothing, as before (0.542334ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (0.724697ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (1.812111ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (0.930194ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (0.600919ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (0.592908ms)
|
||||
✔ readRunDocument reads only the three run documents (0.472013ms)
|
||||
✔ a link inside the data root is followed (0.837843ms)
|
||||
✔ a data root that is itself a link is trusted as configured (0.507475ms)
|
||||
✔ a run directory linked out of the data root is never read (0.551678ms)
|
||||
✔ a document linked out of the data root reads as null (0.849592ms)
|
||||
✔ a runs directory linked out of the data root refuses (0.471204ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.378007ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (0.434354ms)
|
||||
✔ a link loop refuses instead of reading as missing (0.537788ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.358058ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (0.433887ms)
|
||||
✔ a link to the data root's parent is outside it (0.350634ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (0.709726ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.451571ms)
|
||||
✔ the readers write nothing (1.821022ms)
|
||||
✔ no pointer is null (1.572606ms)
|
||||
✔ the pointer release.sh writes reads back (1.0426ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (1.429762ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (0.479496ms)
|
||||
✔ a state file linked out of the data root refuses (0.816096ms)
|
||||
✔ a state directory linked out of the data root refuses (0.478162ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.415921ms)
|
||||
✔ a missing log is empty (0.317867ms)
|
||||
✔ the log reads oldest first and counts malformed lines (0.83492ms)
|
||||
✔ last must be a positive integer (0.406467ms)
|
||||
✔ the state readers write nothing (0.6883ms)
|
||||
✔ list prints each run in the established format (76.308824ms)
|
||||
✖ list prints a damaged result.json as unknown and keeps listing the runs after it (83.762614ms)
|
||||
✖ list prints each result field that isn't a string as unknown or - (94.046733ms)
|
||||
✔ show prints the run in the established format (81.219485ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (141.827726ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (159.983366ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (358.260259ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (260.108949ms)
|
||||
✔ show refuses an invalid id before reading the config (173.914693ms)
|
||||
ℹ tests 43
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1577.810149
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:35:1
|
||||
✖ list prints a damaged result.json as unknown and keeps listing the runs after it (83.762614ms)
|
||||
AssertionError [ERR_ASSERTION]: file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:485
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
^
|
||||
|
||||
TypeError: Cannot read properties of undefined (reading 'padEnd')
|
||||
at listRuns (file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:485:46)
|
||||
at file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:645:5
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:569:25)
|
||||
at async node:internal/modules/esm/loader:650:26
|
||||
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
|
||||
|
||||
Node.js v26.8.1
|
||||
|
||||
|
||||
1 !== 0
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r82/packages/runs/tests/task-cli.test.mjs:42: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 startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 1,
|
||||
expected: 0,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:49:1
|
||||
✖ list prints each result field that isn't a string as unknown or - (94.046733ms)
|
||||
AssertionError [ERR_ASSERTION]: file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:485
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
^
|
||||
|
||||
TypeError: status.padEnd is not a function
|
||||
at listRuns (file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:485:46)
|
||||
at file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:645:5
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:569:25)
|
||||
at async node:internal/modules/esm/loader:650:26
|
||||
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
|
||||
|
||||
Node.js v26.8.1
|
||||
|
||||
|
||||
1 !== 0
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r82/packages/runs/tests/task-cli.test.mjs:59: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: 1,
|
||||
expected: 0,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r82-out/mutants-candidate/orig 2026-10-11 20:29:10.825411670 -0500
|
||||
+++ scripts/mosaic-task.mjs 2026-10-11 20:30:09.006055076 -0500
|
||||
@@ -478,7 +478,7 @@
|
||||
let session = "-";
|
||||
if (result) {
|
||||
if (typeof result.status === "string") status = result.status;
|
||||
- if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
+ taskId = result.taskId;
|
||||
if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
if (typeof result.session === "string") session = result.session;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.771474ms)
|
||||
✔ a missing data root or runs directory lists nothing (2.813953ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.054785ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (1.206363ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (4.915953ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (2.764918ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.419586ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.709871ms)
|
||||
✔ readRunDocument reads only the three run documents (1.262914ms)
|
||||
✔ a link inside the data root is followed (1.982581ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.099763ms)
|
||||
✔ a run directory linked out of the data root is never read (1.16657ms)
|
||||
✔ a document linked out of the data root reads as null (5.674742ms)
|
||||
✔ a runs directory linked out of the data root refuses (1.139878ms)
|
||||
✔ a relative link that climbs out of the data root refuses (3.18749ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (1.736634ms)
|
||||
✔ a link loop refuses instead of reading as missing (4.90889ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.978501ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (4.945408ms)
|
||||
✔ a link to the data root's parent is outside it (0.993881ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (3.732088ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (1.031311ms)
|
||||
✔ the readers write nothing (4.208472ms)
|
||||
✔ no pointer is null (3.315225ms)
|
||||
✔ the pointer release.sh writes reads back (2.589122ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (4.043643ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.005586ms)
|
||||
✔ a state file linked out of the data root refuses (2.37687ms)
|
||||
✔ a state directory linked out of the data root refuses (1.292878ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (0.780712ms)
|
||||
✔ a missing log is empty (0.679308ms)
|
||||
✔ the log reads oldest first and counts malformed lines (2.170115ms)
|
||||
✔ last must be a positive integer (1.140745ms)
|
||||
✔ the state readers write nothing (2.587193ms)
|
||||
✔ list prints each run in the established format (137.246983ms)
|
||||
✖ list prints a damaged result.json as unknown and keeps listing the runs after it (182.376976ms)
|
||||
✖ list prints each result field that isn't a string as unknown or - (546.979624ms)
|
||||
✔ show prints the run in the established format (286.705913ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (543.28419ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (439.769449ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (521.985806ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (124.760819ms)
|
||||
✔ show refuses an invalid id before reading the config (156.920806ms)
|
||||
ℹ tests 43
|
||||
ℹ suites 0
|
||||
ℹ pass 41
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 3136.926367
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:35:1
|
||||
✖ list prints a damaged result.json as unknown and keeps listing the runs after it (182.376976ms)
|
||||
AssertionError [ERR_ASSERTION]: file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:485
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
^
|
||||
|
||||
TypeError: Cannot read properties of undefined (reading 'padEnd')
|
||||
at listRuns (file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:485:72)
|
||||
at file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:645:5
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:569:25)
|
||||
at async node:internal/modules/esm/loader:650:26
|
||||
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
|
||||
|
||||
Node.js v26.8.1
|
||||
|
||||
|
||||
1 !== 0
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r82/packages/runs/tests/task-cli.test.mjs:42: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 startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
generatedMessage: false,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: 1,
|
||||
expected: 0,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:49:1
|
||||
✖ list prints each result field that isn't a string as unknown or - (546.979624ms)
|
||||
AssertionError [ERR_ASSERTION]: file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:485
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
^
|
||||
|
||||
TypeError: Cannot read properties of null (reading 'padEnd')
|
||||
at listRuns (file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:485:72)
|
||||
at file:///mnt/storage/scratch/rocko-r82/scripts/mosaic-task.mjs:645:5
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:569:25)
|
||||
at async node:internal/modules/esm/loader:650:26
|
||||
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
|
||||
|
||||
Node.js v26.8.1
|
||||
|
||||
|
||||
1 !== 0
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r82/packages/runs/tests/task-cli.test.mjs:59: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: 1,
|
||||
expected: 0,
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r82-out/mutants-candidate/orig 2026-10-11 20:29:10.825411670 -0500
|
||||
+++ scripts/mosaic-task.mjs 2026-10-11 20:30:12.265567467 -0500
|
||||
@@ -479,7 +479,7 @@
|
||||
if (result) {
|
||||
if (typeof result.status === "string") status = result.status;
|
||||
if (typeof result.taskId === "string") taskId = result.taskId;
|
||||
- if (typeof result.workspace === "string") workspace = result.workspace;
|
||||
+ workspace = String(result.workspace ?? "-");
|
||||
if (typeof result.session === "string") session = result.session;
|
||||
}
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${workspace.padEnd(10)} session=${session}\n`);
|
||||
@@ -0,0 +1,79 @@
|
||||
✔ isRunId accepts the run id shape and nothing else (1.857681ms)
|
||||
✔ a missing data root or runs directory lists nothing (3.076798ms)
|
||||
✔ runs as a regular file lists nothing, as before (1.106032ms)
|
||||
✔ listRunIds keeps r- names only, sorted oldest first (3.969184ms)
|
||||
✔ listRunRecords returns each result, or null for an incomplete or unreadable one (3.924032ms)
|
||||
✔ readRunRecord returns documents and artifacts in directory order (2.037313ms)
|
||||
✔ readRunRecord is null for a missing run, a dangling link or a file (1.373053ms)
|
||||
✔ readRunRecord and readRunDocument refuse an invalid run id before touching the disk (1.358795ms)
|
||||
✔ readRunDocument reads only the three run documents (0.980627ms)
|
||||
✔ a link inside the data root is followed (1.842269ms)
|
||||
✔ a data root that is itself a link is trusted as configured (1.09261ms)
|
||||
✔ a run directory linked out of the data root is never read (1.253537ms)
|
||||
✔ a document linked out of the data root reads as null (1.8952ms)
|
||||
✔ a runs directory linked out of the data root refuses (1.037846ms)
|
||||
✔ a relative link that climbs out of the data root refuses (0.875211ms)
|
||||
✔ a sibling whose name starts with the data root's name is outside it (1.181116ms)
|
||||
✔ a link loop refuses instead of reading as missing (1.238921ms)
|
||||
✔ an unreadable runs directory refuses instead of listing nothing (0.946737ms)
|
||||
✔ an unreadable run directory refuses instead of reading as missing (1.054035ms)
|
||||
✔ a link to the data root's parent is outside it (0.790977ms)
|
||||
✔ listRunIds sorts whatever order the directory returns (1.366192ms)
|
||||
✔ listRunRecords lists an r- name that isn't a valid run id, as before (0.920499ms)
|
||||
✔ the readers write nothing (4.057365ms)
|
||||
✔ no pointer is null (3.338741ms)
|
||||
✔ the pointer release.sh writes reads back (2.357401ms)
|
||||
✔ a pointer that isn't the version 1 shape refuses with exit 2 (4.1093ms)
|
||||
✔ a pointer that is a directory refuses with exit 4 (1.125582ms)
|
||||
✔ a state file linked out of the data root refuses (2.732175ms)
|
||||
✔ a state directory linked out of the data root refuses (1.021862ms)
|
||||
✔ a state directory linked out to nothing reads as no release and an empty log (2.893264ms)
|
||||
✔ a missing log is empty (0.889532ms)
|
||||
✔ the log reads oldest first and counts malformed lines (2.186929ms)
|
||||
✔ last must be a positive integer (0.97445ms)
|
||||
✔ the state readers write nothing (1.568499ms)
|
||||
✔ list prints each run in the established format (151.820565ms)
|
||||
✔ list prints a damaged result.json as unknown and keeps listing the runs after it (270.264065ms)
|
||||
✖ list prints each result field that isn't a string as unknown or - (199.201847ms)
|
||||
✔ show prints the run in the established format (281.832905ms)
|
||||
✔ show of a missing run and an invalid id exit 4 as before (355.550962ms)
|
||||
✔ list and show refuse a runs directory linked out of the data root (230.346819ms)
|
||||
✔ show refuses a run linked out of the data root; list reports it unknown (285.885439ms)
|
||||
✔ list shows an r- name that isn't a valid run id, as before (115.047027ms)
|
||||
✔ show refuses an invalid id before reading the config (67.647985ms)
|
||||
ℹ tests 43
|
||||
ℹ suites 0
|
||||
ℹ pass 42
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 2089.439062
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/runs/tests/task-cli.test.mjs:49:1
|
||||
✖ list prints each result field that isn't a string as unknown or - (199.201847ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
'r-20260101T000000Z-status unknown task=t-one ws=- session=-\n' +
|
||||
'r-20260101T000001Z-taskid succeeded task=- ws=- session=-\n' +
|
||||
+ 'r-20260101T000002Z-worksp succeeded task=t-one ws=7 session=-\n' +
|
||||
- 'r-20260101T000002Z-worksp succeeded task=t-one ws=- session=-\n' +
|
||||
'r-20260101T000003Z-sessin succeeded task=t-one ws=- session=-\n'
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r82/packages/runs/tests/task-cli.test.mjs:60: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: 'r-20260101T000000Z-status unknown task=t-one ws=- session=-\nr-20260101T000001Z-taskid succeeded task=- ws=- session=-\nr-20260101T000002Z-worksp succeeded task=t-one ws=7 session=-\nr-20260101T000003Z-sessin succeeded task=t-one ws=- session=-\n',
|
||||
expected: 'r-20260101T000000Z-status unknown task=t-one ws=- session=-\nr-20260101T000001Z-taskid succeeded task=- ws=- session=-\nr-20260101T000002Z-worksp succeeded task=t-one ws=- session=-\nr-20260101T000003Z-sessin succeeded task=t-one ws=- session=-\n',
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
same good-list (rc 0, 6 lines)
|
||||
same good-show-r-20260101T000000Z-aaaaaa (rc 0, 11 lines)
|
||||
same good-show-r-20260101T000100Z-bbbbbb (rc 0, 9 lines)
|
||||
same good-show-r-20260101T000200Z-cccccc (rc 0, 10 lines)
|
||||
same good-show-r-20260101T000300Z-dddddd (rc 0, 9 lines)
|
||||
same good-show-r-20260101T000400Z-eeeeee (rc 0, 4 lines)
|
||||
same real-list (rc 0, 6 lines)
|
||||
same real-show-r-20260903T193847Z-b0cdc5 (rc 0, 13 lines)
|
||||
same real-show-r-20260903T193926Z-00bbba (rc 0, 13 lines)
|
||||
same real-show-r-20260903T205744Z-44485b (rc 0, 13 lines)
|
||||
same real-show-r-20260903T205750Z-f444a2 (rc 0, 13 lines)
|
||||
same real-show-r-20260903T205812Z-384152 (rc 0, 13 lines)
|
||||
same real-show-r-20260906T024609Z-68ee7f (rc 0, 11 lines)
|
||||
damaged list: base rc 1, 1 lines; candidate rc 0, 3 lines
|
||||
byte-check rc=0
|
||||
@@ -0,0 +1,13 @@
|
||||
file:///mnt/storage/scratch/rocko-r82-base/scripts/mosaic-task.mjs:484
|
||||
process.stdout.write(`${runId} ${status.padEnd(9)} task=${taskId.padEnd(18)} ws=${String(workspace).padEnd(10)} session=${session}\n`);
|
||||
^
|
||||
|
||||
TypeError: Cannot read properties of undefined (reading 'padEnd')
|
||||
at listRuns (file:///mnt/storage/scratch/rocko-r82-base/scripts/mosaic-task.mjs:484:46)
|
||||
at file:///mnt/storage/scratch/rocko-r82-base/scripts/mosaic-task.mjs:644:5
|
||||
at ModuleJob.run (node:internal/modules/esm/module_job:569:25)
|
||||
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
|
||||
at async node:internal/modules/esm/loader:650:26
|
||||
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5)
|
||||
|
||||
Node.js v26.8.1
|
||||
@@ -0,0 +1 @@
|
||||
r-20260101T000000Z-aaaaaa succeeded task=t-one ws=ws1 session=s1
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,3 @@
|
||||
r-20260101T000000Z-aaaaaa succeeded task=t-one ws=ws1 session=s1
|
||||
r-20260101T000050Z-mmmmmm unknown task=- ws=- session=-
|
||||
r-20260101T000100Z-bbbbbb succeeded task=t-two ws=- session=-
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user