rocko: row 79 round 1 packet, BUILD-LOG and SESSIONS (#1573)
Packet agents/rocko/work/queue-79/ (packet manifest b6b11e7b, 42 files, candidate manifest 16b12387), Rocko's BUILD-LOG and SESSIONS appends. Committed by Sage for Rocko, who has no credential. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
# Row 79 (#1573): coder grant stale text, candidate packet, round 1
|
||||
|
||||
Author: Rocko. Reviewer: Dewey. Brief:
|
||||
`docs/plans/2026-10-11_claude-pin-and-coder-grant.md`, section "Coder
|
||||
grant stale text" (blob 4784ee65, re-pinned by Sage at revs 567-568). It
|
||||
also carries Dewey's row 73 note N1 (comment 27506 on #1567). Base:
|
||||
`331d037c` (`base.txt`). `331d037c..bd4dff33` (2ece4491, bd4dff33,
|
||||
5fc7635c) touches none of this row's paths. I checked that before
|
||||
packing. 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 |
|
||||
|---|---|
|
||||
| `packages/business/README.md` | version 2 example: `crossRole` is `["task.scope.change"]`, so the example matches `roles/coder.json` |
|
||||
| `packages/tasks/README.md` | the `task.reassign` paragraph: the coder holds no grant (row 73), and the writer check refuses a non-pm `task.reassign` before authority anyway |
|
||||
| `packages/tasks/live/run.mjs` | the coder authority line matches `packages/tasks/tests/world.mjs` |
|
||||
| `packages/harness/tests/tools.test.mjs` | coder-without-a-tracker test: one `deepEqual` on the whole untyped list replaces two `includes` asserts (N1) |
|
||||
| `agents/rocko/work/queue-79/mutants.sh` | the mutant rerun: `mutants.sh <tree>` |
|
||||
|
||||
Totals: 4 tracked files, +7 -9, and the new `mutants.sh`. I changed no
|
||||
role file, `broker.mjs`, field table or any other test.
|
||||
|
||||
### run.mjs, the coder line
|
||||
|
||||
The old line was `withinRole: ['task.update.assigned', 'message.send'],
|
||||
crossRole: ['task.reassign', 'task.scope.change']`. It was stale in two
|
||||
ways: the reassign grant, and the missing `git.push.working` and
|
||||
`review.request`. The new line is word for word the coder entry in
|
||||
`world.mjs` and has the same authority as `roles/coder.json`.
|
||||
|
||||
Two other lines in the same `AUTHORITY` object differ from `world.mjs`,
|
||||
and I left them alone because the brief owns only the coder line:
|
||||
|
||||
- pm: `run.mjs` has no `role.launch`. `world.mjs` and `roles/pm.json`
|
||||
have it.
|
||||
- reviewer: `run.mjs` has no `review.verdict`. `world.mjs` and
|
||||
`roles/reviewer.json` have it.
|
||||
|
||||
The live run uses neither action, so this doesn't change its result. If
|
||||
Sage wants the whole object to match, that's a follow-up row.
|
||||
|
||||
## N1: the untyped list (`out/mutants-candidate.txt`, `out/mutants-base.txt`)
|
||||
|
||||
`untypedActions` (`packages/harness/src/tools.mjs:122-125`) returns
|
||||
`[...withinRole, ...crossRole]` minus the actions that have a typed tool.
|
||||
For the shipped coder without a tracker, that is `task.update.assigned`,
|
||||
`git.push.working`, `review.request` and `task.scope.change`.
|
||||
`message.send` is typed (`send_message`). The test now pins that list,
|
||||
including its order, with one `deepEqual`.
|
||||
|
||||
| Mutant | Edit in `packages/harness/src/tools.mjs` | Base `331d037c` | Candidate |
|
||||
|---|---|---|---|
|
||||
| `untyped-within-only` | `return [...withinRole].filter(…)` (Dewey's mutant) | **survived** | killed |
|
||||
| `untyped-cross-first` | `return [...crossRole, ...withinRole].filter(…)` | **survived** | killed |
|
||||
| `untyped-keeps-typed` | `.filter((a) => a === "message.send" \|\| !typed.has(a))` | killed | killed |
|
||||
|
||||
Every kill is in "a coder gets no launch, no resolve_decision, and no
|
||||
task tools without a tracker". On the base, the old `!includes("message.send")`
|
||||
assert already kills `untyped-keeps-typed`. I kept that mutant to show
|
||||
the `deepEqual` doesn't lose that check.
|
||||
|
||||
The script saves the file, applies the sed and checks it changed
|
||||
something. It then runs `packages/harness/tests/tools.test.mjs` and
|
||||
restores the file from the saved copy. The base run used a clean
|
||||
detached worktree at `331d037c`, which I removed afterwards.
|
||||
`out/mutants-*/` holds each diff and log. The script exits 1 on the base,
|
||||
as it should when a mutant survives.
|
||||
|
||||
A correction to my own first run: I wrote `untyped-keeps-typed` with
|
||||
`a !== "message.send"`. That inverts it into a mutant that keeps every
|
||||
typed action except `message.send`, and the coder has no other typed
|
||||
action in `withinRole` or `crossRole`, so it survived. That run says
|
||||
nothing about the test. I fixed the expression to `===` and reran. The
|
||||
outputs in `out/` are from the fixed script only.
|
||||
|
||||
## Repository grep for `task.reassign`
|
||||
|
||||
`git grep -n 'task\.reassign'` on the candidate tree, outside `agents/`:
|
||||
|
||||
| Path | Hits | Why it stays |
|
||||
|---|---|---|
|
||||
| `roles/pm.json:9` | 1 | the pm grant (decision 90: assignee is pm-only) |
|
||||
| `packages/business/src/vocabulary.mjs:17` | 1 | the action vocabulary |
|
||||
| `packages/bus/src/broker.mjs:10` | 1 | the broker's action list. The brief puts `broker.mjs` out of scope |
|
||||
| `packages/harness/src/tools.mjs:46` | 1 | the `task_reassign` typed tool. A pm with a tracker gets it |
|
||||
| `packages/tasks/src/verbs.mjs:13,191,200,201` | 4 | `PM_VERBS` and the verb itself |
|
||||
| `packages/tasks/README.md:107,150,176,193-194` | 5 | the writer-check list, the verb table, the `task-unassigned` refusal, and this row's rewritten paragraph |
|
||||
| `packages/tasks/live/README.md:65` | 1 | the pm's live reassign step |
|
||||
| `packages/tasks/live/run.mjs:29,154` | 2 | the pm grant and the pm's reassign step. The coder line no longer has it |
|
||||
| `packages/tasks/tests/world.mjs:34` | 1 | the pm grant in the test world |
|
||||
| `packages/tasks/tests/verbs.test.mjs:96-110` | 6 | a coder's `task.reassign` refused with `field-writer`, no coder holds it, and the pm's reassign paths |
|
||||
| `packages/tasks/tests/shapes.test.mjs:127` | 1 | a pm reassign |
|
||||
| `packages/bus/tests/broker.test.mjs:361,373,381` | 3 | the shipped coder raises `task.reassign` as gated to the human. That holds because the coder has no grant for it |
|
||||
| `packages/business/tests/resolve.test.mjs:141` | 1 | `classify(coder, "task.reassign")` is `gated`, the same fact |
|
||||
| `packages/business/tests/role.test.mjs:64,117` | 2 | 64 is row 73's comment on the coder file. 117 is a synthetic role that holds the action in both lists, to test that refusal |
|
||||
| `scripts/test-task.sh:279` | 1 | `v2ok`, a synthetic version 2 role with the action in `crossRole`, used only to check that `resolve-role` accepts a minimal role. It isn't the coder |
|
||||
| `docs/design/mosaic-stack-design.html:729,732,975` | 3 | the action list, the pm grant and the verb list. There's no coder grant here |
|
||||
| `docs/plans/2026-10-04_slice-1.md:73` | 1 | the field table: assignee is pm, via `task.assign` and `task.reassign` |
|
||||
| `docs/plans/2026-09-26_lead-decisions.md:1914` | 1 | decision 90's record of the old coder grant, which is history |
|
||||
| `docs/plans/2026-10-11_claude-pin-and-coder-grant.md` | 14 | the briefs for rows 73 and 79 |
|
||||
| `docs/plans/queue.json`, `docs/plans/QUEUE.md` | 5, 1 | row titles and notes |
|
||||
| `BUILD-LOG.md`, `docs/SESSIONS.md` | 7, 2 | append-only history |
|
||||
|
||||
`v1/` has no hits. No hit outside history and briefs shows the coder
|
||||
holding `task.reassign`.
|
||||
|
||||
## Dewey's correction to the row 73 packet
|
||||
|
||||
Dewey's approval of row 73 (comment 27506) corrects a line in that
|
||||
packet. The header of `agents/rocko/work/queue-73/mutants.sh` says "the
|
||||
tasks test kills nothing". That's true only for my five mutants. Dewey's
|
||||
`verbs-reassign-not-pm` mutant is killed only by the verbs line row 73
|
||||
added. The committed row 73 file stays as it is, on Sage's instruction,
|
||||
and this note is the record.
|
||||
|
||||
## Gate (`out/gate/`, sequential, scratch worktree at 331d037c with the candidate, `node_modules` linked)
|
||||
|
||||
Run 00:11:53Z-00:17:41Z (2026-10-12). The brief's gate names the tasks,
|
||||
business and harness suites and every script. I also ran bus, cli,
|
||||
webui and seat, the package set row 73's gate used.
|
||||
|
||||
| Suite | Result |
|
||||
|---|---|
|
||||
| tasks | 71 pass, 0 fail, 0 skipped |
|
||||
| bus | 84 pass, 0 fail, 0 skipped |
|
||||
| business | 60 pass, 0 fail, 0 skipped |
|
||||
| harness | 59 pass, 0 fail, 0 skipped |
|
||||
| cli | 113 pass, 0 fail, 0 skipped (the base predates row 78's added test) |
|
||||
| webui | 61 pass, 0 fail, 0 skipped |
|
||||
| seat | 27 pass, 0 fail, 0 skipped |
|
||||
| test-auth | 15 passed, 0 failed |
|
||||
| test-conductor | 17 passed, 0 failed |
|
||||
| test-config | 24 passed, 0 failed |
|
||||
| test-discord | 66 passed, 0 failed |
|
||||
| test-extension-package | 18 passed, 0 failed |
|
||||
| test-foundation | 44 passed, 0 failed |
|
||||
| test-queue | 27 passed, 0 failed |
|
||||
| test-release | 14 passed, 0 failed |
|
||||
| test-task | 98 passed, 0 failed (Docker) |
|
||||
|
||||
The harness count is unchanged, because the row edits one existing test.
|
||||
After the gate I removed the `rocko-r79_default` network.
|
||||
@@ -0,0 +1 @@
|
||||
331d037cecb27fb1e479dbdfded02c7598ee34a6
|
||||
@@ -0,0 +1,111 @@
|
||||
diff --git a/agents/rocko/work/queue-79/mutants.sh b/agents/rocko/work/queue-79/mutants.sh
|
||||
new file mode 100755
|
||||
index 00000000..0d925699
|
||||
--- /dev/null
|
||||
+++ b/agents/rocko/work/queue-79/mutants.sh
|
||||
@@ -0,0 +1,45 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# Row 79 (#1573): rerun the untyped-list mutants against a tree. Usage:
|
||||
+# mutants.sh <tree>. Each mutant edits untypedActions in
|
||||
+# packages/harness/src/tools.mjs, runs the harness tools test, 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. untyped-within-only stands in
|
||||
+# for Dewey's mutant of that name (row 73 comment 27506).
|
||||
+set -euo pipefail
|
||||
+TREE="$(cd "${1:?usage: mutants.sh <tree>}" && pwd)"
|
||||
+cd "$TREE"
|
||||
+SRC=packages/harness/src/tools.mjs
|
||||
+TESTS=(packages/harness/tests/tools.test.mjs)
|
||||
+run_tests() { node --test "${TESTS[@]}" >"$1" 2>&1; }
|
||||
+
|
||||
+# name | sed expression
|
||||
+MUTANTS=(
|
||||
+ 'untyped-within-only|s/^ return \[\.\.\.resolved\.limits\.authority\.withinRole, \.\.\.resolved\.limits\.authority\.crossRole\]\.filter/ return [...resolved.limits.authority.withinRole].filter/'
|
||||
+ 'untyped-cross-first|s/^ return \[\.\.\.resolved\.limits\.authority\.withinRole, \.\.\.resolved\.limits\.authority\.crossRole\]\.filter/ return [...resolved.limits.authority.crossRole, ...resolved.limits.authority.withinRole].filter/'
|
||||
+ 'untyped-keeps-typed|s/\.filter((a) => !typed\.has(a));$/.filter((a) => a === "message.send" || !typed.has(a));/'
|
||||
+)
|
||||
+
|
||||
+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/business/README.md b/packages/business/README.md
|
||||
index 9c3e8d1f..ca372c5e 100644
|
||||
--- a/packages/business/README.md
|
||||
+++ b/packages/business/README.md
|
||||
@@ -34,7 +34,7 @@ in this repository, or `$MOSAIC_ROLES_DIR` if set.
|
||||
"network": "api-only",
|
||||
"authority": {
|
||||
"withinRole": ["task.update.assigned", "git.push.working", "review.request", "message.send"],
|
||||
- "crossRole": ["task.reassign", "task.scope.change"]
|
||||
+ "crossRole": ["task.scope.change"]
|
||||
},
|
||||
"credentials": [
|
||||
{ "service": "gitea", "scopes": ["write:issue", "write:repository", "read:user"] },
|
||||
diff --git a/packages/harness/tests/tools.test.mjs b/packages/harness/tests/tools.test.mjs
|
||||
index 31606131..3fe7dd1e 100644
|
||||
--- a/packages/harness/tests/tools.test.mjs
|
||||
+++ b/packages/harness/tests/tools.test.mjs
|
||||
@@ -30,9 +30,7 @@ test("a coder gets no launch, no resolve_decision, and no task tools without a t
|
||||
const tools = typedTools({ resolved: coder });
|
||||
assert.deepEqual(names(tools), ["send_message", "raise_decision", "list_agents", "inbox", "trail"]);
|
||||
// Held actions without a tool are listed, so the manifest shows them.
|
||||
- const untyped = untypedActions(coder, tools);
|
||||
- assert.ok(untyped.includes("git.push.working"));
|
||||
- assert.ok(!untyped.includes("message.send"));
|
||||
+ assert.deepEqual(untypedActions(coder, tools), ["task.update.assigned", "git.push.working", "review.request", "task.scope.change"]);
|
||||
});
|
||||
|
||||
test("a coder with a tracker gets its own task tools and no task_reassign", (t) => {
|
||||
diff --git a/packages/tasks/README.md b/packages/tasks/README.md
|
||||
index 61b36664..d47f5de6 100644
|
||||
--- a/packages/tasks/README.md
|
||||
+++ b/packages/tasks/README.md
|
||||
@@ -190,10 +190,10 @@ Details that aren't obvious from the table:
|
||||
- `task.close` moves the task into the done bucket. `verdict` is a
|
||||
citation of the review verdict in the queue. The adapter records it
|
||||
and doesn't check it. Checking it against the queue is a follow-up.
|
||||
-- A coder role's `crossRole` grant of `task.reassign` can't be used. The
|
||||
- writer check refuses it before authority is looked at. If a coder
|
||||
- should hand work on, that's a change to the field table, not to the
|
||||
- role file.
|
||||
+- The coder role holds no `task.reassign` grant (row 73). The writer
|
||||
+ check refuses a non-pm `task.reassign` before authority is looked at
|
||||
+ anyway. If a coder should hand work on, that's a change to the field
|
||||
+ table, not to the role file.
|
||||
|
||||
Verbs for one business run one at a time, in the same queue as the poll,
|
||||
so a poll never reads between two writes of a verb.
|
||||
diff --git a/packages/tasks/live/run.mjs b/packages/tasks/live/run.mjs
|
||||
index eed1513e..0c8d7e97 100644
|
||||
--- a/packages/tasks/live/run.mjs
|
||||
+++ b/packages/tasks/live/run.mjs
|
||||
@@ -29,7 +29,7 @@ const AUTHORITY = {
|
||||
withinRole: ['task.create', 'task.assign', 'task.reassign', 'task.schedule', 'task.update.assigned', 'task.close', 'message.send'],
|
||||
crossRole: ['task.priority.change', 'task.scope.change'],
|
||||
},
|
||||
- coder: { withinRole: ['task.update.assigned', 'message.send'], crossRole: ['task.reassign', 'task.scope.change'] },
|
||||
+ coder: { withinRole: ['task.update.assigned', 'git.push.working', 'review.request', 'message.send'], crossRole: ['task.scope.change'] },
|
||||
reviewer: { withinRole: ['task.update.assigned', 'message.send'], crossRole: [] },
|
||||
};
|
||||
const ref = (x) => (x.file ? { file: x.file, expires: x.expires } : { env: x.env, expires: x.expires });
|
||||
@@ -0,0 +1,5 @@
|
||||
8c9b45ad7bad35832a6a7f101fb1b21b07f8f95dbbc33216eab4bfc98fc5fc8c agents/rocko/work/queue-79/mutants.sh
|
||||
4e16bb3470adbfdd47ab7bcf1222baea01f8880895e8399b0cd398cfbeb8cab2 packages/business/README.md
|
||||
c704e4bdf2d941198de041475c49973add743ea66fa60081fd36758b498dc2c3 packages/harness/tests/tools.test.mjs
|
||||
3feefaa95a6864b2fda00cd2ca235e03989b3be0af1d3415f5f597c83d2a632f packages/tasks/live/run.mjs
|
||||
d2382d780c5532562af1a35a51e199a83ed911b18ca90dcbbc7540a7b14dc70a packages/tasks/README.md
|
||||
@@ -0,0 +1,5 @@
|
||||
agents/rocko/work/queue-79/mutants.sh
|
||||
packages/business/README.md
|
||||
packages/harness/tests/tools.test.mjs
|
||||
packages/tasks/live/run.mjs
|
||||
packages/tasks/README.md
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
# Row 79 (#1573): rerun the untyped-list mutants against a tree. Usage:
|
||||
# mutants.sh <tree>. Each mutant edits untypedActions in
|
||||
# packages/harness/src/tools.mjs, runs the harness tools test, 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. untyped-within-only stands in
|
||||
# for Dewey's mutant of that name (row 73 comment 27506).
|
||||
set -euo pipefail
|
||||
TREE="$(cd "${1:?usage: mutants.sh <tree>}" && pwd)"
|
||||
cd "$TREE"
|
||||
SRC=packages/harness/src/tools.mjs
|
||||
TESTS=(packages/harness/tests/tools.test.mjs)
|
||||
run_tests() { node --test "${TESTS[@]}" >"$1" 2>&1; }
|
||||
|
||||
# name | sed expression
|
||||
MUTANTS=(
|
||||
'untyped-within-only|s/^ return \[\.\.\.resolved\.limits\.authority\.withinRole, \.\.\.resolved\.limits\.authority\.crossRole\]\.filter/ return [...resolved.limits.authority.withinRole].filter/'
|
||||
'untyped-cross-first|s/^ return \[\.\.\.resolved\.limits\.authority\.withinRole, \.\.\.resolved\.limits\.authority\.crossRole\]\.filter/ return [...resolved.limits.authority.crossRole, ...resolved.limits.authority.withinRole].filter/'
|
||||
'untyped-keeps-typed|s/\.filter((a) => !typed\.has(a));$/.filter((a) => a === "message.send" || !typed.has(a));/'
|
||||
)
|
||||
|
||||
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,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -u
|
||||
W=/mnt/storage/scratch/rocko-r79; G=/mnt/storage/scratch/rocko-r79-out/gate
|
||||
mkdir -p $G; cd $W
|
||||
date -u +%Y-%m-%dT%H:%M:%SZ > $G/start.txt
|
||||
: > $G/summary.txt
|
||||
for p in 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,92 @@
|
||||
✔ launch identity is stamped, payload identity is refused and stale holder cannot send (46.763545ms)
|
||||
✔ decision classes route from policy; gated resolution is human-only, choice and target must match (39.207918ms)
|
||||
✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (42.070922ms)
|
||||
✔ launch events require a human CLI capability; generic emit cannot forge authority events (32.542071ms)
|
||||
✔ within-role decisions close atomically and invalid options or blocking omissions refuse (31.518394ms)
|
||||
✔ observer capabilities read human inbox but cannot mutate or forge launch identity (34.180668ms)
|
||||
✔ task action subjects and linked decision trail are complete and ordered (30.714402ms)
|
||||
✔ launch binding is durable and reconnecting requires the identical trusted record (14.057971ms)
|
||||
✔ business isolation includes inherited object names and cross-business message references (22.99639ms)
|
||||
✔ authority never transfers between action, run, target, unresolved or replaced role holder (28.552054ms)
|
||||
✔ task projection uses schema current view, skipping earlier and equal-start polls (18.951726ms)
|
||||
✔ revocation permanently bars the old run from reclaiming first, including after broker restart (23.454392ms)
|
||||
✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (14.861904ms)
|
||||
✔ both arbiters require human resolution when their cross-role route is themselves (26.062558ms)
|
||||
✔ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (25.781751ms)
|
||||
✔ S1 adapter takes resolved limits and refs, rejects mismatched instance, never mutates input (2.557094ms)
|
||||
✔ only validated broker references load; returned data and exceptions cannot expose a known token (6.220455ms)
|
||||
✔ bad file modes, symlinks, repository/data paths, malformed tokens and missing dates refuse (18.303922ms)
|
||||
✔ expiry refuses use and env references never become client data (2.224505ms)
|
||||
✔ S1 parsed service refs work, service mismatch refuses, Gitea rotation due is a warning state (2.44983ms)
|
||||
✔ opaque tokens shorter than 16 characters refuse before use (0.549348ms)
|
||||
✔ roles lists open decisions routed to a role, and never the human inbox (42.711306ms)
|
||||
✔ recent lists closed decisions of every route, newest close first, with how each closed (40.041912ms)
|
||||
✔ recent stops at RECENT rows (159.47863ms)
|
||||
✔ every row is what trail already gives the same session for that id (41.571909ms)
|
||||
✔ a role session can't list decisions, so it can't read another role's open decisions (45.584026ms)
|
||||
✔ decisions is a read: one business, strict arguments, nothing written (43.763563ms)
|
||||
✔ endLaunch writes session.ended, releases the run claim and kills its capabilities (34.889628ms)
|
||||
✔ endLaunch refuses an unknown run, a second end and a rebind of the ended run (19.156647ms)
|
||||
✔ a restarted broker refuses to rebind an ended run; a refused rebind leaves the run unbound (22.589759ms)
|
||||
✔ endLaunch leaves a claim another run took alone (26.156585ms)
|
||||
✔ refuse records action.refused against the caller with the code only (21.096756ms)
|
||||
✔ launches off refuses role.launch with launch-revoked until launches on (37.232155ms)
|
||||
✔ broker process: launch ops authorize role.launch, record refusals and end runs (122.545284ms)
|
||||
✔ human proof binds CLI entry, process start and nonce; agents and incomplete ancestry refuse (3.167499ms)
|
||||
✔ process reader gets own kernel identity without exposing environment values (2.722237ms)
|
||||
✔ EACCES ancestor environments skip only markers; commands and registered launches still refuse (1.221536ms)
|
||||
✔ real pid 1 remains inspectable when its environment is protected (0.507652ms)
|
||||
✔ within-role sends cite an open gated launch decision without spending it or naming it in grants (37.355704ms)
|
||||
✔ missing and foreign-business citations refuse and roll back message and grant (29.27602ms)
|
||||
✔ cross-role sends still need a matching resolved decision and consume it once (47.047642ms)
|
||||
✔ broker process binds trusted launches, offers reader capabilities, refuses human mutation, closes cleanly (130.510562ms)
|
||||
✔ startup token refusal returns safe code without value or partial listening broker (88.852519ms)
|
||||
✔ loaded fixture token is absent from socket replies and SQLite, including refusal evidence (82.517889ms)
|
||||
✔ killed broker leaves an explicit stale lock; another process cannot silently reclaim it (136.118514ms)
|
||||
✔ trusted host registers later launches; socket clients never have a registration verb (71.796279ms)
|
||||
✔ runtime excludes declared project roots even when host supplies no repoRoots (67.563187ms)
|
||||
✔ a refused launch binding leaves the broker and existing capabilities alive; bad protocol stops it (103.065067ms)
|
||||
✔ v3b prototype refusals, views and append-only mutations (134.075416ms)
|
||||
✔ gated approval authorizes once, survives store reopen, and fresh approval works (47.637018ms)
|
||||
✔ another run cannot consume an approval; a failed check leaves it usable (30.403088ms)
|
||||
✔ two scheduled callers have exactly one grant and one consumed refusal (25.589215ms)
|
||||
✔ failed commit rolls consumption back; cross-role consumes and within-role stays reusable (66.263301ms)
|
||||
✔ class drift gated to cross-role refuses before consumption (40.678045ms)
|
||||
✔ class drift cross-role to gated refuses before consumption (27.480924ms)
|
||||
✔ class drift gated to within-role refuses before consumption (24.838606ms)
|
||||
✔ class drift cross-role to within-role refuses before consumption (26.060984ms)
|
||||
✔ class drift within-role to gated refuses before consumption (26.279643ms)
|
||||
✔ class drift within-role to cross-role refuses before consumption (19.685978ms)
|
||||
✔ message.send consumes approval and prevents a later send or authorize (24.897949ms)
|
||||
✔ role.revoke consumes approval and prevents a later revoke or authorize (31.190714ms)
|
||||
✔ creates private WAL store and excludes a second writer until explicit close (27.680957ms)
|
||||
✔ rollback is atomic and schema metadata is checked against trusted DDL, not just itself (22.454027ms)
|
||||
✔ existing empty database and symlink runtime directory refuse, never initialize over damage (27.528578ms)
|
||||
✔ crash during a transaction recovers no partial event after explicit fixture-only lock removal (94.602906ms)
|
||||
✔ writer refuses mixed at/read_at forms atomically, even through trusted SQL helpers (15.092952ms)
|
||||
✔ async transactions refuse before invoking their function (11.340717ms)
|
||||
✔ tasks rows carry priority and requirement for every session that reads tasks (55.432024ms)
|
||||
✔ the read model rebuilds from the ledger: a reopened bus and each trail give the same values (74.532671ms)
|
||||
✔ an empty business and one with snapshots but no task.created read cleanly (22.337569ms)
|
||||
✔ recordTask keeps sync reads and a role write apart (34.213529ms)
|
||||
✔ read_at must be one canonical UTC format, so the projection compares strings safely (16.851097ms)
|
||||
✔ a bad entry refuses the whole record (16.466861ms)
|
||||
✔ taskView reads the projection for one business (22.52833ms)
|
||||
✔ requestTask hands only a holder and a task verb to the handler, and records refusals (46.973875ms)
|
||||
✔ the server sends task verbs to the adapter with its own timeout; other verbs stay synchronous (302.694965ms)
|
||||
✔ without an adapter the server refuses every task verb (20.097993ms)
|
||||
✔ the runtime refuses an invalid adapter and closes a valid one (24.047512ms)
|
||||
✔ the process loads the S3 adapter from plain-data trackers (191.965586ms)
|
||||
✔ socket capability stamps launch identity; shared views use wire, no SQL client (38.358175ms)
|
||||
✔ two wire claims serialize; a lost reply never automatically retries (32.179908ms)
|
||||
✔ malformed, oversized and identity-forging envelopes refuse without echoing input (21.773354ms)
|
||||
✔ client preserves UTF-8 when a response divides a multibyte character (16.736266ms)
|
||||
✔ committed mutation followed by dropped reply reports unknown and is never retried (32.801778ms)
|
||||
ℹ tests 84
|
||||
ℹ suites 0
|
||||
ℹ pass 84
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 821.732719
|
||||
@@ -0,0 +1,68 @@
|
||||
✔ config directory and file path follow MOSAIC_CONFIG (2.183268ms)
|
||||
✔ the fixture business validates and comes back frozen (6.602748ms)
|
||||
✔ two instances may share a definition (2.13351ms)
|
||||
✔ top-level refusals (6.796159ms)
|
||||
✔ arbiters and projects (13.063638ms)
|
||||
✔ role instances (4.562729ms)
|
||||
✔ Vikunja bots (9.67808ms)
|
||||
✔ a role without Vikunja takes no tracker block (2.771037ms)
|
||||
✔ credential references match the definition's services (4.410447ms)
|
||||
✔ launch (9.913796ms)
|
||||
✔ loadBusiness: file checks (2.178237ms)
|
||||
✔ loadBusiness: not a regular file (55.383245ms)
|
||||
✔ loading writes nothing (1.896338ms)
|
||||
✔ names that are Object.prototype properties don't count as declared (3.225168ms)
|
||||
✔ the shipped example refuses as written and validates once filled in (0.656711ms)
|
||||
✔ usage errors exit 4 (405.030898ms)
|
||||
✔ validate: a good business exits 0 and prints instance digests (151.464385ms)
|
||||
✔ validate: project files (558.998158ms)
|
||||
✔ validate: missing files and a broken system config (307.427517ms)
|
||||
✔ validate: credential reference problems exit 2 and name each one (101.183619ms)
|
||||
✔ validate: a token file inside the repository is refused (105.981073ms)
|
||||
✔ validate: role definitions come from MOSAIC_ROLES_DIR (432.868788ms)
|
||||
✔ resolve: prints one instance's record (241.832955ms)
|
||||
✔ resolve: refusals (485.036739ms)
|
||||
✔ parse: exactly one of file or env, plus the service's date (4.324999ms)
|
||||
✔ check: a good file has no problems (1.4598ms)
|
||||
✔ check never opens the file: a write-only token passes (0.597147ms)
|
||||
✔ check: file problems (1.32524ms)
|
||||
✔ check: token files can't live in the repository or dataRoot, even through a linked directory (1.28172ms)
|
||||
✔ check: dates and environment references (0.600572ms)
|
||||
✔ path and load (3.448641ms)
|
||||
✔ refusals (1.930464ms)
|
||||
✔ systemVars flattens the validated config (2.895867ms)
|
||||
✔ precedence: system, business, project, project role, agent (7.189615ms)
|
||||
✔ limits narrow the definition and never widen it (3.369537ms)
|
||||
✔ role.launch stays within-role only for the instance the launch block names (6.447022ms)
|
||||
✔ limits.authority without role.launch leaves the launcher with no launch block (2.407627ms)
|
||||
✔ limits.authority narrows cross-role actions too (1.82741ms)
|
||||
✔ classify (1.316918ms)
|
||||
✔ the record carries what the broker and launcher need (0.984331ms)
|
||||
✔ digest: key order doesn't matter, any value change does (17.686519ms)
|
||||
✔ refusals (6.905781ms)
|
||||
✔ the four shipped version 2 roles load (4.314257ms)
|
||||
✔ shipped role scopes match addendum B section 2 and the SR runbook (1.885955ms)
|
||||
✔ shipped authority follows the note's table (0.856015ms)
|
||||
✔ version 1 files keep loading with no authority (1.415186ms)
|
||||
✔ the conductor policy isn't a role (0.527962ms)
|
||||
✔ a missing role file is exit 4, a symbolic link too (0.601861ms)
|
||||
✔ version 2 refusals (2.541944ms)
|
||||
✔ authority: closed vocabulary, no gated-only action, no overlap (3.583984ms)
|
||||
✔ credentials: Gitea scopes (1.096183ms)
|
||||
✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.694496ms)
|
||||
✔ credentials: services (0.954423ms)
|
||||
✔ contract: a non-empty regular Markdown file beside the role file (1.126891ms)
|
||||
✔ every key names known layers and a merge rule (3.028061ms)
|
||||
✔ unknown keys and wrong layers refuse (1.183861ms)
|
||||
✔ types (4.110335ms)
|
||||
✔ merge: defaults, then the most specific layer wins (0.467747ms)
|
||||
✔ merge: limits only narrow, and provenance lists each source (0.818552ms)
|
||||
✔ merge doesn't change its inputs (0.255662ms)
|
||||
ℹ tests 60
|
||||
ℹ suites 0
|
||||
ℹ pass 60
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 2896.07396
|
||||
@@ -0,0 +1,123 @@
|
||||
✔ every screen and overlay fits 120x36, 80x24 and the narrow layout, row for row (1536.180636ms)
|
||||
✔ width counts terminal cells: wide CJK and emoji 2, U+FE0F after a one-cell base 1, marks 0 (67.12178ms)
|
||||
✔ broker text is shown, never interpreted: no raw control character or bidi override reaches the terminal (180.31339ms)
|
||||
✔ NO_COLOR: no escape codes, except reverse video on the selected row (296.248694ms)
|
||||
✔ 1-9 shows the decide flow's own lines and question; only y resolves (49.361967ms)
|
||||
✔ the app shows the same decide text as mosaic decide (21.991744ms)
|
||||
✔ any key but y or Y at the question answers No; nothing is sent (174.879507ms)
|
||||
✔ below 40x10 the question is hidden, so every key answers it No, y included (Filbert R3) (68.843117ms)
|
||||
✔ a throw while answering the question goes to crash, sends nothing and leaves no job pending (19.838983ms)
|
||||
✔ type-ahead never answers the question: a paste, keys typed before it is drawn, keys inside askMs (396.675943ms)
|
||||
✔ quitting at the question answers No and sends nothing, armed or not (35.226598ms)
|
||||
✔ a timer tick reads nothing under an overlay, never answers the question, and keeps a resolved status (32.447873ms)
|
||||
✔ a long question is cut inside the question; the action, target, choice and prompt stay (Dewey B1) (43.375305ms)
|
||||
✔ a decide box too big for the terminal says so, and every key answers it No, y included (Dewey B1, round 3) (311.101942ms)
|
||||
✔ at every size the decide box shows each line y depends on, or says it is hidden (9635.451681ms)
|
||||
✔ outcome unknown: the CLI's sentence, no retry, then the trail or a re-read (58.532739ms)
|
||||
✔ refused and failed reads keep the last list, marked stale; a refused decide says refused (27.875194ms)
|
||||
✔ keys: views, moving, trail of a selection, the command line, help and quit (67.457501ms)
|
||||
✔ one option: the status line says Press 1, not 1-1 (18.910434ms)
|
||||
✔ no business: the app says so and :business picks one (8.954235ms)
|
||||
✔ mosaic with no argument: exit 3 in an agent run, exit 4 with the usage off a terminal, the app on one (1.464487ms)
|
||||
✔ scripts/mosaic with no argument reaches the app entry; the seat usage it printed before has not drifted (175.561159ms)
|
||||
✔ strings to keep exactly live once, in the decide flow and the transport; the app does not restate them (0.468186ms)
|
||||
✔ decide with --note still asks; a No sends nothing (9.530517ms)
|
||||
✔ the app's business comes from a live bus host only (0.956356ms)
|
||||
✔ runApp leaves the terminal as it found it on q, end of input, SIGTERM, SIGINT, SIGHUP and an error, the first frame's included (6.660612ms)
|
||||
✔ draw is pure: same state, same frame (0.755716ms)
|
||||
✔ inbox lists only decisions routed to the human, with what approving authorizes and how to decide (26.931613ms)
|
||||
✔ decide resolves by id prefix with --yes, and the trail shows it in broker order with the task to follow (19.324909ms)
|
||||
✔ decide refuses without a terminal or --yes, on an unknown option and on a short reference (17.397252ms)
|
||||
✔ decide prints a declining choice as declining (14.887269ms)
|
||||
✔ an unknown outcome is reported once and never resent (15.148535ms)
|
||||
✔ a decision closed before the answer arrives exits 2 and points at its trail (17.3086ms)
|
||||
✔ a prefix that matches two open decisions exits 2 and resolves neither (17.762474ms)
|
||||
✔ without --business a command uses the live host's business, and a stale host.json is not a host (17.617717ms)
|
||||
✔ every human command refuses inside an agent run before it touches the bus (17.000181ms)
|
||||
✔ usage errors exit 4; no business and no host is a usage error (18.92841ms)
|
||||
✔ agents and tasks print through the broker (11.431838ms)
|
||||
✔ notify.json: missing, loose, malformed and extra keys refuse; a binding or null passes (2.312051ms)
|
||||
✔ bootConfig builds the broker's boot message for one business, with no trackers key when no project names one (72.93434ms)
|
||||
✔ trackers come from the tracker.* variables of the one project that names a tracker project (101.781602ms)
|
||||
✔ with two projects, the one that sets tracker.project supplies the tracker and the other is no conflict (62.88584ms)
|
||||
✔ two projects that each name a tracker project refuse, since the boot shape holds one (53.950996ms)
|
||||
✔ a business without tracker.baseUrl gets no trackers entry (44.2682ms)
|
||||
✔ an unknown business and a broken system config refuse with exit 3 (82.955787ms)
|
||||
✔ empty views say so (1.156083ms)
|
||||
✔ the trail keeps the broker's order and names a decision's task without its rows (1.421351ms)
|
||||
✔ tasks print the tracker fields the snapshot carries (0.252011ms)
|
||||
✔ the host boots the broker, binds a launch in process, and the notifier DMs a blocking decision exactly once (937.330439ms)
|
||||
✔ a notifier that dies takes the host down with exit 1, so the unit restarts the pair (197.504639ms)
|
||||
✔ a second host for the same data root refuses with exit 3 while the first runs (90.298055ms)
|
||||
✔ a broker reply that misses the wait breaks the channel: the late reply answers nothing, later requests refuse, the host exits 1 (1093.533039ms)
|
||||
✔ a broker reply with another request's id, or none, breaks the channel and the host exits 1 (185.133338ms)
|
||||
✔ a broker reply with no request waiting breaks the channel and the host exits 1 (92.69269ms)
|
||||
✔ a notifier that refuses stops the broker and the host refuses with exit 3 (168.649645ms)
|
||||
✔ a notifier that refuses after the broker died still refuses with exit 3, without a send to the dead broker (165.323995ms)
|
||||
✔ a notifier that dies before it replies, after the broker died, still refuses, without a send to the dead broker (114.462331ms)
|
||||
✔ a close send that fails with EPIPE after the notifier refuses still gives the notifier's refusal, exit 3 (181.066365ms)
|
||||
✔ a close send that fails with EPIPE after the notifier dies unanswered still gives the notifier's error (98.527885ms)
|
||||
✔ close() whose stop and close sends fail with EPIPE still finishes, with exit 1 (176.828346ms)
|
||||
✔ watchChildren reports a child that died before it was called, and one that dies later (32.520397ms)
|
||||
✔ bus stop refuses to signal a live pid that is not a bus host (204.350467ms)
|
||||
✔ bus start refuses with exit 3 and the code when the broker refuses to boot; bus status names the lock (291.835756ms)
|
||||
✔ bus start refuses with exit 3 without a notifier config (125.011319ms)
|
||||
✔ bus start runs until bus stop; status reports it while it runs (751.583406ms)
|
||||
✔ bus-service.sh renders the unit and installs it into a given directory (49.324812ms)
|
||||
✔ bus-service.sh pins the claude binary, refuses one the unit can't carry, and renders without one (74.843787ms)
|
||||
✔ bus-service.sh refuses a directory pin and keeps a symlink default unresolved (16.991554ms)
|
||||
✔ bus start --pm: the PM runs under its own PID namespace, registered, with a manifest (1234.464592ms)
|
||||
✔ the PM launches a coder through its launch tool; the coder answers; refusals name their code (472.250175ms)
|
||||
✔ a runner that stops at once ends its launch with the runner's reason (183.978664ms)
|
||||
✔ 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 (595.223962ms)
|
||||
✔ 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 (3540.512527ms)
|
||||
✔ a malformed sessions.json refuses the host start with exit 3 and stays as it was (83.352754ms)
|
||||
✔ an over-long launch request is refused at once, not at the 10 s idle timeout (94.653395ms)
|
||||
✔ a launch client that never closes its side doesn't hold the host's close (100.565088ms)
|
||||
✔ a runner that ignores SIGTERM is killed when the host closes (1198.710982ms)
|
||||
✔ claudeVersion asks MOSAIC_CLAUDE_BIN when set, else claude on PATH (10.046277ms)
|
||||
✔ zoned uses the IANA zone across DST (26.304529ms)
|
||||
✔ each open blocking decision is DM'd once, across polls and a restart; non-blocking ones are not (25.737085ms)
|
||||
✔ two blocking decisions get two DMs with different nonces (18.39801ms)
|
||||
✔ the digest nonce differs per business and per day and fits Discord's 25 characters (0.335883ms)
|
||||
✔ a failed DM is journaled, backs off, and is retried until it lands (18.21639ms)
|
||||
✔ five definite refusals stop a DM: one gave-up line, one log line, and a restart keeps the count (22.895804ms)
|
||||
✔ 429s, 5xx-style unknowns and refusals without a status never count toward the limit (21.450999ms)
|
||||
✔ a crash between the fifth refusal and its gave-up line: the next poll appends it and sends nothing (17.824901ms)
|
||||
✔ 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 (145.903728ms)
|
||||
✔ a restart after the second refusal does not send before that refusal's 30 min are up (45.100795ms)
|
||||
✔ the digest goes at 08:00 Chicago once a day, with blocking ones marked as DM'd (15.675121ms)
|
||||
✔ a late start with no digest for the day sends one at once; an empty inbox gets one line (9.803946ms)
|
||||
✔ an inbox read failure is logged and the next poll retries (0.91292ms)
|
||||
✔ no Discord id reaches the journal or the log (9.955328ms)
|
||||
✔ the journal: a torn tail is copied out and truncated, so an append after it reopens cleanly (2.976182ms)
|
||||
✔ the journal: a crash between the copy and the truncate leaves a tail the next open repairs (2.989845ms)
|
||||
✔ the journal: a whole file that is one torn line truncates to empty (1.78217ms)
|
||||
✔ the journal: a malformed complete line refuses and leaves the file and any torn tail alone (0.699087ms)
|
||||
✔ the journal: a loose file mode, a loose directory or a symlinked journal refuses (0.806322ms)
|
||||
✔ the journal: a line with a wrong type refuses with exit 3 and names the field (5.410841ms)
|
||||
✔ the journal: a symlinked directory refuses and says it is a link (0.729068ms)
|
||||
✔ 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.09788ms)
|
||||
✔ the journal: an append after the file was swapped for a symlink refuses and writes nothing through it (1.353663ms)
|
||||
✔ the journal: a directory it cannot write or create refuses with exit 3 and names the path (0.959083ms)
|
||||
✔ digest content stays within Discord's 2000 characters (0.582408ms)
|
||||
✔ runLoop never overlaps ticks and stops after the one in flight (111.083751ms)
|
||||
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 (352.406648ms)
|
||||
✔ the transport writes {business, verb, args} to the child and reads its JSON (49.887462ms)
|
||||
✔ a bus code on stderr becomes the exit code; garbage and timeouts are outcome problems (2237.899349ms)
|
||||
✔ busExit and refuseInsideAgent (0.469372ms)
|
||||
✔ talk sends a REQUEST, prints and reads everything that arrives, and stops at the reply (53.98155ms)
|
||||
✔ talk --wait 0 only sends; no reply within --wait exits 1 and says where it will show (1021.436309ms)
|
||||
✔ talk, stop and launches off/on refuse inside an agent run; bad arguments are usage errors (10.113244ms)
|
||||
✔ launches off and on go to the broker and change the business's launch state (9.786186ms)
|
||||
✔ launches list reads sessions.json and marks a stale entry; stop reports it and refuses a non-runner (11.086871ms)
|
||||
ℹ tests 113
|
||||
ℹ suites 0
|
||||
ℹ pass 113
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 13398.761644
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-12T00:17:41Z
|
||||
@@ -0,0 +1,67 @@
|
||||
✔ sessionModel: agent vars win, then the system's execution settings (15.097602ms)
|
||||
✔ a pi bundle: prompt, policy, tools and manifest, 0600 in a 0700 directory (6.097868ms)
|
||||
✔ a claude-code bundle adds the wrapped gate hook and the MCP config (3.358165ms)
|
||||
✔ a bundle is written once: an existing file refuses (2.910743ms)
|
||||
✔ a path with a single quote can't go into the hook command (2.716976ms)
|
||||
✔ allow exits 0, a deny exits 2 with the reason on stderr (198.562157ms)
|
||||
✔ a missing or wrong policy, or a bad event, exits 2 (125.951469ms)
|
||||
✔ the bundle's wrapped command: a missing gate or node still blocks (1138.55797ms)
|
||||
✔ claude: typed tools through MCP, the hook blocks, builtins outside --tools don't exist (1449.8132ms)
|
||||
✔ claude: the hook alone blocks a path outside the workspace (552.581946ms)
|
||||
✔ claude: a second turn resumes the first turn's session (887.521272ms)
|
||||
✔ claude adapter: --restricted is always passed (7.845157ms)
|
||||
✔ claude adapter: MOSAIC_CLAUDE_BIN wins over PATH and must be an absolute executable (36.152914ms)
|
||||
✔ claude adapter: a directory pin exits 2 before it runs; a pin with a space runs (11.658979ms)
|
||||
✔ claude: CLAUDE.md files and auto-memory don't reach the model; without --restricted they do (945.726312ms)
|
||||
✔ claude: a missing hook or MCP file refuses before claude starts (10.879578ms)
|
||||
✔ pi: policy tools and typed tools pass, anything else is blocked (3.997626ms)
|
||||
✔ claude: builtins map from pi names, typed tools need the mcp prefix (1.095666ms)
|
||||
✔ file tool paths must resolve inside the workspace (1.903989ms)
|
||||
✔ pi's own path normalisation can't be used to step out (1.523161ms)
|
||||
✔ a symlink inside the workspace that points out is outside (0.986938ms)
|
||||
✔ a dangling symlink is refused at any depth, in both harnesses (4.595008ms)
|
||||
✔ read is checked under every spelling pi's read would open, in both harnesses (24.131388ms)
|
||||
✔ other spellings cover directories, dangling links and pi's cwd (1.889138ms)
|
||||
✔ a relative path climbs from the workspace's real path, in both harnesses (7.448035ms)
|
||||
✔ claude path fields per tool (2.25162ms)
|
||||
✔ glob patterns stay inside the workspace (0.810033ms)
|
||||
✔ a path that can't be checked is blocked (0.375567ms)
|
||||
✔ initialize, ping and tools/list (66.981066ms)
|
||||
✔ tools/call goes through the tool socket; a refusal is an isError result (54.207372ms)
|
||||
✔ unknown tools and methods are JSON-RPC errors and never reach the socket (52.929411ms)
|
||||
✔ a missing argument is a usage error (53.671989ms)
|
||||
✔ pi: typed tools reach the socket, the gate blocks, agent_end writes the marker (573.847505ms)
|
||||
✔ pi: a write through a dangling symlink is blocked, and nothing appears outside (397.472721ms)
|
||||
✔ pi: a read is refused when pi would open another spelling outside (343.928275ms)
|
||||
✔ pi: a relative path climbs from the real path of a workspace behind a symlink (393.322868ms)
|
||||
✔ pi: a relative path climbs from the real path of a dataRoot behind a symlink (417.483266ms)
|
||||
✔ pi: a missing extension refuses before any model call (8.185612ms)
|
||||
✔ pi: an extension without its configuration fails pi's start (335.304274ms)
|
||||
✔ founderCheck: founder variables, then a needed service without a usable token (2.517134ms)
|
||||
✔ turnRequest names the sender, class, reply and decision (0.333266ms)
|
||||
✔ a message becomes a turn, the answer goes back as a RESULT, SIGTERM releases and exits 0 (228.464532ms)
|
||||
✔ a SIGTERM before the claim stops the runner with exit 0 and no claim (81.232047ms)
|
||||
✔ typed tools carry the runner's capability; launch goes to the host's launch socket (390.880481ms)
|
||||
✔ a RESULT gets no automatic reply; failed turns reply with the reason (1224.709889ms)
|
||||
✔ SIGTERM during a turn kills the turn's process group and still exits 0 (124.494814ms)
|
||||
✔ founder credentials stop before the claim (20) (120.95178ms)
|
||||
✔ a refused claim exits 21; an ended run's capability exits 22 (125.318769ms)
|
||||
✔ the launch ending under a running session exits 22 (115.856272ms)
|
||||
✔ a broker that stays unreachable exits 23 after brokerRetries polls (213.292434ms)
|
||||
✔ a broker that is down at the claim exits 23, not 21 (63.560481ms)
|
||||
✔ no capability, or a malformed one, on stdin exits 2 (202.236177ms)
|
||||
✔ a missing or malformed policy exits 2 before the claim (128.552785ms)
|
||||
✔ the PM gets launch, its task verbs and the reads (10.750162ms)
|
||||
✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.109782ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (2.453379ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (3.203499ms)
|
||||
✔ an action outside the instance's authority has no tool (3.229567ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (12.162075ms)
|
||||
ℹ tests 59
|
||||
ℹ suites 0
|
||||
ℹ pass 59
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 10229.260926
|
||||
@@ -0,0 +1,35 @@
|
||||
✔ resolveSeat: by name under --repo resolves the repo layout (2.906146ms)
|
||||
✔ resolveSeat: by path resolves the fleet layout (0.779689ms)
|
||||
✔ resolveSeat: refusals for missing dir, missing launch.sh, non-executable launch.sh, invalid name, and unknown layout (1.668958ms)
|
||||
✔ tmuxContext: outside tmux, default socket, custom socket, and exec failure (1.375449ms)
|
||||
✔ makeRegistration produces a record that validates; each shape violation throws SeatError (1.682596ms)
|
||||
✔ writeRegistration/readRegistration: round trip, permissions, absence, and malformed records (2.811175ms)
|
||||
✔ updateTask: changes task, taskSetBy and updatedAt only, and refuses appropriately (2.527075ms)
|
||||
✔ CLI launch: registers, execs the fake launch script, and passes args through (47.092168ms)
|
||||
✔ CLI launch: --harness lands in the record (44.521233ms)
|
||||
✔ CLI launch: the launch script's own exit code passes through (47.042592ms)
|
||||
✔ CLI launch: relaunching a seat rewrites the one registration record (108.56695ms)
|
||||
✔ CLI launch: omitting --task records an empty string, not null (50.970252ms)
|
||||
✔ CLI seat task: updates only the task after a launch, and refuses on an unlaunched seat (166.7263ms)
|
||||
✔ CLI refusals: no args, unknown flag, missing config, already-registered env, and exec failure (253.281917ms)
|
||||
✔ samePath: equal paths, symlinked dirs, distinct dirs, and non-strings (0.716742ms)
|
||||
✔ resolveSetBy: explicit --by wins over the environment; absent or empty environment gives unknown; invalid explicit or environment values refuse with exit 4 (1.234669ms)
|
||||
✔ 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 (1.031888ms)
|
||||
✔ 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 (1.777342ms)
|
||||
✔ 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 (524.917291ms)
|
||||
✔ family: exactly one launch.max key in the model name, else null (0.88077ms)
|
||||
✔ sessionEnv passes only the allowlist, the repo's bin on PATH, and the run id (0.951983ms)
|
||||
✔ newRun: short ids, 0700 directories, and a refusal when the socket path won't fit (2.668467ms)
|
||||
✔ session file and launch log: 0600, the session file written once (1.657492ms)
|
||||
✔ endReason maps the runner's exit codes; a signal is killed (0.191811ms)
|
||||
✔ Registry mirrors to sessions.json; readSessions marks live entries; bad files refuse (1.892694ms)
|
||||
✔ stopSession refuses an unknown run, reports a stale one, and won't signal a pid that isn't a runner (1.440688ms)
|
||||
✔ a session runs under unshare as pid 1 of its namespace, claims, answers, and stops on mosaic stop (248.912611ms)
|
||||
ℹ tests 27
|
||||
ℹ suites 0
|
||||
ℹ pass 27
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1364.839999
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-12T00:11:53Z
|
||||
@@ -0,0 +1,16 @@
|
||||
tasks rc=0 ℹ pass 71 ℹ fail 0 ℹ skipped 0
|
||||
bus rc=0 ℹ pass 84 ℹ 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 113 ℹ fail 0 ℹ skipped 0
|
||||
webui rc=0 ℹ pass 61 ℹ 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 (17.31034ms)
|
||||
✔ a business with no tracker entry refuses task verbs (15.417448ms)
|
||||
✔ credential.expiring and .expired are recorded once per instance (29.923225ms)
|
||||
✔ a token file that changes on disk records credential.changed (14.483636ms)
|
||||
✔ autostart polls, reconciles and retries a startup the tracker was down for (40.940808ms)
|
||||
✔ a refusal a restart must clear is not retried by the poll (15.149673ms)
|
||||
✔ a poll that fires while two are queued is dropped (23.014072ms)
|
||||
✔ close waits for a running verb and refuses one that has not started (51.216077ms)
|
||||
✔ the bundled Vikunja is the pinned upstream image the runbook names (1.462225ms)
|
||||
✔ every published port is on 127.0.0.1, and no secret is in the file (0.551338ms)
|
||||
✔ the fake answers each route with the statuses and shapes Vikunja v2.7.0 sent (111.165006ms)
|
||||
✔ the project list holds recorded project objects in the recorded list envelope (13.798135ms)
|
||||
✔ the recorded task bodies pass the checks S3 applies to every read (0.920338ms)
|
||||
✔ the client works against the fake over real HTTP with the platform fetch (139.135362ms)
|
||||
✔ a correct install starts, and the first reconcile records tasks that already exist (28.656714ms)
|
||||
✔ verbs refuse while a business is starting and after startup refused it (15.275601ms)
|
||||
✔ startup refuses a token that can do more than its role needs (43.930148ms)
|
||||
✔ startup refuses an unsupported version and flags an untested one (43.552985ms)
|
||||
✔ startup refuses a board that the runbook did not install (55.746058ms)
|
||||
✔ startup refuses a project the sync bot cannot read (12.887974ms)
|
||||
✔ startup refuses a configured label the pm bot cannot see (12.749843ms)
|
||||
✔ startup refuses an expired credential and a missing sync credential (22.364084ms)
|
||||
✔ an unreachable tracker refuses with tracker-unavailable (7.728412ms)
|
||||
✔ an edit in the UI is recorded once, with the fields that changed (81.42524ms)
|
||||
✔ a move between open buckets is seen on the board, though updated does not change (46.885744ms)
|
||||
✔ a person's comment is counted and a bot's is not (89.948736ms)
|
||||
✔ the hourly reconcile catches a comment through comment_count (86.11245ms)
|
||||
✔ a task closed in the UI leaves the open view with its done bucket (116.06318ms)
|
||||
✔ a task that leaves the board is recorded as deleted, moved or out of reach (65.93744ms)
|
||||
✔ a poll that read before a verb wrote does not overwrite the verb (37.780011ms)
|
||||
✔ a tracker fault during a tick is reported and the next tick catches up (39.93548ms)
|
||||
✔ a malformed answer refuses the tick with tracker-shape (17.666421ms)
|
||||
✔ no token value reaches the database, the log or a refusal (58.089972ms)
|
||||
✔ the first look at a task counts only comments inside the window (39.280576ms)
|
||||
✔ with descendants off the adapter reads no project list and no child, as in v0 (46.696061ms)
|
||||
✔ a three-level tree is read per project, and a project outside it is not (24.050392ms)
|
||||
✔ a watch-only child keeps the business ready, and a failed child read refuses as transient (38.727896ms)
|
||||
✔ a root without the installed buckets refuses with descendants on (18.069228ms)
|
||||
✔ the project list refuses without read_all, and skips archived projects and saved filters (28.932018ms)
|
||||
✔ descendants must be true or false (10.587085ms)
|
||||
✔ a move inside the tree is a moved tombstone plus a snapshot under the new ref (73.836158ms)
|
||||
✔ a child made after startup joins the tree at the next reconcile (58.273086ms)
|
||||
✔ a child that leaves the tree has its tasks recorded missing, and the ledger keeps their history (60.609224ms)
|
||||
✔ a child deleted or hidden between reconciles drops out at the next tick, and the root still refuses (82.216922ms)
|
||||
✔ a reconcile that fails keeps the previous tree (32.627677ms)
|
||||
✔ a closed task the cursor missed takes its own project's done bucket (35.136311ms)
|
||||
✔ closed tasks read at startup take their own project's done bucket (12.164463ms)
|
||||
✔ a closed task the cursor returns takes its own project's done bucket (34.515202ms)
|
||||
✔ a task moved out of a child that leaves the tree at the same time is moved, not no-access (38.955833ms)
|
||||
✔ a task in a bucket outside the five keeps its raw bucket id (33.098481ms)
|
||||
✔ bucket 0 on a watch-only task never becomes a bucket or a state (83.86468ms)
|
||||
✔ a child whose kanban view is deleted still refuses the tick, and the reconcile reads it watch-only (56.861668ms)
|
||||
✔ a child dropped at a tick comes back at the next reconcile once the bot reads it again (36.322511ms)
|
||||
✔ task.create needs a recorded human request and a requirement id (40.830579ms)
|
||||
✔ only labels named in the business file can be written (28.518622ms)
|
||||
✔ task.schedule sets and clears a due date and relations (50.631247ms)
|
||||
✔ assign and reassign move the role bots and record task.assigned (80.008732ms)
|
||||
✔ task.update.assigned is for the assignee and records task.state (63.665102ms)
|
||||
✔ a wrong expected digest records task.conflict and writes nothing (25.450824ms)
|
||||
✔ a cross-role verb needs a resolved decision, used once (26.378053ms)
|
||||
✔ task.close needs a verdict; after it every verb refuses with task-done (25.390764ms)
|
||||
✔ a lost answer is settled by a re-read and never retried (24.145661ms)
|
||||
✔ a create whose answer is lost is reported uncertain, and the poll finds the task (37.314877ms)
|
||||
✔ a task the sync bot cannot read refuses and records nothing (16.440093ms)
|
||||
✔ verbs and polls for one business run one at a time (89.802378ms)
|
||||
✔ a due date with milliseconds is written to the second (68.542785ms)
|
||||
✔ every write landed and the final read failed: the verb succeeds and records what it wrote (44.787838ms)
|
||||
✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (17.816973ms)
|
||||
✔ a create whose final read fails succeeds and records task.created (37.761337ms)
|
||||
✔ an edit between the last write and the final read shows as external on the next poll (40.783799ms)
|
||||
✔ task.created is recorded when a later label write fails (14.762914ms)
|
||||
ℹ tests 71
|
||||
ℹ suites 0
|
||||
ℹ pass 71
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 927.841043
|
||||
@@ -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 '331d037cecb27fb1e479dbdfded02c7598ee34a6'.
|
||||
|
||||
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 '331d037cecb27fb1e479dbdfded02c7598ee34a6'.
|
||||
|
||||
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: 2344807 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-r79) 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,70 @@
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (4281.395968ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5171.551685ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (6048.134859ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (133.61028ms)
|
||||
✔ decisions route serves the roles and recent lists from the reader view (62.759289ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (121.543124ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (143.241275ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (3900.275333ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (495.186193ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (537.243746ms)
|
||||
✔ serve refuses a --business value that is not a business id (715.354032ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4155.17437ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2674.570212ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (1254.950013ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (673.011921ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (3389.583508ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (56924.876207ms)
|
||||
✔ preview options are all three or none, and each is checked (12.607089ms)
|
||||
✔ the CLI refuses a partial or invalid preview flag set at start (3935.511486ms)
|
||||
✔ the CLI with all three flags serves the preview mode (515.742553ms)
|
||||
✔ a request for the public name needs the header equal to the user id, else 401 and nothing read (65.811064ms)
|
||||
✔ the header name matches without regard to case, and the value compare is exact (15.711822ms)
|
||||
✔ the public name with the header reads the bus views, and the Host and Origin are checked first (96.883382ms)
|
||||
✔ in preview mode every write answers 403 read-only, from the public name and loopback, and reaches nothing (40.269673ms)
|
||||
✔ loopback requests are unchanged in preview mode, and the bus views work with the board down (17.38229ms)
|
||||
✔ a proxy that rewrites Host to the loopback port gets 403 on its first request, whatever the user (68.956617ms)
|
||||
✔ a repeated Host is 400 before any other check, in preview mode and without it (45.852634ms)
|
||||
✔ without the preview flags the public name is refused and writes still reach the board (15.688014ms)
|
||||
✔ redactor: config, dataRoot, any absolute path, Discord ids and the JSON parser quote (2.473032ms)
|
||||
✔ credential state from the date alone, as the bus states it (0.306334ms)
|
||||
✔ queue: rows, one row, ids and methods, notes; no path or id from a row (3503.018468ms)
|
||||
✔ queue: a refused read fails closed with the store's text, redacted (1122.846064ms)
|
||||
✔ queue: a store that fails to load, or a child that dies, gives a fixed message with no path or stack (1947.088213ms)
|
||||
✔ business: names, vars on the allowlist, authority, credential metadata only (9.863523ms)
|
||||
✔ business: missing or invalid file refuses with the module's text, redacted (8.396188ms)
|
||||
✔ business without --business: the live bus host, else no-bus-host; no system config: not-configured (9.041038ms)
|
||||
✔ settings: release, board, loopback address, notifier binding name only (174.646706ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (3541.677423ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23126.607183ms)
|
||||
✔ loopback host and board origin fail closed (10.203767ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (173.294715ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (115.700774ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (3429.088587ms)
|
||||
✔ render prints the unit without the preview flags (27.549503ms)
|
||||
✔ render carries every serve flag, the preview set included (23.834301ms)
|
||||
✔ a partial preview set is refused (36.089714ms)
|
||||
✔ a value the unit cannot carry is refused, for every flag (4304.852038ms)
|
||||
✔ the rendered unit names none of the human proof agent markers and sets no agent variable (76.952931ms)
|
||||
✔ install into --dir with --no-reload writes the file whole, then reports unchanged (440.252347ms)
|
||||
✔ install without --no-reload runs daemon-reload and nothing that starts the unit (170.240198ms)
|
||||
✔ uninstall refuses while the unit is active, and removes it once it is not (266.468973ms)
|
||||
✔ status prints the unit state and GET /healthz on the installed port (722.736469ms)
|
||||
✔ usage: an unknown verb or flag, and start or enable, exit 4 (74.94704ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.458637ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.791782ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (2.356704ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (9353.043226ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3095.169101ms)
|
||||
✔ Queue, Business and Settings in their five states, with no move button (6423.190415ms)
|
||||
✔ seeded secrets, Discord ids and paths reach no response and no page; business refusals in the module's words (1676.082647ms)
|
||||
✔ the server log names no config path when the system config refuses (315.908499ms)
|
||||
ℹ tests 61
|
||||
ℹ suites 0
|
||||
ℹ pass 61
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 57617.542224
|
||||
@@ -0,0 +1,4 @@
|
||||
baseline: pass
|
||||
untyped-within-only: SURVIVED
|
||||
untyped-cross-first: SURVIVED
|
||||
untyped-keeps-typed: killed (✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker;)
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ the PM gets launch, its task verbs and the reads (10.044136ms)
|
||||
✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (1.962409ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (1.619424ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (1.332889ms)
|
||||
✔ an action outside the instance's authority has no tool (2.391639ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (13.290146ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 159.894616
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r79-out/mutants-base/orig 2026-10-11 19:11:33.793887167 -0500
|
||||
+++ packages/harness/src/tools.mjs 2026-10-11 19:11:34.345734068 -0500
|
||||
@@ -121,7 +121,7 @@
|
||||
// reviewer sees what the session can't do through the bus.
|
||||
export function untypedActions(resolved, tools) {
|
||||
const typed = new Set(tools.map((t) => t.action).filter(Boolean));
|
||||
- return [...resolved.limits.authority.withinRole, ...resolved.limits.authority.crossRole].filter((a) => !typed.has(a));
|
||||
+ return [...resolved.limits.authority.crossRole, ...resolved.limits.authority.withinRole].filter((a) => !typed.has(a));
|
||||
}
|
||||
|
||||
// One call over a tool socket: a JSON line out, a JSON line back.
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ the PM gets launch, its task verbs and the reads (6.472822ms)
|
||||
✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (1.843678ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (1.448665ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (1.203643ms)
|
||||
✔ an action outside the instance's authority has no tool (1.33157ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (7.099107ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 98.65402
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r79-out/mutants-base/orig 2026-10-11 19:11:33.793887167 -0500
|
||||
+++ packages/harness/src/tools.mjs 2026-10-11 19:11:34.479333187 -0500
|
||||
@@ -121,7 +121,7 @@
|
||||
// reviewer sees what the session can't do through the bus.
|
||||
export function untypedActions(resolved, tools) {
|
||||
const typed = new Set(tools.map((t) => t.action).filter(Boolean));
|
||||
- return [...resolved.limits.authority.withinRole, ...resolved.limits.authority.crossRole].filter((a) => !typed.has(a));
|
||||
+ return [...resolved.limits.authority.withinRole, ...resolved.limits.authority.crossRole].filter((a) => a === "message.send" || !typed.has(a));
|
||||
}
|
||||
|
||||
// One call over a tool socket: a JSON line out, a JSON line back.
|
||||
@@ -0,0 +1,37 @@
|
||||
✔ the PM gets launch, its task verbs and the reads (5.385225ms)
|
||||
✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker (4.821045ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (2.066035ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (1.073711ms)
|
||||
✔ an action outside the instance's authority has no tool (1.201315ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (6.900094ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 5
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 101.208053
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/harness/tests/tools.test.mjs:28:1
|
||||
✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker (4.821045ms)
|
||||
AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:
|
||||
|
||||
assert.ok(!untyped.includes("message.send"))
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r79-base/packages/harness/tests/tools.test.mjs:35: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: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: false,
|
||||
expected: true,
|
||||
operator: '==',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r79-out/mutants-base/orig 2026-10-11 19:11:33.793887167 -0500
|
||||
+++ packages/harness/src/tools.mjs 2026-10-11 19:11:34.192166778 -0500
|
||||
@@ -121,7 +121,7 @@
|
||||
// reviewer sees what the session can't do through the bus.
|
||||
export function untypedActions(resolved, tools) {
|
||||
const typed = new Set(tools.map((t) => t.action).filter(Boolean));
|
||||
- return [...resolved.limits.authority.withinRole, ...resolved.limits.authority.crossRole].filter((a) => !typed.has(a));
|
||||
+ return [...resolved.limits.authority.withinRole].filter((a) => !typed.has(a));
|
||||
}
|
||||
|
||||
// One call over a tool socket: a JSON line out, a JSON line back.
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ the PM gets launch, its task verbs and the reads (6.602662ms)
|
||||
✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (1.908252ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (1.525703ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (1.28065ms)
|
||||
✔ an action outside the instance's authority has no tool (1.946547ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (7.213912ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 115.265537
|
||||
@@ -0,0 +1,4 @@
|
||||
baseline: pass
|
||||
untyped-within-only: killed (✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker;)
|
||||
untyped-cross-first: killed (✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker;)
|
||||
untyped-keeps-typed: killed (✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker;)
|
||||
@@ -0,0 +1,14 @@
|
||||
✔ the PM gets launch, its task verbs and the reads (5.523497ms)
|
||||
✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (1.637037ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (1.348486ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (1.1546ms)
|
||||
✔ an action outside the instance's authority has no tool (1.742125ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (6.472016ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 100.186671
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r79-out/mutants-candidate/orig 2026-10-11 19:09:57.945649851 -0500
|
||||
+++ packages/harness/src/tools.mjs 2026-10-11 19:11:28.721544686 -0500
|
||||
@@ -121,7 +121,7 @@
|
||||
// reviewer sees what the session can't do through the bus.
|
||||
export function untypedActions(resolved, tools) {
|
||||
const typed = new Set(tools.map((t) => t.action).filter(Boolean));
|
||||
- return [...resolved.limits.authority.withinRole, ...resolved.limits.authority.crossRole].filter((a) => !typed.has(a));
|
||||
+ return [...resolved.limits.authority.crossRole, ...resolved.limits.authority.withinRole].filter((a) => !typed.has(a));
|
||||
}
|
||||
|
||||
// One call over a tool socket: a JSON line out, a JSON line back.
|
||||
@@ -0,0 +1,44 @@
|
||||
✔ the PM gets launch, its task verbs and the reads (6.25404ms)
|
||||
✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.106602ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (1.578228ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (1.444234ms)
|
||||
✔ an action outside the instance's authority has no tool (1.447951ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (8.17316ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 5
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 96.690506
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/harness/tests/tools.test.mjs:28:1
|
||||
✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.106602ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
+ 'task.scope.change',
|
||||
'task.update.assigned',
|
||||
'git.push.working',
|
||||
'review.request',
|
||||
- 'task.scope.change'
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r79/packages/harness/tests/tools.test.mjs:33: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: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ 'task.scope.change', 'task.update.assigned', 'git.push.working', 'review.request' ],
|
||||
expected: [ 'task.update.assigned', 'git.push.working', 'review.request', 'task.scope.change' ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r79-out/mutants-candidate/orig 2026-10-11 19:09:57.945649851 -0500
|
||||
+++ packages/harness/src/tools.mjs 2026-10-11 19:11:28.858132329 -0500
|
||||
@@ -121,7 +121,7 @@
|
||||
// reviewer sees what the session can't do through the bus.
|
||||
export function untypedActions(resolved, tools) {
|
||||
const typed = new Set(tools.map((t) => t.action).filter(Boolean));
|
||||
- return [...resolved.limits.authority.withinRole, ...resolved.limits.authority.crossRole].filter((a) => !typed.has(a));
|
||||
+ return [...resolved.limits.authority.withinRole, ...resolved.limits.authority.crossRole].filter((a) => a === "message.send" || !typed.has(a));
|
||||
}
|
||||
|
||||
// One call over a tool socket: a JSON line out, a JSON line back.
|
||||
@@ -0,0 +1,44 @@
|
||||
✔ the PM gets launch, its task verbs and the reads (6.764249ms)
|
||||
✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.248644ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (1.600479ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (1.246387ms)
|
||||
✔ an action outside the instance's authority has no tool (2.019065ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (9.68713ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 5
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 99.535652
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/harness/tests/tools.test.mjs:28:1
|
||||
✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.248644ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
'task.update.assigned',
|
||||
'git.push.working',
|
||||
'review.request',
|
||||
+ 'message.send',
|
||||
'task.scope.change'
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r79/packages/harness/tests/tools.test.mjs:33: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: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ 'task.update.assigned', 'git.push.working', 'review.request', 'message.send', 'task.scope.change' ],
|
||||
expected: [ 'task.update.assigned', 'git.push.working', 'review.request', 'task.scope.change' ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
--- /mnt/storage/scratch/rocko-r79-out/mutants-candidate/orig 2026-10-11 19:09:57.945649851 -0500
|
||||
+++ packages/harness/src/tools.mjs 2026-10-11 19:11:28.572760580 -0500
|
||||
@@ -121,7 +121,7 @@
|
||||
// reviewer sees what the session can't do through the bus.
|
||||
export function untypedActions(resolved, tools) {
|
||||
const typed = new Set(tools.map((t) => t.action).filter(Boolean));
|
||||
- return [...resolved.limits.authority.withinRole, ...resolved.limits.authority.crossRole].filter((a) => !typed.has(a));
|
||||
+ return [...resolved.limits.authority.withinRole].filter((a) => !typed.has(a));
|
||||
}
|
||||
|
||||
// One call over a tool socket: a JSON line out, a JSON line back.
|
||||
@@ -0,0 +1,43 @@
|
||||
✔ the PM gets launch, its task verbs and the reads (8.08255ms)
|
||||
✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.40499ms)
|
||||
✔ a coder with a tracker gets its own task tools and no task_reassign (2.046596ms)
|
||||
✔ launch only when the business's launch block names the instance as launcher (2.97995ms)
|
||||
✔ an action outside the instance's authority has no tool (2.252279ms)
|
||||
✔ callTool: one JSON line out, the result back, a refusal rejects (7.573715ms)
|
||||
ℹ tests 6
|
||||
ℹ suites 0
|
||||
ℹ pass 5
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 102.78462
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at packages/harness/tests/tools.test.mjs:28:1
|
||||
✖ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.40499ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
[
|
||||
'task.update.assigned',
|
||||
'git.push.working',
|
||||
'review.request',
|
||||
- 'task.scope.change'
|
||||
]
|
||||
|
||||
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r79/packages/harness/tests/tools.test.mjs:33: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: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: [ 'task.update.assigned', 'git.push.working', 'review.request' ],
|
||||
expected: [ 'task.update.assigned', 'git.push.working', 'review.request', 'task.scope.change' ],
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
070278515150bb6cc4d1416f6e808ced34578ae243d032afc1b55ed428e527e0 ./base.txt
|
||||
a44d40d7aec057133a5d14eb899beddfad1341d3650f1dcac95fabcab2e96934 ./BUILD.md
|
||||
cba84c0edd4a4bd68f14e38c01769b741350e7ef5681b0900bd88a623ddb0161 ./build.patch
|
||||
16b12387dce8d21f5cc5311b9fc44e9692867b983c4f561f779610cc61e2b349 ./candidate-manifest.sha256
|
||||
68ab78bcfe2c2b1fdb1479f9f5aa5d1b27e16c2ceb6250084551bcff6a949f62 ./files.txt
|
||||
8c9b45ad7bad35832a6a7f101fb1b21b07f8f95dbbc33216eab4bfc98fc5fc8c ./mutants.sh
|
||||
4f668f8a220655eda444098e0aacaffe68b8e33304df98dfce724fe9a7b76dc5 ./out/gate/business.log
|
||||
79a3edff56a713c3989cb43846428ccf7d4d40d157ee4acd133d816b91b1c20d ./out/gate/bus.log
|
||||
ebcc91d05da88b1f6178503a8a244f0da3d5544da344b2a5a12b81b789aa3342 ./out/gate/cli.log
|
||||
5fbaf122c036a63d349b4137e2c7c0e88c668bb6ef518ef6357a0fe1aaf03d48 ./out/gate/end.txt
|
||||
e880e20e57393d40d7e7697a541df7de93a439688e4f4e139ede6b7a426a34ef ./out/gate/harness.log
|
||||
794ee0814a5e314384cf8cba2940c84f77220a2f08f148d3b6c135529e70437a ./out/gate/seat.log
|
||||
df7a2c8caae9fe29a9566ad02bc23a2c36b6c78e1611a95eee958f87b8e110c1 ./out/gate.sh
|
||||
a5e915127f378b075116c36d763012c7f9beea17d1b2ab5c993ba184771bb95d ./out/gate/start.txt
|
||||
0f08d010f732aafa6656154dc09ef683463c1ed9135fa3b8b2861bbc4c2a9424 ./out/gate/summary.txt
|
||||
6fbb557e6bc8d88cb8222a7a76921ea23ecf37db2a69c41d366e794ca24dc2fc ./out/gate/tasks.log
|
||||
f91fc95a173339137f981e24fbf630acfde957e32c3cd71e28304532083c6a77 ./out/gate/test-auth.log
|
||||
5602eb82548d44107a464e3dcae6a61c5d5ab54809ba4ee258409d1ceee7d328 ./out/gate/test-conductor.log
|
||||
52d211444489ea729dafc3c9745d4474d9dfd50f41055cbad792424197f04073 ./out/gate/test-config.log
|
||||
7d5016ded1994048642f8b9ae845e52e8af4a069ba05c056c8f580a4589bacbe ./out/gate/test-discord.log
|
||||
61b744b7816bfb0866db902ca66c63df6822dbcb63d494c473542ab9c9a03b97 ./out/gate/test-extension-package.log
|
||||
83dfaa21c4e4ad941088efab3f69e87ebd2f6bd3cc72ede938e21dc06da8a34f ./out/gate/test-foundation.log
|
||||
4aa6fdaca560f89c2e381fc3985bb0ef06c5f10ecf14fb0d15995adc9c9bb4fb ./out/gate/test-queue.log
|
||||
fa832794ee35025fb4559d58d01a270f6bff2eb65e863e9075b797f47fa68545 ./out/gate/test-release.log
|
||||
ccea37f4ffde1f160dcd1a1864988083a645d974e892065c956b338d0f8c853a ./out/gate/test-task.log
|
||||
174c97c13cf2e4ed4d47a6e4c1a65987e895539372b6f9da0328f15aeda05332 ./out/gate/webui.log
|
||||
2507d82f25fce27ba9d1853a39326c8fa3dda848e35bafeba3773806635bf41f ./out/mutants-base/baseline.log
|
||||
c314ad8ec1d673ebf70372de6bbf93dd0f920bb448602f37d5f50527eb1038ce ./out/mutants-base.txt
|
||||
89e648149944738c3873c1f23967dffe2202aaca8d91acb5b1fb86a7431ea37a ./out/mutants-base/untyped-cross-first.diff
|
||||
6b9b49eb6e5b8967a9ba6c64fde86ecb3140e5bcc7ca0e46b4d3a22858c184ab ./out/mutants-base/untyped-cross-first.log
|
||||
c7bea34ca07af7652f8817865e2a68a62b4e07b4618019e9a2856fefb48c5485 ./out/mutants-base/untyped-keeps-typed.diff
|
||||
75b9d5da4a0c5fcb28251554be4e6965d82af14382c3808b586842ca103d7f45 ./out/mutants-base/untyped-keeps-typed.log
|
||||
1a368c7c832872a1c2b4de7a87ec3b4245fa105f42348ba18c76973929b9c450 ./out/mutants-base/untyped-within-only.diff
|
||||
3415c13f10a65af6160242ca9b7a96c02be391f3281c3f38b8cb7d1483f1b8af ./out/mutants-base/untyped-within-only.log
|
||||
9dec5efbee09b790ee7f0980cbc98a2789f5c6b827caf577a4f6566a157cac62 ./out/mutants-candidate/baseline.log
|
||||
d6d54bda35e8ced325b0246140e4c73f85cef2e747987aa6278c205292d736b3 ./out/mutants-candidate.txt
|
||||
3f97fc76c99fafe1bff7ca5c1b8335f7566fdfa28da103624c7b6af1dbddf9eb ./out/mutants-candidate/untyped-cross-first.diff
|
||||
680b8e468ddeb66e43986cb8f4d348af65422aa03b59cb72b37e0c855c34e7e1 ./out/mutants-candidate/untyped-cross-first.log
|
||||
7b70ac3bc815706016c095145e147feb716558fc45ddd915e56a0e79084bb5fd ./out/mutants-candidate/untyped-keeps-typed.diff
|
||||
ee5e0c3d27f71af3793fd23329f61556e3374d1fa5d78e86e25a5c14318f1dba ./out/mutants-candidate/untyped-keeps-typed.log
|
||||
bfe8ea1345a8fb488607f490e3d2504945cd7fbb9e9175f90fd7261a7ef5e648 ./out/mutants-candidate/untyped-within-only.diff
|
||||
19d5b967f342ad4e8a9015ed36351194736e1b944631c7270784d8048729a8da ./out/mutants-candidate/untyped-within-only.log
|
||||
Reference in New Issue
Block a user