diff --git a/BUILD-LOG.md b/BUILD-LOG.md index b281ea8c9..64bffa95a 100644 --- a/BUILD-LOG.md +++ b/BUILD-LOG.md @@ -4256,3 +4256,11 @@ Before (a0080da8): no test covered a directory pin, a symlink default or a pin w After (candidate, uncommitted packet agents/rocko/work/queue-72/, candidate manifest e6531a53): one test in host.test.mjs, one in claude-session.test.mjs, and mutants.sh. All six mutants are killed on the candidate and all six survive on the base. Deviation from the brief: a directory named claude on PATH can't reach the default pin, because bash's command -v skips directories. The test asserts the real behaviour: no pin, with exit 0. No change to bus-service.sh or adapter.sh. Gate (Rocko, scratch worktree a0080da8 plus the candidate, sequential): cli 113/113, harness 58/58 with 0 skipped; test-auth 15, test-conductor 17, test-config 24, test-discord 66, test-extension-package 18, test-foundation 44, test-queue 27, test-release 14, test-task 98, all with 0 failed (Docker). Removed the rocko-r72_default network. No commits, no pushes, no tokens read. + +### 2026-10-11 — Rocko, row 73 round 1 candidate: drop the coder's task.reassign grant (#1567) + +Before (324c064b): `roles/coder.json` grants `crossRole: ["task.reassign", "task.scope.change"]`. The broker classes a coder's `task.reassign` as cross-role and routes its decision to pm, and a coder with a tracker gets a `task_reassign` tool. Yet the task verb refuses every non-pm `task.reassign` with `field-writer` before authority is checked (lead decision 90), so the grant can never succeed. The mutant `broker-unlisted-cross` (an unlisted action becomes cross-role) survives the base tests. + +After (candidate, uncommitted packet agents/rocko/work/queue-73/, candidate manifest bf4e5ed6, packet manifest 41ffcd5c, 53 files): the coder's `crossRole` is `["task.scope.change"]`. Its `task.reassign` is gated and routes to the human, and it gets no `task_reassign` tool. New or changed tests are in business role and resolve, bus broker (a test built on the shipped roles), harness tools and tasks verbs, and the `world.mjs` fixture now matches the shipped role. The narrowing test moved from the coder to the pm, because with one cross-role action left the old test passes under `resolve-cross-unnarrowed`. All 5 mutants are killed on the candidate. No change to broker.mjs or PM_VERBS. Not changed, named in BUILD.md for Sage: `packages/business/README.md` line 37, `packages/tasks/README.md` lines 193-196 and `packages/tasks/live/run.mjs` line 32 still show the old grant. + +Gate (Rocko, scratch worktree 324c064b plus the candidate, sequential, 23:09:50Z-23:14:34Z): tasks 71, bus 81, business 60, harness 58 (0 skipped), cli 112, webui 50, seat 27 node tests; test-auth 15, test-conductor 17, test-config 24, test-discord 66, test-extension-package 18, test-foundation 44, test-queue 27, test-release 14, test-task 98, all 0 failed (Docker). Removed the rocko-r73_default network. Queue revs 533-534; the request failed without a credential, as expected. No commits, no pushes, no tokens read. diff --git a/agents/rocko/work/queue-73/BUILD.md b/agents/rocko/work/queue-73/BUILD.md new file mode 100644 index 000000000..6330dc86d --- /dev/null +++ b/agents/rocko/work/queue-73/BUILD.md @@ -0,0 +1,140 @@ +# Row 73 (#1567): drop the coder's task.reassign grant, candidate packet, round 1 + +Author: Rocko. Reviewer: Dewey. Brief: +`docs/plans/2026-10-11_claude-pin-and-coder-grant.md`, section "Coder role: +drop the task.reassign grant the broker always refuses". Base: `324c064b` +(`base.txt`). At 23:16Z the checkout HEAD `f6b9ea4e` has no change since the +base to any candidate path or to `packages/{bus,business,tasks}/src` or +`packages/harness/src/tools.mjs`. `build.patch` applies to it cleanly. 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 | +|---|---| +| `roles/coder.json` | `crossRole`: `["task.reassign", "task.scope.change"]` → `["task.scope.change"]`. Nothing else in the file changes. | +| `packages/business/tests/role.test.mjs` | "shipped authority follows the note's table": asserts that the coder's `crossRole` is exactly `["task.scope.change"]` | +| `packages/business/tests/resolve.test.mjs` | "classify": the coder's `task.reassign` is now `gated` and its `task.scope.change` is `cross`. "limits.authority narrows cross-role actions too" moves from the coder to the pm (see below). | +| `packages/bus/tests/broker.test.mjs` | +1 test built on the shipped role files: "the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role" | +| `packages/harness/tests/tools.test.mjs` | +1 test: "a coder with a tracker gets its own task tools and no task_reassign" | +| `packages/tasks/tests/world.mjs` | the fixture's coder `crossRole` now matches the shipped role | +| `packages/tasks/tests/verbs.test.mjs` | in "assign and reassign …": a coder's `task.reassign` refuses `field-writer` and records no `action.allowed` | +| `agents/rocko/work/queue-73/mutants.sh` | the mutant rerun: `mutants.sh ` | + +No change to `broker.mjs`, `PM_VERBS`, the slice 1 field table or any other +role's grants. + +### Why the narrowing test moved to the pm + +Before this change, the test limited the coder to `task.scope.change` and +watched `task.reassign` drop out of `crossRole`. With one cross-role action +left, that limit drops nothing from `crossRole`. I checked this: with the new +role file and the old test, the mutant `resolve-cross-unnarrowed` (crossRole +ignores `limits.authority`) passes the test (`out/old-narrow-test-under-mutant.txt`). +The pm still holds two cross-role actions. The test now limits the pm to +`task.create`, `task.close` and `task.priority.change`. It checks that +`crossRole` keeps `task.priority.change` and drops `task.scope.change`, and +that `withinRole` narrows too. + +## Every place that read the old grant, and what it says now + +Probe (`out/probe-base.txt`, `out/probe-candidate.txt`): the shipped roles +through `validateBusinessDocument`, `resolveInstance`, `busBusiness` and a +real `Broker`, as `bootConfig` assembles them. + +| Reader | Before (base) | After (candidate) | +|---|---|---| +| `business/src/resolve.mjs` `resolveInstance` | coder `crossRole` `[task.reassign, task.scope.change]` | `[task.scope.change]`. The resolved digest of every coder instance changes too. Only the bundle manifest records it, and nothing compares it. | +| `business/src/resolve.mjs` `classify` | `cross` | `gated` | +| `bus/src/broker.mjs` `#classification` (via `cli/src/config.mjs` `bootConfig` → `busBusiness`) | `cross-role`; `decision.raise` routes to the domain arbiter, `pm` by default (`cto` for technical) | `gated`; routes to `human` | +| `harness/src/tools.mjs` `typedTools`, with a tracker | the coder gets a `task_reassign` tool | no `task_reassign` tool; `task_scope_change` and `task_update_assigned` remain | +| `harness/src/tools.mjs` `untypedActions` → `bundle.mjs` prompt, without a tracker | the prompt lists `task.reassign` among "Actions you hold that have no bus tool yet" | not listed | +| `tasks/src/verbs.mjs` `PM_VERBS` | `field-writer` before authority | unchanged: `field-writer` before authority | +| `tasks/tests/world.mjs` fixture | copied the old grant | matches the shipped role | +| business, bus, harness and tasks tests | see Files | see Files | + +Readers I did not change (outside the brief's files; Sage's call): + +- `packages/business/README.md`, lines 30-43: the version 2 example is the + shipped coder file and still shows `"crossRole": ["task.reassign", + "task.scope.change"]`. It goes stale with this change. Suggested fix: drop + `"task.reassign", ` from the example. +- `packages/tasks/README.md`, lines 193-196: "A coder role's `crossRole` + grant of `task.reassign` can't be used. The writer check refuses it before + authority is looked at. …" This will be stale too. Suggested text: "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." +- `packages/tasks/live/run.mjs`, line 32: the live run's own copy of the + slice 1 authority still gives the coder `task.reassign`. Nothing runs it in + the suites. It never has the coder call `task.reassign`, so its result + doesn't change. It should match `world.mjs`. +- Unaffected: `scripts/test-task.sh` line 279 and + `business/tests/role.test.mjs` line 115 are role-validation fixtures, not + the coder's grant. Historical notes are left as they are: the slice 1 + plan, the Darkwing and Filbert work notes, and lead decision 90. + +## What a coder's task.reassign does end to end after the change + +1. A pi coder session has no `task_reassign` tool, so it can't make the + call through the harness. +2. It can still `raise_decision` with `action: task.reassign`, because the + tool's action enum is every action. The broker classes it `gated` and + routes it to the human, where before it went to the pm as cross-role. The + human is then asked a question that can only end in `field-writer`. +3. If the human approves and the coder calls the verb directly on the bus, + the broker's `authorize` passes as `gated`; the bus test shows that. The + task verbs refuse first with `field-writer`, before `authorize`, so nothing + is consumed and nothing is written (tasks test). + +The brief names the follow-up but doesn't make it, and nor does this row. To +refuse a non-pm `task.reassign` (or any `PM_VERBS` action) at +`decision.raise`, before a decision opens, is a broker change and would be +its own row. + +A bus that is already running keeps the authority it loaded at boot. The +change reaches it on its next restart. + +## Mutants (`out/mutants-candidate.txt`, `out/mutants-base.txt`) + +| Mutant | Edit | Base `324c064b` | Candidate | +|---|---|---|---| +| `role-keeps-reassign` | `roles/coder.json` puts `task.reassign` back | n/a (the base is this mutant) | killed by role, classify, bus and harness tests | +| `broker-unlisted-cross` | `#classification`: an action in neither list → `cross-role` | **survived** | killed by the new bus test | +| `resolve-cross-unnarrowed` | `resolveInstance`: `crossRole` ignores `limits.authority` | killed | killed (by the narrowing test and the harness test "an action outside the instance's authority has no tool") | +| `classify-unlisted-cross` | `classify`: an unlisted action → `cross` | killed | killed | +| `tools-all-task-verbs` | `typedTools`: a task tool for every verb, held or not | killed | killed (now also by the new harness test) | + +The script saves each file, applies the sed and checks it changed something. +It then runs the five test files and restores the file from the saved copy, +so it works on an uncommitted tree. `out/mutants-*/` holds each diff and log. +I ran the candidate twice. The run recorded here uses the final script; the +first run used the same script before a comment-only reflow, with the same +results. + +## Gate (`out/gate/`, sequential, scratch worktree at 324c064b with the candidate, `node_modules` linked, 23:09:50Z-23:14:34Z) + +| Suite | Result | +|---|---| +| tasks `node --test 'packages/tasks/tests/*.test.mjs'` | 71 pass, 0 fail | +| bus | 81 pass, 0 fail | +| business | 60 pass, 0 fail | +| harness | 58 pass, 0 fail, 0 skipped | +| cli | 112 pass, 0 fail | +| webui | 50 pass, 0 fail | +| seat | 27 pass, 0 fail | +| 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) | + +cli, webui and seat go beyond the gate the brief names. I ran them because +they read the shipped roles. After the gate I removed the `rocko-r73_default` +network. diff --git a/agents/rocko/work/queue-73/base.txt b/agents/rocko/work/queue-73/base.txt new file mode 100644 index 000000000..0faf48a68 --- /dev/null +++ b/agents/rocko/work/queue-73/base.txt @@ -0,0 +1 @@ +324c064b2a9290ff6c17449c3fa0725aa7a09494 diff --git a/agents/rocko/work/queue-73/build.patch b/agents/rocko/work/queue-73/build.patch new file mode 100644 index 000000000..e0e721f37 --- /dev/null +++ b/agents/rocko/work/queue-73/build.patch @@ -0,0 +1,210 @@ +diff --git a/agents/rocko/work/queue-73/mutants.sh b/agents/rocko/work/queue-73/mutants.sh +new file mode 100755 +index 00000000..8d550d1f +--- /dev/null ++++ b/agents/rocko/work/queue-73/mutants.sh +@@ -0,0 +1,56 @@ ++#!/usr/bin/env bash ++# Row 73 (#1567): rerun the role-file revert and the mutants against a tree ++# with the candidate. Usage: mutants.sh . Each mutant edits one line, ++# runs the row's tests, 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 its file, or the unmutated run fails. ++# The tasks test is in the list but kills nothing here: the verb refuses a ++# coder's task.reassign with or without the grant. ++set -euo pipefail ++TREE="$(cd "${1:?usage: mutants.sh }" && pwd)" ++cd "$TREE" ++ROLE=roles/coder.json ++BROKER=packages/bus/src/broker.mjs ++RESOLVE=packages/business/src/resolve.mjs ++TOOLS=packages/harness/src/tools.mjs ++TESTS=( ++ packages/bus/tests/broker.test.mjs ++ packages/business/tests/role.test.mjs ++ packages/business/tests/resolve.test.mjs ++ packages/harness/tests/tools.test.mjs ++ packages/tasks/tests/verbs.test.mjs ++) ++run_tests() { node --test "${TESTS[@]}" >"$1" 2>&1; } ++ ++# name | file | sed expression ++MUTANTS=( ++ 'role-keeps-reassign|'"$ROLE"'|s/"crossRole": \["task.scope.change"\]/"crossRole": ["task.reassign", "task.scope.change"]/' ++ 'broker-unlisted-cross|'"$BROKER"'|/^ ? .cross-role.$/{n;s/^ : .gated.;$/ : '"'"'cross-role'"'"';/}' ++ 'resolve-cross-unnarrowed|'"$RESOLVE"'|s/^ crossRole = crossRole.filter((a) => vars\["limits.authority"\].includes(a));$/ crossRole = [...crossRole];/' ++ 'classify-unlisted-cross|'"$RESOLVE"'|/^ if (resolved.limits.authority.crossRole.includes(action)) return "cross";$/{n;s/return "gated";/return "cross";/}' ++ 'tools-all-task-verbs|'"$TOOLS"'|s/^ if (held.has(action)) add(name, action, action, description, obj(properties, required));$/ add(name, action, action, description, obj(properties, required));/' ++) ++ ++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 file expr <<<"$m" ++ cp -p "$file" "$OUT/orig" ++ sed -i -e "$expr" "$file" ++ if cmp -s "$OUT/orig" "$file"; then ++ echo "$name: NOT APPLIED (sed matched nothing)"; status=1; continue ++ fi ++ diff -u "$OUT/orig" "$file" >"$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" "$file" ++ cmp -s "$OUT/orig" "$file" || { echo "restore failed: $file" >&2; exit 1; } ++ rm -f "$OUT/orig" ++done ++exit "$status" +diff --git a/packages/bus/tests/broker.test.mjs b/packages/bus/tests/broker.test.mjs +index 3e908d70..d5d53d9e 100644 +--- a/packages/bus/tests/broker.test.mjs ++++ b/packages/bus/tests/broker.test.mjs +@@ -4,6 +4,9 @@ import { mkdtempSync, rmSync } from 'node:fs'; + import { tmpdir } from 'node:os'; + import { join } from 'node:path'; + import { Store } from '../src/store.mjs'; ++import { busBusiness } from '../src/business.mjs'; ++import { resolveInstance, validateBusinessDocument } from '../../business/src/index.mjs'; ++import { businessDoc, REPO_ROLES, systemFor } from '../../business/tests/helpers.mjs'; + const { Broker } = await import('../src/broker.mjs').catch((e) => { + if (e.code === 'ERR_MODULE_NOT_FOUND') return {}; + throw e; +@@ -354,3 +357,26 @@ test('both arbiters require human resolution when their cross-role route is them + assert.equal(b.authorize(cap, action, { decision: d.id, target: 'vikunja:3/41' }).class, 'cross-role'); + } + }); ++ ++test('the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role', (t) => { ++ const root = mkdtempSync(join(tmpdir(), 'bus-roles-')); ++ t.after(() => rmSync(root, { recursive: true, force: true })); ++ const business = validateBusinessDocument(businessDoc(root, 'demo'), join(root, 'businesses', 'demo.json'), { ++ rolesDir: REPO_ROLES, ++ }); ++ const resolved = {}; ++ for (const instance of Object.keys(business.roles)) ++ resolved[instance] = resolveInstance({ system: systemFor(root), business, instance }); ++ const { b, agent, human } = setup(t, { demo: busBusiness(business, resolved) }); ++ const c = agent('coder'); ++ call(b, c, 'role.claim'); ++ const reassign = raise(b, c, 'task.reassign', { target: 'vikunja:3/7' }); ++ assert.equal(reassign.class, 'gated'); ++ assert.equal(reassign.route_to, 'human'); ++ const scope = raise(b, c, 'task.scope.change', { domain: 'technical', target: 'vikunja:3/7' }); ++ assert.equal(scope.class, 'cross-role'); ++ assert.equal(scope.route_to, 'cto'); ++ // Approval passes the broker; the task verb still refuses a coder with field-writer (packages/tasks). ++ call(b, human, 'decision.resolve', { id: reassign.id, choice: 'yes' }); ++ assert.equal(b.authorize(c, 'task.reassign', { decision: reassign.id, target: 'vikunja:3/7' }).class, 'gated'); ++}); +diff --git a/packages/business/tests/resolve.test.mjs b/packages/business/tests/resolve.test.mjs +index 0995eb5c..75ac2925 100644 +--- a/packages/business/tests/resolve.test.mjs ++++ b/packages/business/tests/resolve.test.mjs +@@ -122,21 +122,23 @@ test("limits.authority without role.launch leaves the launcher with no launch bl + }); + + test("limits.authority narrows cross-role actions too", () => { ++ // pm, the role with two cross-role actions: the limit keeps one and drops the other. + const s = setup((d) => { +- d.roles.coder.vars["limits.authority"] = ["task.update.assigned", "git.push.working", "task.scope.change"]; ++ d.roles.pm.vars["limits.authority"] = ["task.create", "task.close", "task.priority.change"]; + }); +- const coder = resolve(s, "coder"); +- assert.deepEqual(coder.limits.authority, { withinRole: ["task.update.assigned", "git.push.working"], crossRole: ["task.scope.change"] }); +- assert.equal(classify(coder, "task.reassign"), "gated"); +- assert.equal(classify(coder, "task.scope.change"), "cross"); +- assert.equal(classify(coder, "review.request"), "gated"); ++ const pm = resolve(s, "pm"); ++ assert.deepEqual(pm.limits.authority, { withinRole: ["task.create", "task.close"], crossRole: ["task.priority.change"] }); ++ assert.equal(classify(pm, "task.priority.change"), "cross"); ++ assert.equal(classify(pm, "task.scope.change"), "gated"); ++ assert.equal(classify(pm, "task.assign"), "gated"); + }); + + test("classify", () => { + const s = setup(); + const coder = resolve(s, "coder"); + assert.equal(classify(coder, "git.push.working"), "within"); +- assert.equal(classify(coder, "task.reassign"), "cross"); ++ assert.equal(classify(coder, "task.scope.change"), "cross"); ++ assert.equal(classify(coder, "task.reassign"), "gated"); + assert.equal(classify(coder, "task.close"), "gated"); + assert.equal(classify(coder, "deploy"), "gated"); + assert.equal(classify(resolve(s, "pm"), "task.priority.change"), "cross"); +diff --git a/packages/business/tests/role.test.mjs b/packages/business/tests/role.test.mjs +index 1a401307..00628f80 100644 +--- a/packages/business/tests/role.test.mjs ++++ b/packages/business/tests/role.test.mjs +@@ -61,6 +61,8 @@ test("shipped role scopes match addendum B section 2 and the SR runbook", () => + test("shipped authority follows the note's table", () => { + const auth = (name) => loadRole(REPO_ROLES, name).authority; + assert.ok(auth("coder").withinRole.includes("git.push.working")); ++ // Assignee is pm-only (decision 90): a coder grant of task.reassign could never succeed. ++ assert.deepEqual(auth("coder").crossRole, ["task.scope.change"]); + assert.ok(!auth("reviewer").withinRole.includes("git.push.working")); + assert.deepEqual(auth("reviewer").crossRole, []); + assert.ok(auth("pm").withinRole.includes("role.launch")); +diff --git a/packages/harness/tests/tools.test.mjs b/packages/harness/tests/tools.test.mjs +index b520dd4c..31606131 100644 +--- a/packages/harness/tests/tools.test.mjs ++++ b/packages/harness/tests/tools.test.mjs +@@ -35,6 +35,14 @@ test("a coder gets no launch, no resolve_decision, and no task tools without a t + assert.ok(!untyped.includes("message.send")); + }); + ++test("a coder with a tracker gets its own task tools and no task_reassign", (t) => { ++ const coder = resolvedFor(t, "coder"); ++ assert.deepEqual(names(typedTools({ resolved: coder, tracker: true })), [ ++ "send_message", "task_scope_change", "task_update_assigned", ++ "raise_decision", "list_agents", "inbox", "trail", "list_tasks", ++ ]); ++}); ++ + test("launch only when the business's launch block names the instance as launcher", (t) => { + const pm = resolvedFor(t, "pm", (d) => delete d.launch); + assert.equal(pm.launch, null); +diff --git a/packages/tasks/tests/verbs.test.mjs b/packages/tasks/tests/verbs.test.mjs +index f5621f7b..c9ea98a6 100644 +--- a/packages/tasks/tests/verbs.test.mjs ++++ b/packages/tasks/tests/verbs.test.mjs +@@ -93,6 +93,9 @@ test('assign and reassign move the role bots and record task.assigned', async (t + // The field-writer check runs before authority, so the refused call consumes nothing. + await assert.rejects(w.call(coder, 'task.assign', { task_ref, role: 'coder' }), refusedWith('field-writer')); + assert.equal(allowed(w, 'task.assign').length, 0); ++ // Assignee stays pm-only (decision 90); the coder role holds no task.reassign grant, and the verb refuses it anyway. ++ await assert.rejects(w.call(coder, 'task.reassign', { task_ref, role: 'reviewer' }), refusedWith('field-writer')); ++ assert.equal(allowed(w, 'task.reassign').length, 0); + await assert.rejects(w.call(pm, 'task.assign', { task_ref, role: 'cto' }), refusedWith('unknown-role')); + await assert.rejects(w.call(pm, 'task.assign', { task_ref, role: 'toString' }), refusedWith('unknown-role')); + await assert.rejects(w.call(pm, 'task.reassign', { task_ref, role: 'coder' }), refusedWith('task-unassigned')); +diff --git a/packages/tasks/tests/world.mjs b/packages/tasks/tests/world.mjs +index d50e96ea..5085e779 100644 +--- a/packages/tasks/tests/world.mjs ++++ b/packages/tasks/tests/world.mjs +@@ -42,7 +42,7 @@ export const AUTHORITY = { + }, + coder: { + withinRole: ['task.update.assigned', 'git.push.working', 'review.request', 'message.send'], +- crossRole: ['task.reassign', 'task.scope.change'], ++ crossRole: ['task.scope.change'], + }, + reviewer: { withinRole: ['review.verdict', 'message.send', 'task.update.assigned'], crossRole: [] }, + cto: { +diff --git a/roles/coder.json b/roles/coder.json +index 2a7325a1..04220271 100644 +--- a/roles/coder.json ++++ b/roles/coder.json +@@ -7,7 +7,7 @@ + "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": [ + { diff --git a/agents/rocko/work/queue-73/candidate-manifest.sha256 b/agents/rocko/work/queue-73/candidate-manifest.sha256 new file mode 100644 index 000000000..b8a47a7b5 --- /dev/null +++ b/agents/rocko/work/queue-73/candidate-manifest.sha256 @@ -0,0 +1,8 @@ +e3300acd1f85f7c7c495dc2228ec904c0af992f9ea09693adcf3e5b1121d5f83 agents/rocko/work/queue-73/mutants.sh +6c451be1461b903e2072af0a592b1be33b2e4cf9245e2fa8609ab678d7f39848 packages/business/tests/resolve.test.mjs +17fbdd672e9daca32401b96d8cad0893aaa2ef14db9f3a6f4834e9f8b8f1b50c packages/business/tests/role.test.mjs +bca2e886b021831ada150dfa76be247dbe489072fb249d1a5b63e98582077853 packages/bus/tests/broker.test.mjs +9cd45207694693734207ded38b65c99e59787db74e562668b88a499c4454ed0f packages/harness/tests/tools.test.mjs +5df33892007143de7537ff97059762372c78041ad3bd8be456758d3c51ec984b packages/tasks/tests/verbs.test.mjs +2d1c06d38617d1affd58034f5a5441fe1413b7bc2a2333fedda99c6e26baf2f0 packages/tasks/tests/world.mjs +5b00c49dc1c998156798e0fd9fbe1e1c7e2bb62373dc9f80efaa60902b66b228 roles/coder.json diff --git a/agents/rocko/work/queue-73/files.txt b/agents/rocko/work/queue-73/files.txt new file mode 100644 index 000000000..0b1813aa8 --- /dev/null +++ b/agents/rocko/work/queue-73/files.txt @@ -0,0 +1,8 @@ +agents/rocko/work/queue-73/mutants.sh +packages/business/tests/resolve.test.mjs +packages/business/tests/role.test.mjs +packages/bus/tests/broker.test.mjs +packages/harness/tests/tools.test.mjs +packages/tasks/tests/verbs.test.mjs +packages/tasks/tests/world.mjs +roles/coder.json diff --git a/agents/rocko/work/queue-73/mutants.sh b/agents/rocko/work/queue-73/mutants.sh new file mode 100755 index 000000000..8d550d1fb --- /dev/null +++ b/agents/rocko/work/queue-73/mutants.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# Row 73 (#1567): rerun the role-file revert and the mutants against a tree +# with the candidate. Usage: mutants.sh . Each mutant edits one line, +# runs the row's tests, 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 its file, or the unmutated run fails. +# The tasks test is in the list but kills nothing here: the verb refuses a +# coder's task.reassign with or without the grant. +set -euo pipefail +TREE="$(cd "${1:?usage: mutants.sh }" && pwd)" +cd "$TREE" +ROLE=roles/coder.json +BROKER=packages/bus/src/broker.mjs +RESOLVE=packages/business/src/resolve.mjs +TOOLS=packages/harness/src/tools.mjs +TESTS=( + packages/bus/tests/broker.test.mjs + packages/business/tests/role.test.mjs + packages/business/tests/resolve.test.mjs + packages/harness/tests/tools.test.mjs + packages/tasks/tests/verbs.test.mjs +) +run_tests() { node --test "${TESTS[@]}" >"$1" 2>&1; } + +# name | file | sed expression +MUTANTS=( + 'role-keeps-reassign|'"$ROLE"'|s/"crossRole": \["task.scope.change"\]/"crossRole": ["task.reassign", "task.scope.change"]/' + 'broker-unlisted-cross|'"$BROKER"'|/^ ? .cross-role.$/{n;s/^ : .gated.;$/ : '"'"'cross-role'"'"';/}' + 'resolve-cross-unnarrowed|'"$RESOLVE"'|s/^ crossRole = crossRole.filter((a) => vars\["limits.authority"\].includes(a));$/ crossRole = [...crossRole];/' + 'classify-unlisted-cross|'"$RESOLVE"'|/^ if (resolved.limits.authority.crossRole.includes(action)) return "cross";$/{n;s/return "gated";/return "cross";/}' + 'tools-all-task-verbs|'"$TOOLS"'|s/^ if (held.has(action)) add(name, action, action, description, obj(properties, required));$/ add(name, action, action, description, obj(properties, required));/' +) + +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 file expr <<<"$m" + cp -p "$file" "$OUT/orig" + sed -i -e "$expr" "$file" + if cmp -s "$OUT/orig" "$file"; then + echo "$name: NOT APPLIED (sed matched nothing)"; status=1; continue + fi + diff -u "$OUT/orig" "$file" >"$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" "$file" + cmp -s "$OUT/orig" "$file" || { echo "restore failed: $file" >&2; exit 1; } + rm -f "$OUT/orig" +done +exit "$status" diff --git a/agents/rocko/work/queue-73/out/gate.sh b/agents/rocko/work/queue-73/out/gate.sh new file mode 100755 index 000000000..2d83fd81e --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -u +W=/mnt/storage/scratch/rocko-r73; G=/mnt/storage/scratch/rocko-r73-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 diff --git a/agents/rocko/work/queue-73/out/gate/bus.log b/agents/rocko/work/queue-73/out/gate/bus.log new file mode 100644 index 000000000..727196cce --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/bus.log @@ -0,0 +1,89 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (75.005416ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (46.010344ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (117.296262ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (88.211853ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (45.454ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (40.349948ms) +✔ task action subjects and linked decision trail are complete and ordered (62.71095ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (19.640675ms) +✔ business isolation includes inherited object names and cross-business message references (30.687724ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (35.606534ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (14.931591ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (30.298419ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (23.683738ms) +✔ both arbiters require human resolution when their cross-role route is themselves (37.164098ms) +✔ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (36.167453ms) +✔ S1 adapter takes resolved limits and refs, rejects mismatched instance, never mutates input (22.223275ms) +✔ only validated broker references load; returned data and exceptions cannot expose a known token (6.415097ms) +✔ bad file modes, symlinks, repository/data paths, malformed tokens and missing dates refuse (7.757975ms) +✔ expiry refuses use and env references never become client data (3.599696ms) +✔ S1 parsed service refs work, service mismatch refuses, Gitea rotation due is a warning state (3.510469ms) +✔ opaque tokens shorter than 16 characters refuse before use (0.519448ms) +✔ roles lists open decisions routed to a role, and never the human inbox (62.978066ms) +✔ recent lists closed decisions of every route, newest close first, with how each closed (53.783969ms) +✔ recent stops at RECENT rows (353.1222ms) +✔ every row is what trail already gives the same session for that id (61.037502ms) +✔ a role session can't list decisions, so it can't read another role's open decisions (50.943117ms) +✔ decisions is a read: one business, strict arguments, nothing written (68.290864ms) +✔ endLaunch writes session.ended, releases the run claim and kills its capabilities (48.870662ms) +✔ endLaunch refuses an unknown run, a second end and a rebind of the ended run (29.248538ms) +✔ a restarted broker refuses to rebind an ended run; a refused rebind leaves the run unbound (32.637699ms) +✔ endLaunch leaves a claim another run took alone (151.775432ms) +✔ refuse records action.refused against the caller with the code only (25.854569ms) +✔ launches off refuses role.launch with launch-revoked until launches on (41.369233ms) +✔ broker process: launch ops authorize role.launch, record refusals and end runs (183.620622ms) +✔ human proof binds CLI entry, process start and nonce; agents and incomplete ancestry refuse (5.460808ms) +✔ process reader gets own kernel identity without exposing environment values (1.105513ms) +✔ EACCES ancestor environments skip only markers; commands and registered launches still refuse (2.890964ms) +✔ real pid 1 remains inspectable when its environment is protected (0.66196ms) +✔ within-role sends cite an open gated launch decision without spending it or naming it in grants (58.516738ms) +✔ missing and foreign-business citations refuse and roll back message and grant (33.696575ms) +✔ cross-role sends still need a matching resolved decision and consume it once (51.512186ms) +✔ broker process binds trusted launches, offers reader capabilities, refuses human mutation, closes cleanly (140.146767ms) +✔ startup token refusal returns safe code without value or partial listening broker (165.369856ms) +✔ loaded fixture token is absent from socket replies and SQLite, including refusal evidence (138.944712ms) +✔ killed broker leaves an explicit stale lock; another process cannot silently reclaim it (186.620794ms) +✔ trusted host registers later launches; socket clients never have a registration verb (143.38202ms) +✔ runtime excludes declared project roots even when host supplies no repoRoots (181.87432ms) +✔ a refused launch binding leaves the broker and existing capabilities alive; bad protocol stops it (81.246986ms) +✔ v3b prototype refusals, views and append-only mutations (169.826249ms) +✔ gated approval authorizes once, survives store reopen, and fresh approval works (66.31408ms) +✔ another run cannot consume an approval; a failed check leaves it usable (170.806451ms) +✔ two scheduled callers have exactly one grant and one consumed refusal (35.10518ms) +✔ failed commit rolls consumption back; cross-role consumes and within-role stays reusable (71.095234ms) +✔ class drift gated to cross-role refuses before consumption (41.943308ms) +✔ class drift cross-role to gated refuses before consumption (42.424786ms) +✔ class drift gated to within-role refuses before consumption (30.638739ms) +✔ class drift cross-role to within-role refuses before consumption (32.766764ms) +✔ class drift within-role to gated refuses before consumption (36.477882ms) +✔ class drift within-role to cross-role refuses before consumption (41.694199ms) +✔ message.send consumes approval and prevents a later send or authorize (36.671986ms) +✔ role.revoke consumes approval and prevents a later revoke or authorize (38.981706ms) +✔ creates private WAL store and excludes a second writer until explicit close (32.015978ms) +✔ rollback is atomic and schema metadata is checked against trusted DDL, not just itself (31.440407ms) +✔ existing empty database and symlink runtime directory refuse, never initialize over damage (30.603692ms) +✔ crash during a transaction recovers no partial event after explicit fixture-only lock removal (197.089583ms) +✔ writer refuses mixed at/read_at forms atomically, even through trusted SQL helpers (24.893809ms) +✔ async transactions refuse before invoking their function (24.126915ms) +✔ recordTask keeps sync reads and a role write apart (50.271252ms) +✔ read_at must be one canonical UTC format, so the projection compares strings safely (18.59157ms) +✔ a bad entry refuses the whole record (28.135164ms) +✔ taskView reads the projection for one business (155.463221ms) +✔ requestTask hands only a holder and a task verb to the handler, and records refusals (64.058729ms) +✔ the server sends task verbs to the adapter with its own timeout; other verbs stay synchronous (308.778218ms) +✔ without an adapter the server refuses every task verb (42.008397ms) +✔ the runtime refuses an invalid adapter and closes a valid one (52.987183ms) +✔ the process loads the S3 adapter from plain-data trackers (288.225403ms) +✔ socket capability stamps launch identity; shared views use wire, no SQL client (51.411447ms) +✔ two wire claims serialize; a lost reply never automatically retries (185.785126ms) +✔ malformed, oversized and identity-forging envelopes refuse without echoing input (33.328628ms) +✔ client preserves UTF-8 when a response divides a multibyte character (23.91873ms) +✔ committed mutation followed by dropped reply reports unknown and is never retried (27.83698ms) +ℹ tests 81 +ℹ suites 0 +ℹ pass 81 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1202.758647 diff --git a/agents/rocko/work/queue-73/out/gate/business.log b/agents/rocko/work/queue-73/out/gate/business.log new file mode 100644 index 000000000..075582a14 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/business.log @@ -0,0 +1,68 @@ +✔ config directory and file path follow MOSAIC_CONFIG (3.499142ms) +✔ the fixture business validates and comes back frozen (8.200955ms) +✔ two instances may share a definition (2.889005ms) +✔ top-level refusals (9.161253ms) +✔ arbiters and projects (18.302779ms) +✔ role instances (7.565324ms) +✔ Vikunja bots (14.375041ms) +✔ a role without Vikunja takes no tracker block (7.070399ms) +✔ credential references match the definition's services (8.726652ms) +✔ launch (19.472588ms) +✔ loadBusiness: file checks (4.217411ms) +✔ loadBusiness: not a regular file (75.414373ms) +✔ loading writes nothing (3.026667ms) +✔ names that are Object.prototype properties don't count as declared (6.226665ms) +✔ the shipped example refuses as written and validates once filled in (1.219599ms) +✔ usage errors exit 4 (477.425638ms) +✔ validate: a good business exits 0 and prints instance digests (122.226689ms) +✔ validate: project files (587.623581ms) +✔ validate: missing files and a broken system config (412.505364ms) +✔ validate: credential reference problems exit 2 and name each one (114.443595ms) +✔ validate: a token file inside the repository is refused (115.872029ms) +✔ validate: role definitions come from MOSAIC_ROLES_DIR (395.576524ms) +✔ resolve: prints one instance's record (382.072144ms) +✔ resolve: refusals (671.297775ms) +✔ parse: exactly one of file or env, plus the service's date (5.20369ms) +✔ check: a good file has no problems (3.750629ms) +✔ check never opens the file: a write-only token passes (0.883724ms) +✔ check: file problems (2.127762ms) +✔ check: token files can't live in the repository or dataRoot, even through a linked directory (1.608643ms) +✔ check: dates and environment references (1.54162ms) +✔ path and load (3.887149ms) +✔ refusals (3.166373ms) +✔ systemVars flattens the validated config (3.977377ms) +✔ precedence: system, business, project, project role, agent (9.369246ms) +✔ limits narrow the definition and never widen it (5.814447ms) +✔ role.launch stays within-role only for the instance the launch block names (9.938752ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (3.698816ms) +✔ limits.authority narrows cross-role actions too (3.358156ms) +✔ classify (2.651364ms) +✔ the record carries what the broker and launcher need (1.878428ms) +✔ digest: key order doesn't matter, any value change does (16.959853ms) +✔ refusals (5.200785ms) +✔ the four shipped version 2 roles load (6.343277ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.898026ms) +✔ shipped authority follows the note's table (0.923704ms) +✔ version 1 files keep loading with no authority (1.694498ms) +✔ the conductor policy isn't a role (0.391224ms) +✔ a missing role file is exit 4, a symbolic link too (1.024239ms) +✔ version 2 refusals (2.475814ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (4.492413ms) +✔ credentials: Gitea scopes (2.331614ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (4.431165ms) +✔ credentials: services (1.431893ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.71708ms) +✔ every key names known layers and a merge rule (1.619414ms) +✔ unknown keys and wrong layers refuse (1.319144ms) +✔ types (3.666892ms) +✔ merge: defaults, then the most specific layer wins (0.481573ms) +✔ merge: limits only narrow, and provenance lists each source (0.550264ms) +✔ merge doesn't change its inputs (0.231736ms) +ℹ tests 60 +ℹ suites 0 +ℹ pass 60 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 3407.146697 diff --git a/agents/rocko/work/queue-73/out/gate/cli.log b/agents/rocko/work/queue-73/out/gate/cli.log new file mode 100644 index 000000000..a04778754 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/cli.log @@ -0,0 +1,122 @@ +✔ every screen and overlay fits 120x36, 80x24 and the narrow layout, row for row (2575.437868ms) +✔ width counts terminal cells: wide CJK and emoji 2, U+FE0F after a one-cell base 1, marks 0 (121.840489ms) +✔ broker text is shown, never interpreted: no raw control character or bidi override reaches the terminal (259.988312ms) +✔ NO_COLOR: no escape codes, except reverse video on the selected row (583.254542ms) +✔ 1-9 shows the decide flow's own lines and question; only y resolves (75.499086ms) +✔ the app shows the same decide text as mosaic decide (31.276476ms) +✔ any key but y or Y at the question answers No; nothing is sent (246.91868ms) +✔ below 40x10 the question is hidden, so every key answers it No, y included (Filbert R3) (82.445862ms) +✔ a throw while answering the question goes to crash, sends nothing and leaves no job pending (25.837195ms) +✔ type-ahead never answers the question: a paste, keys typed before it is drawn, keys inside askMs (445.758625ms) +✔ quitting at the question answers No and sends nothing, armed or not (48.00947ms) +✔ a timer tick reads nothing under an overlay, never answers the question, and keeps a resolved status (37.142973ms) +✔ a long question is cut inside the question; the action, target, choice and prompt stay (Dewey B1) (46.730692ms) +✔ a decide box too big for the terminal says so, and every key answers it No, y included (Dewey B1, round 3) (367.441442ms) +✔ at every size the decide box shows each line y depends on, or says it is hidden (13172.79353ms) +✔ outcome unknown: the CLI's sentence, no retry, then the trail or a re-read (81.404171ms) +✔ refused and failed reads keep the last list, marked stale; a refused decide says refused (37.386594ms) +✔ keys: views, moving, trail of a selection, the command line, help and quit (90.340526ms) +✔ one option: the status line says Press 1, not 1-1 (24.889131ms) +✔ no business: the app says so and :business picks one (15.041507ms) +✔ mosaic with no argument: exit 3 in an agent run, exit 4 with the usage off a terminal, the app on one (5.682261ms) +✔ scripts/mosaic with no argument reaches the app entry; the seat usage it printed before has not drifted (230.572504ms) +✔ strings to keep exactly live once, in the decide flow and the transport; the app does not restate them (0.620902ms) +✔ decide with --note still asks; a No sends nothing (11.58382ms) +✔ the app's business comes from a live bus host only (2.054439ms) +✔ runApp leaves the terminal as it found it on q, end of input, SIGTERM, SIGINT, SIGHUP and an error, the first frame's included (10.430805ms) +✔ draw is pure: same state, same frame (1.022236ms) +✔ inbox lists only decisions routed to the human, with what approving authorizes and how to decide (54.444537ms) +✔ decide resolves by id prefix with --yes, and the trail shows it in broker order with the task to follow (50.898151ms) +✔ decide refuses without a terminal or --yes, on an unknown option and on a short reference (39.078896ms) +✔ decide prints a declining choice as declining (30.366338ms) +✔ an unknown outcome is reported once and never resent (50.934024ms) +✔ a decision closed before the answer arrives exits 2 and points at its trail (25.95427ms) +✔ a prefix that matches two open decisions exits 2 and resolves neither (35.958621ms) +✔ without --business a command uses the live host's business, and a stale host.json is not a host (16.387693ms) +✔ every human command refuses inside an agent run before it touches the bus (26.398696ms) +✔ usage errors exit 4; no business and no host is a usage error (22.963519ms) +✔ agents and tasks print through the broker (21.444282ms) +✔ notify.json: missing, loose, malformed and extra keys refuse; a binding or null passes (3.686442ms) +✔ bootConfig builds the broker's boot message for one business, with no trackers key when no project names one (126.715818ms) +✔ trackers come from the tracker.* variables of the one project that names a tracker project (178.667084ms) +✔ with two projects, the one that sets tracker.project supplies the tracker and the other is no conflict (76.289126ms) +✔ two projects that each name a tracker project refuse, since the boot shape holds one (103.153178ms) +✔ a business without tracker.baseUrl gets no trackers entry (93.104531ms) +✔ an unknown business and a broken system config refuse with exit 3 (220.550038ms) +✔ empty views say so (1.445675ms) +✔ the trail keeps the broker's order and names a decision's task without its rows (1.62635ms) +✔ tasks print the tracker fields the snapshot carries (0.275421ms) +✔ the host boots the broker, binds a launch in process, and the notifier DMs a blocking decision exactly once (1234.573704ms) +✔ a notifier that dies takes the host down with exit 1, so the unit restarts the pair (255.78367ms) +✔ a second host for the same data root refuses with exit 3 while the first runs (125.006311ms) +✔ a broker reply that misses the wait breaks the channel: the late reply answers nothing, later requests refuse, the host exits 1 (1130.72943ms) +✔ a broker reply with another request's id, or none, breaks the channel and the host exits 1 (307.7752ms) +✔ a broker reply with no request waiting breaks the channel and the host exits 1 (200.138306ms) +✔ a notifier that refuses stops the broker and the host refuses with exit 3 (265.698781ms) +✔ a notifier that refuses after the broker died still refuses with exit 3, without a send to the dead broker (181.266956ms) +✔ a notifier that dies before it replies, after the broker died, still refuses, without a send to the dead broker (146.196068ms) +✔ a close send that fails with EPIPE after the notifier refuses still gives the notifier's refusal, exit 3 (194.368599ms) +✔ a close send that fails with EPIPE after the notifier dies unanswered still gives the notifier's error (114.904121ms) +✔ close() whose stop and close sends fail with EPIPE still finishes, with exit 1 (216.017254ms) +✔ watchChildren reports a child that died before it was called, and one that dies later (34.650091ms) +✔ bus stop refuses to signal a live pid that is not a bus host (204.737058ms) +✔ bus start refuses with exit 3 and the code when the broker refuses to boot; bus status names the lock (402.133502ms) +✔ bus start refuses with exit 3 without a notifier config (193.518643ms) +✔ bus start runs until bus stop; status reports it while it runs (938.99266ms) +✔ bus-service.sh renders the unit and installs it into a given directory (78.270678ms) +✔ bus-service.sh pins the claude binary, refuses one the unit can't carry, and renders without one (121.526952ms) +✔ bus start --pm: the PM runs under its own PID namespace, registered, with a manifest (1386.034158ms) +✔ the PM launches a coder through its launch tool; the coder answers; refusals name their code (583.053034ms) +✔ a runner that stops at once ends its launch with the runner's reason (276.596415ms) +✔ 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 (902.684414ms) +✔ 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 (3857.50546ms) +✔ a malformed sessions.json refuses the host start with exit 3 and stays as it was (110.075476ms) +✔ an over-long launch request is refused at once, not at the 10 s idle timeout (123.391452ms) +✔ a launch client that never closes its side doesn't hold the host's close (125.094283ms) +✔ a runner that ignores SIGTERM is killed when the host closes (1230.598399ms) +✔ claudeVersion asks MOSAIC_CLAUDE_BIN when set, else claude on PATH (7.358594ms) +✔ zoned uses the IANA zone across DST (29.221001ms) +✔ each open blocking decision is DM'd once, across polls and a restart; non-blocking ones are not (41.382705ms) +✔ two blocking decisions get two DMs with different nonces (41.511473ms) +✔ the digest nonce differs per business and per day and fits Discord's 25 characters (0.391142ms) +✔ a failed DM is journaled, backs off, and is retried until it lands (41.061189ms) +✔ five definite refusals stop a DM: one gave-up line, one log line, and a restart keeps the count (56.151739ms) +✔ 429s, 5xx-style unknowns and refusals without a status never count toward the limit (83.90553ms) +✔ a crash between the fifth refusal and its gave-up line: the next poll appends it and sends nothing (37.52893ms) +✔ 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 (232.090057ms) +✔ a restart after the second refusal does not send before that refusal's 30 min are up (113.374042ms) +✔ the digest goes at 08:00 Chicago once a day, with blocking ones marked as DM'd (36.376926ms) +✔ a late start with no digest for the day sends one at once; an empty inbox gets one line (39.173684ms) +✔ an inbox read failure is logged and the next poll retries (2.215435ms) +✔ no Discord id reaches the journal or the log (22.25059ms) +✔ the journal: a torn tail is copied out and truncated, so an append after it reopens cleanly (12.880256ms) +✔ the journal: a crash between the copy and the truncate leaves a tail the next open repairs (6.917527ms) +✔ the journal: a whole file that is one torn line truncates to empty (2.277526ms) +✔ the journal: a malformed complete line refuses and leaves the file and any torn tail alone (1.171449ms) +✔ the journal: a loose file mode, a loose directory or a symlinked journal refuses (3.129807ms) +✔ the journal: a line with a wrong type refuses with exit 3 and names the field (8.844715ms) +✔ the journal: a symlinked directory refuses and says it is a link (1.039649ms) +✔ 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.847472ms) +✔ the journal: an append after the file was swapped for a symlink refuses and writes nothing through it (1.433451ms) +✔ the journal: a directory it cannot write or create refuses with exit 3 and names the path (1.114175ms) +✔ digest content stays within Discord's 2000 characters (0.621691ms) +✔ runLoop never overlaps ticks and stops after the one in flight (119.237271ms) +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 (724.50701ms) +✔ the transport writes {business, verb, args} to the child and reads its JSON (91.241323ms) +✔ a bus code on stderr becomes the exit code; garbage and timeouts are outcome problems (2435.284197ms) +✔ busExit and refuseInsideAgent (0.695552ms) +✔ talk sends a REQUEST, prints and reads everything that arrives, and stops at the reply (115.335304ms) +✔ talk --wait 0 only sends; no reply within --wait exits 1 and says where it will show (1053.430583ms) +✔ talk, stop and launches off/on refuse inside an agent run; bad arguments are usage errors (15.844796ms) +✔ launches off and on go to the broker and change the business's launch state (14.087384ms) +✔ launches list reads sessions.json and marks a stale entry; stop reports it and refuses a non-runner (15.217499ms) +ℹ tests 112 +ℹ suites 0 +ℹ pass 112 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 18837.646924 diff --git a/agents/rocko/work/queue-73/out/gate/end.txt b/agents/rocko/work/queue-73/out/gate/end.txt new file mode 100644 index 000000000..28d6925b7 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/end.txt @@ -0,0 +1 @@ +2026-10-11T23:14:34Z diff --git a/agents/rocko/work/queue-73/out/gate/harness.log b/agents/rocko/work/queue-73/out/gate/harness.log new file mode 100644 index 000000000..c47d4b0f8 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/harness.log @@ -0,0 +1,66 @@ +✔ sessionModel: agent vars win, then the system's execution settings (28.582565ms) +✔ a pi bundle: prompt, policy, tools and manifest, 0600 in a 0700 directory (10.80112ms) +✔ a claude-code bundle adds the wrapped gate hook and the MCP config (7.891606ms) +✔ a bundle is written once: an existing file refuses (4.681172ms) +✔ a path with a single quote can't go into the hook command (5.835675ms) +✔ allow exits 0, a deny exits 2 with the reason on stderr (491.930816ms) +✔ a missing or wrong policy, or a bad event, exits 2 (280.01237ms) +✔ the bundle's wrapped command: a missing gate or node still blocks (1240.222858ms) +✔ claude: typed tools through MCP, the hook blocks, builtins outside --tools don't exist (1816.377717ms) +✔ claude: the hook alone blocks a path outside the workspace (731.111927ms) +✔ claude: a second turn resumes the first turn's session (1803.113028ms) +✔ claude adapter: --restricted is always passed (9.598654ms) +✔ claude adapter: MOSAIC_CLAUDE_BIN wins over PATH and must be an absolute executable (43.271331ms) +✔ claude: CLAUDE.md files and auto-memory don't reach the model; without --restricted they do (1233.642263ms) +✔ claude: a missing hook or MCP file refuses before claude starts (13.803182ms) +✔ pi: policy tools and typed tools pass, anything else is blocked (9.070302ms) +✔ claude: builtins map from pi names, typed tools need the mcp prefix (1.487225ms) +✔ file tool paths must resolve inside the workspace (7.762967ms) +✔ pi's own path normalisation can't be used to step out (5.452659ms) +✔ a symlink inside the workspace that points out is outside (2.168089ms) +✔ a dangling symlink is refused at any depth, in both harnesses (8.67524ms) +✔ read is checked under every spelling pi's read would open, in both harnesses (45.396712ms) +✔ other spellings cover directories, dangling links and pi's cwd (3.008336ms) +✔ a relative path climbs from the workspace's real path, in both harnesses (10.755171ms) +✔ claude path fields per tool (1.281399ms) +✔ glob patterns stay inside the workspace (1.64637ms) +✔ a path that can't be checked is blocked (0.661031ms) +✔ initialize, ping and tools/list (100.93379ms) +✔ tools/call goes through the tool socket; a refusal is an isError result (79.489337ms) +✔ unknown tools and methods are JSON-RPC errors and never reach the socket (73.485687ms) +✔ a missing argument is a usage error (131.29632ms) +✔ pi: typed tools reach the socket, the gate blocks, agent_end writes the marker (1126.108528ms) +✔ pi: a write through a dangling symlink is blocked, and nothing appears outside (674.432288ms) +✔ pi: a read is refused when pi would open another spelling outside (584.730201ms) +✔ pi: a relative path climbs from the real path of a workspace behind a symlink (675.898409ms) +✔ pi: a relative path climbs from the real path of a dataRoot behind a symlink (959.55437ms) +✔ pi: a missing extension refuses before any model call (14.697573ms) +✔ pi: an extension without its configuration fails pi's start (532.20757ms) +✔ founderCheck: founder variables, then a needed service without a usable token (5.252564ms) +✔ turnRequest names the sender, class, reply and decision (0.404605ms) +✔ a message becomes a turn, the answer goes back as a RESULT, SIGTERM releases and exits 0 (437.11389ms) +✔ a SIGTERM before the claim stops the runner with exit 0 and no claim (195.724419ms) +✔ typed tools carry the runner's capability; launch goes to the host's launch socket (575.474458ms) +✔ a RESULT gets no automatic reply; failed turns reply with the reason (1375.381179ms) +✔ SIGTERM during a turn kills the turn's process group and still exits 0 (194.928324ms) +✔ founder credentials stop before the claim (20) (184.605222ms) +✔ a refused claim exits 21; an ended run's capability exits 22 (453.390314ms) +✔ the launch ending under a running session exits 22 (217.268639ms) +✔ a broker that stays unreachable exits 23 after brokerRetries polls (272.988015ms) +✔ a broker that is down at the claim exits 23, not 21 (96.658628ms) +✔ no capability, or a malformed one, on stdin exits 2 (289.734618ms) +✔ a missing or malformed policy exits 2 before the claim (164.918924ms) +✔ the PM gets launch, its task verbs and the reads (11.769269ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (4.543725ms) +✔ a coder with a tracker gets its own task tools and no task_reassign (2.885134ms) +✔ launch only when the business's launch block names the instance as launcher (2.70311ms) +✔ an action outside the instance's authority has no tool (8.068441ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (24.367924ms) +ℹ tests 58 +ℹ suites 0 +ℹ pass 58 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 11062.352505 diff --git a/agents/rocko/work/queue-73/out/gate/seat.log b/agents/rocko/work/queue-73/out/gate/seat.log new file mode 100644 index 000000000..e2df11356 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/seat.log @@ -0,0 +1,35 @@ +✔ resolveSeat: by name under --repo resolves the repo layout (2.571856ms) +✔ resolveSeat: by path resolves the fleet layout (0.733308ms) +✔ resolveSeat: refusals for missing dir, missing launch.sh, non-executable launch.sh, invalid name, and unknown layout (1.502708ms) +✔ tmuxContext: outside tmux, default socket, custom socket, and exec failure (1.320435ms) +✔ makeRegistration produces a record that validates; each shape violation throws SeatError (1.629035ms) +✔ writeRegistration/readRegistration: round trip, permissions, absence, and malformed records (2.372825ms) +✔ updateTask: changes task, taskSetBy and updatedAt only, and refuses appropriately (1.798218ms) +✔ CLI launch: registers, execs the fake launch script, and passes args through (64.567607ms) +✔ CLI launch: --harness lands in the record (57.869902ms) +✔ CLI launch: the launch script's own exit code passes through (43.095625ms) +✔ CLI launch: relaunching a seat rewrites the one registration record (93.424815ms) +✔ CLI launch: omitting --task records an empty string, not null (46.406032ms) +✔ CLI seat task: updates only the task after a launch, and refuses on an unlaunched seat (133.037855ms) +✔ CLI refusals: no args, unknown flag, missing config, already-registered env, and exec failure (204.105953ms) +✔ samePath: equal paths, symlinked dirs, distinct dirs, and non-strings (0.619616ms) +✔ resolveSetBy: explicit --by wins over the environment; absent or empty environment gives unknown; invalid explicit or environment values refuse with exit 4 (0.743583ms) +✔ 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.034ms) +✔ 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.309264ms) +✔ 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 (424.850272ms) +✔ family: exactly one launch.max key in the model name, else null (1.134819ms) +✔ sessionEnv passes only the allowlist, the repo's bin on PATH, and the run id (1.321324ms) +✔ newRun: short ids, 0700 directories, and a refusal when the socket path won't fit (2.696089ms) +✔ session file and launch log: 0600, the session file written once (1.648677ms) +✔ endReason maps the runner's exit codes; a signal is killed (0.21076ms) +✔ Registry mirrors to sessions.json; readSessions marks live entries; bad files refuse (1.820038ms) +✔ stopSession refuses an unknown run, reports a stale one, and won't signal a pid that isn't a runner (1.401457ms) +✔ a session runs under unshare as pid 1 of its namespace, claims, answers, and stops on mosaic stop (250.310689ms) +ℹ tests 27 +ℹ suites 0 +ℹ pass 27 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1192.412558 diff --git a/agents/rocko/work/queue-73/out/gate/start.txt b/agents/rocko/work/queue-73/out/gate/start.txt new file mode 100644 index 000000000..3825455e9 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/start.txt @@ -0,0 +1 @@ +2026-10-11T23:09:50Z diff --git a/agents/rocko/work/queue-73/out/gate/summary.txt b/agents/rocko/work/queue-73/out/gate/summary.txt new file mode 100644 index 000000000..2401ad323 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/summary.txt @@ -0,0 +1,16 @@ +tasks rc=0 ℹ pass 71 ℹ fail 0 ℹ skipped 0 +bus rc=0 ℹ pass 81 ℹ fail 0 ℹ skipped 0 +business rc=0 ℹ pass 60 ℹ fail 0 ℹ skipped 0 +harness rc=0 ℹ pass 58 ℹ fail 0 ℹ skipped 0 +cli rc=0 ℹ pass 112 ℹ fail 0 ℹ skipped 0 +webui rc=0 ℹ pass 50 ℹ 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 diff --git a/agents/rocko/work/queue-73/out/gate/tasks.log b/agents/rocko/work/queue-73/out/gate/tasks.log new file mode 100644 index 000000000..c713e892b --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/tasks.log @@ -0,0 +1,79 @@ +✔ the boot config is checked before anything starts (47.200233ms) +✔ a business with no tracker entry refuses task verbs (26.054232ms) +✔ credential.expiring and .expired are recorded once per instance (71.464071ms) +✔ a token file that changes on disk records credential.changed (19.23182ms) +✔ autostart polls, reconciles and retries a startup the tracker was down for (55.654321ms) +✔ a refusal a restart must clear is not retried by the poll (19.019302ms) +✔ a poll that fires while two are queued is dropped (31.522387ms) +✔ close waits for a running verb and refuses one that has not started (84.044017ms) +✔ the bundled Vikunja is the pinned upstream image the runbook names (1.460154ms) +✔ every published port is on 127.0.0.1, and no secret is in the file (0.553947ms) +✔ the fake answers each route with the statuses and shapes Vikunja v2.7.0 sent (224.349567ms) +✔ the project list holds recorded project objects in the recorded list envelope (22.371425ms) +✔ the recorded task bodies pass the checks S3 applies to every read (1.419284ms) +✔ the client works against the fake over real HTTP with the platform fetch (215.956568ms) +✔ a correct install starts, and the first reconcile records tasks that already exist (56.215912ms) +✔ verbs refuse while a business is starting and after startup refused it (41.960644ms) +✔ startup refuses a token that can do more than its role needs (69.306729ms) +✔ startup refuses an unsupported version and flags an untested one (63.000628ms) +✔ startup refuses a board that the runbook did not install (85.304122ms) +✔ startup refuses a project the sync bot cannot read (46.47812ms) +✔ startup refuses a configured label the pm bot cannot see (25.371916ms) +✔ startup refuses an expired credential and a missing sync credential (52.17586ms) +✔ an unreachable tracker refuses with tracker-unavailable (15.114537ms) +✔ an edit in the UI is recorded once, with the fields that changed (127.212799ms) +✔ a move between open buckets is seen on the board, though updated does not change (65.945293ms) +✔ a person's comment is counted and a bot's is not (118.78426ms) +✔ the hourly reconcile catches a comment through comment_count (159.932149ms) +✔ a task closed in the UI leaves the open view with its done bucket (177.635334ms) +✔ a task that leaves the board is recorded as deleted, moved or out of reach (196.943355ms) +✔ a poll that read before a verb wrote does not overwrite the verb (89.064442ms) +✔ a tracker fault during a tick is reported and the next tick catches up (53.781773ms) +✔ a malformed answer refuses the tick with tracker-shape (22.569344ms) +✔ no token value reaches the database, the log or a refusal (71.43717ms) +✔ the first look at a task counts only comments inside the window (47.402383ms) +✔ with descendants off the adapter reads no project list and no child, as in v0 (75.132178ms) +✔ a three-level tree is read per project, and a project outside it is not (43.731266ms) +✔ a watch-only child keeps the business ready, and a failed child read refuses as transient (52.398292ms) +✔ a root without the installed buckets refuses with descendants on (20.347468ms) +✔ the project list refuses without read_all, and skips archived projects and saved filters (47.255975ms) +✔ descendants must be true or false (15.341385ms) +✔ a move inside the tree is a moved tombstone plus a snapshot under the new ref (111.510521ms) +✔ a child made after startup joins the tree at the next reconcile (86.324892ms) +✔ a child that leaves the tree has its tasks recorded missing, and the ledger keeps their history (94.225955ms) +✔ a child deleted or hidden between reconciles drops out at the next tick, and the root still refuses (146.919538ms) +✔ a reconcile that fails keeps the previous tree (80.42665ms) +✔ a closed task the cursor missed takes its own project's done bucket (61.092169ms) +✔ closed tasks read at startup take their own project's done bucket (38.269422ms) +✔ a closed task the cursor returns takes its own project's done bucket (70.162556ms) +✔ a task moved out of a child that leaves the tree at the same time is moved, not no-access (46.700813ms) +✔ a task in a bucket outside the five keeps its raw bucket id (38.564246ms) +✔ bucket 0 on a watch-only task never becomes a bucket or a state (95.280726ms) +✔ a child whose kanban view is deleted still refuses the tick, and the reconcile reads it watch-only (70.345835ms) +✔ a child dropped at a tick comes back at the next reconcile once the bot reads it again (50.218065ms) +✔ task.create needs a recorded human request and a requirement id (95.495374ms) +✔ only labels named in the business file can be written (54.586778ms) +✔ task.schedule sets and clears a due date and relations (87.727746ms) +✔ assign and reassign move the role bots and record task.assigned (136.022256ms) +✔ task.update.assigned is for the assignee and records task.state (158.096097ms) +✔ a wrong expected digest records task.conflict and writes nothing (58.524297ms) +✔ a cross-role verb needs a resolved decision, used once (75.182705ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (157.320621ms) +✔ a lost answer is settled by a re-read and never retried (77.393226ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (77.31654ms) +✔ a task the sync bot cannot read refuses and records nothing (36.749543ms) +✔ verbs and polls for one business run one at a time (113.82165ms) +✔ a due date with milliseconds is written to the second (80.352537ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (47.226617ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (27.798719ms) +✔ a create whose final read fails succeeds and records task.created (44.517445ms) +✔ an edit between the last write and the final read shows as external on the next poll (70.754281ms) +✔ task.created is recorded when a later label write fails (24.516626ms) +ℹ tests 71 +ℹ suites 0 +ℹ pass 71 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1636.446672 diff --git a/agents/rocko/work/queue-73/out/gate/test-auth.log b/agents/rocko/work/queue-73/out/gate/test-auth.log new file mode 100644 index 000000000..ac2287606 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-auth.log @@ -0,0 +1,17 @@ +OK status with missing harness credential exits 3 and still lists accounts +OK status reports harness credential (read-only) + mosaic accounts +OK api key material never reaches output +OK oauth token material never reaches output +OK unparseable credential file exits 2 +OK symlinked credential file exits 4 +OK env-side credential names reported +OK env var values never reach output +OK accounts without an accounts dir reports none and creates nothing +OK accounts lists files and marks the active one +OK loose account perms flagged in listing +OK agent --auth with missing account file refuses (exit 4) +OK agent --auth with non-0600 account file refuses +OK agent --auth with invalid account name refuses +OK auth.sh without valid config refuses + +selftest: 15 passed, 0 failed diff --git a/agents/rocko/work/queue-73/out/gate/test-conductor.log b/agents/rocko/work/queue-73/out/gate/test-conductor.log new file mode 100644 index 000000000..62afc513c --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-conductor.log @@ -0,0 +1,23 @@ +On branch refactor +Your branch is up to date with 'origin/refactor'. + +nothing to commit, working tree clean +OK dry-run: allowed change, exit 0, nothing committed (exit 0) +OK dry-run committed nothing +OK apply: allowed change exits 0 (exit 0) +OK apply: attribution in commit subject +OK apply: target tree clean after commit +OK disallowed path refused (exit 1) +OK disallowed path: target untouched +OK syntax gate refused broken .mjs (exit 1) +OK syntax gate: target untouched +OK suite failure refused (exit 1) +OK suite failure: target reverted to clean +OK disabled policy refused (exit 2) +OK disabled policy: target untouched +OK failed run refused (exit 1) +OK failed run: target untouched +OK missing run exits 4 (exit 4) +OK invalid policy exits 2 (exit 2) + +selftest: 17 passed, 0 failed diff --git a/agents/rocko/work/queue-73/out/gate/test-config.log b/agents/rocko/work/queue-73/out/gate/test-config.log new file mode 100644 index 000000000..76c05ef74 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-config.log @@ -0,0 +1,26 @@ +OK absent adapter defaults to pi +OK adapter mock validates (exit 0) +OK unsupported adapter exits 2 (exit 2) +OK env exports adapter +OK bootstrap creates default when absent (exit 0) +OK bootstrap wrote config file +OK bootstrap is idempotent on existing config (exit 0) +OK bootstrap did not rewrite existing config +OK validate missing config exits 3 (exit 3) +OK malformed JSON exits 2 (exit 2) +OK unsupported configVersion exits 2 (exit 2) +OK unknown top-level key exits 2 (exit 2) +OK unknown execution key exits 2 (exit 2) +OK unsupported backend exits 2 (exit 2) +OK unsupported environment exits 2 (exit 2) +OK relative dataRoot exits 2 (exit 2) +OK non-canonical dataRoot exits 2 (exit 2) +OK filesystem root dataRoot exits 2 (exit 2) +OK home directory dataRoot exits 2 (exit 2) +OK dataRoot containing config dir exits 2 (exit 2) +OK control character in provider exits 2 (exit 2) +OK symlinked config file exits 2 (exit 2) +OK env exports resolve correctly +OK failed validation modified nothing + +selftest: 24 passed, 0 failed diff --git a/agents/rocko/work/queue-73/out/gate/test-discord.log b/agents/rocko/work/queue-73/out/gate/test-discord.log new file mode 100644 index 000000000..b013f9ffa --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-discord.log @@ -0,0 +1,70 @@ +toolchain: node v26.8.1 + +OK syntax: packages/discord/src/approvals.mjs +OK syntax: packages/discord/src/authorize.mjs +OK syntax: packages/discord/src/binding.mjs +OK syntax: packages/discord/src/cli.mjs +OK syntax: packages/discord/src/connector.mjs +OK syntax: packages/discord/src/context.mjs +OK syntax: packages/discord/src/engine-pi.mjs +OK syntax: packages/discord/src/errors.mjs +OK syntax: packages/discord/src/gateway.mjs +OK syntax: packages/discord/src/git.mjs +OK syntax: packages/discord/src/journal.mjs +OK syntax: packages/discord/src/notify.mjs +OK syntax: packages/discord/src/rest.mjs +OK syntax: packages/discord/src/setspark.mjs +OK syntax: packages/discord/src/tools.mjs +OK syntax: packages/discord/src/web.mjs +OK syntax: packages/discord/bin/git-credential.mjs +OK syntax: packages/discord/extension/tools.mjs +OK syntax: packages/discord/tests/approvals.test.mjs +OK syntax: packages/discord/tests/authorize.test.mjs +OK syntax: packages/discord/tests/binding.test.mjs +OK syntax: packages/discord/tests/connector.test.mjs +OK syntax: packages/discord/tests/context.test.mjs +OK syntax: packages/discord/tests/engine.test.mjs +OK syntax: packages/discord/tests/fake-pi.mjs +OK syntax: packages/discord/tests/gateway.test.mjs +OK syntax: packages/discord/tests/git.test.mjs +OK syntax: packages/discord/tests/helpers.mjs +OK syntax: packages/discord/tests/journal.test.mjs +OK syntax: packages/discord/tests/notify.test.mjs +OK syntax: packages/discord/tests/recover.test.mjs +OK syntax: packages/discord/tests/rest.test.mjs +OK syntax: packages/discord/tests/setspark.test.mjs +OK syntax: packages/discord/tests/tools.test.mjs +OK syntax: packages/discord/tests/web.test.mjs +OK syntax: packages/discord/fixtures/claim-worker.mjs +OK syntax: packages/discord/fixtures/legacy-owner-worker.mjs +OK syntax: scripts/discord.sh +OK syntax: scripts/discord-service.sh +OK packages/discord declares no dependencies +OK no bot-token-shaped string in packages/discord +OK fixture binding uses placeholder ids only +OK fixture binding validates +OK real pi with the extension exposes exactly list_dir, read_file, search and no built-in tool +OK real pi with a writable root exposes exactly the three reads plus write_file and edit_file, and writes nothing at start +OK real pi with a web key exposes the three reads plus web_fetch and web_search, and no write tool without a writable root +OK real pi with a git root exposes the reads, writes and the four git verbs, commits nothing at start, and never shows the token +OK real pi with protocol vault adds reserve_id to the git verbs +OK real pi with a setspark key exposes the reads and the eight record verbs, no counters, and never shows the key +OK real pi refuses a git key on a read-only root (fail closed) +OK real pi with the pilot flags (--no-tools) exposes no tool at all +OK real pi exits non-zero without MOSAIC_DISCORD_TOOLS: no session, no tools (fail closed) +OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT +OK node --test packages/discord/tests/ (ℹ pass 178) +OK scripts/discord.sh --help exits 0 +OK scripts/discord.sh check without a binding exits 4 +OK scripts/discord.sh recover without a binding exits 4 +OK scripts/discord.sh reload without a binding exits 4 +OK scripts/discord-service.sh without a command exits 4 +OK service unit renders with the repository path, a supervised run as the main process, exit 3 never retried, and reload as SIGHUP +OK service install writes the rendered unit (0644) and leaves no temp file +OK service install a second time reports unchanged +OK systemd-analyze verify accepts the rendered unit +OK service uninstall removes the unit file +OK service install with an unknown flag exits 4 +OK service install with USER unset finishes and names the account for lingering + +discord suite: 66 passed, 0 failed diff --git a/agents/rocko/work/queue-73/out/gate/test-extension-package.log b/agents/rocko/work/queue-73/out/gate/test-extension-package.log new file mode 100644 index 000000000..40c37b8af --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-extension-package.log @@ -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: 231435 Killed "$@" > /dev/null 2>&1 +OK forced interruption kills the replacing process +OK next invocation recovers old consistent installation +OK interrupted replacement rolled back +OK sync succeeds after interruption recovery +OK unlocked stale lock file does not block +OK active lock refuses a concurrent sync +OK source symlink fails closed +OK nested second entrypoint fails closed + +extension package selftest: 18 passed, 0 failed diff --git a/agents/rocko/work/queue-73/out/gate/test-foundation.log b/agents/rocko/work/queue-73/out/gate/test-foundation.log new file mode 100644 index 000000000..6338e1e6d --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-foundation.log @@ -0,0 +1,53 @@ +toolchain: node v26.8.1, python 3.12.8, jsonschema 4.26.0 + +OK syntax: scripts/foundation-inspect.mjs +OK syntax: scripts/foundation/strict-json.mjs +OK syntax: scripts/foundation/canonical.mjs +OK syntax: scripts/foundation/resolve.mjs +OK syntax: scripts/foundation/validate-record.mjs +OK syntax: scripts/foundation/fixtures/build-fixtures.mjs +OK syntax: scripts/foundation/canonical.test.mjs +OK syntax: scripts/foundation/cli.test.mjs +OK syntax: scripts/foundation/fixtures.test.mjs +OK syntax: scripts/foundation/resolve.test.mjs +OK syntax: scripts/foundation/strict-json.test.mjs +OK syntax: scripts/foundation/verify-schema.py (ast only; no bytecode written) +OK fixture generator runs +OK checked-in fixtures/bundles equal a fresh generation +OK checked-in fixtures/raw equal a fresh generation +OK checked-in fixtures/index.json equal a fresh generation +OK checked-in demo bundles equal a fresh generation +OK a failing nested test fails the run under a parent runner's NODE_TEST_CONTEXT +OK node --test scripts/foundation/ (ℹ pass 80) +OK differential schema oracle: PASS: differential schema oracle (finite corpus; compatibility evidence, not equivalence proof) + platform witness: strftime('%Y') for year 999 -> '999' (pinned checker refuses years 0001..0999) + node v26.8.1; corpus 1568 records (38 pinned fixtures, 478 unique bundle records, 1052 typeCase/mutation/lexical cases) + schema column: agree-valid 540, agree-invalid 991, DISAGREEMENTS 0; strict-only (parser-bound) cases: 27; unsupported-kind records not schema-assessed by the inspector: 10 + profile column (schema-valid records only): profile-valid 510, profile-invalid 30 + profile refusals asserted: 30 schema-agreed-valid records refused only by the strict typed-string profile (rule profile-pattern-mismatch), 12 declared by name; 73 named probes verified against declared schema/profile columns +OK oracle: zero schema-column disagreements with the pinned checker +OK oracle: strict-only profile refusals are counted and asserted +OK demo: permitted read preview exits 0 (exit 0) +OK demo: permitted file.change preview exits 0 (exit 0) +OK demo: assignment.change proposal is unresolved (exit 3) (exit 3) +OK demo: revoked registration is refused (exit 3) (exit 3) +OK demo: message is not authority (exit 3) (exit 3) +OK usage: no arguments exits 2 (exit 2) +OK io: missing file exits 4 (exit 4) +OK io: directory exits 4 (exit 4) +OK io: symlink exits 4 (O_NOFOLLOW) (exit 4) +OK bound: oversize fixture exits 2 (exit 2) +OK profile: one final LF in a typed selection id is refused before admission (exit 2) (exit 2) +OK profile: two final LFs fail the schema pattern itself (exit 2) (exit 2) +OK profile: escaped newlines in free-form text stay allowed (exit 0) (exit 0) +OK profile refusal is invalid-request/profile-pattern-mismatch with selection and operation withheld, value not echoed +OK text output starts with the disclaimer +OK json output is valid JSON with result allowed and exactly the charter §7 fields +OK json golden matches byte-for-byte +OK sandboxed bundle run (env -i, PATH=/nonexistent) produced the unresolved proposal +OK sandbox inventory (path/type/size/mode/uid/gid/inode/mtime/sha256) unchanged by runs +OK canary never printed (bundle run and credential-file run) +OK a non-bundle JSON file is refused at the shape gate, not read into output +OK no field of the non-bundle file is echoed + +selftest: 44 passed, 0 failed diff --git a/agents/rocko/work/queue-73/out/gate/test-queue.log b/agents/rocko/work/queue-73/out/gate/test-queue.log new file mode 100644 index 000000000..3f0fc67d5 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-queue.log @@ -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-r73) is not the queue's canonical root (/mnt/storage/src/mosaic-stack) + +queue suite: 27 passed, 0 failed diff --git a/agents/rocko/work/queue-73/out/gate/test-release.log b/agents/rocko/work/queue-73/out/gate/test-release.log new file mode 100644 index 000000000..7202b85d4 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-release.log @@ -0,0 +1,16 @@ +OK valid RELEASE resolves (exit 0) +OK invalid RELEASE exits 1 (exit 1) +OK missing RELEASE exits 1 (exit 1) +OK valid RELEASE leaves image tag consistent with version +OK status safe on empty state (exit 0) +OK status created no pointer +OK fault-injected activation refuses (exit 1) +OK refused activation wrote no pointer +OK refusal logged exactly once with valid fields +OK healthy activation succeeds (exit 0) +OK pointer written with valid fields +OK repeat activation succeeds (log grows) (exit 0) +OK log is append-only across activations +OK rollback without previous refuses (exit 1) + +selftest: 14 passed, 0 failed diff --git a/agents/rocko/work/queue-73/out/gate/test-task.log b/agents/rocko/work/queue-73/out/gate/test-task.log new file mode 100644 index 000000000..df6724a77 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/test-task.log @@ -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 diff --git a/agents/rocko/work/queue-73/out/gate/webui.log b/agents/rocko/work/queue-73/out/gate/webui.log new file mode 100644 index 000000000..ea5bcdef1 --- /dev/null +++ b/agents/rocko/work/queue-73/out/gate/webui.log @@ -0,0 +1,59 @@ +✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (8106.572334ms) +Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286} +✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (8747.634305ms) +✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (9887.359002ms) +✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (264.222307ms) +✔ decisions route serves the roles and recent lists from the reader view (109.024685ms) +✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (108.781146ms) +✔ bus refusals map to statuses and never carry a path or a stack (82.034912ms) +✔ humanCall speaks the human transport protocol without blocking the server (2363.712435ms) +✔ busReader takes --business, else the live bus host, else refuses (837.234229ms) +✔ humanCall kills a transport that runs past its timeout (595.698952ms) +✔ serve refuses a --business value that is not a business id (1239.153702ms) +✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (7658.493085ms) +✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (2334.361368ms) +✔ conversation view: a newer session with no readable history keeps the marker (1475.86245ms) +✔ conversation view: seats without history say so and offer no reply (1154.68976ms) +✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6505.513225ms) +✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (57598.455344ms) +✔ redactor: config, dataRoot, any absolute path, Discord ids and the JSON parser quote (2.787175ms) +✔ credential state from the date alone, as the bus states it (0.265543ms) +✔ queue: rows, one row, ids and methods, notes; no path or id from a row (2447.752007ms) +✔ queue: a refused read fails closed with the store's text, redacted (1106.728316ms) +✔ queue: a store that fails to load, or a child that dies, gives a fixed message with no path or stack (2952.199165ms) +✔ business: names, vars on the allowlist, authority, credential metadata only (43.48209ms) +✔ business: missing or invalid file refuses with the module's text, redacted (18.270212ms) +✔ business without --business: the live bus host, else no-bus-host; no system config: not-configured (23.291575ms) +✔ settings: release, board, loopback address, notifier binding name only (657.992106ms) +✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (7673.38997ms) +✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (26157.798956ms) +✔ loopback host and board origin fail closed (12.188559ms) +✔ real board fixture passes through WebUI; assets and isolated seen/reply work (347.900023ms) +✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (276.644747ms) +✔ unreachable board reports URL; CLI rejects unsupported options (1741.484661ms) +✔ render prints the unit without the preview flags (60.324721ms) +✔ render carries every serve flag, the preview set included (85.287597ms) +✔ a partial preview set is refused (184.902743ms) +✔ a value the unit cannot carry is refused, for every flag (3027.921779ms) +✔ the rendered unit names none of the human proof agent markers and sets no agent variable (130.32085ms) +✔ install into --dir with --no-reload writes the file whole, then reports unchanged (738.374793ms) +✔ install without --no-reload runs daemon-reload and nothing that starts the unit (114.539901ms) +✔ uninstall refuses while the unit is active, and removes it once it is not (669.457415ms) +✔ status prints the unit state and GET /healthz on the installed port (700.129598ms) +✔ usage: an unknown verb or flag, and start or enable, exit 4 (267.924672ms) +✔ tokens.css and icons.svg are byte copies of docs/design (1.609561ms) +✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.068117ms) +✔ shipped strings are unchanged, and the web keeps its write boundary (2.504909ms) +✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (12906.255137ms) +✔ five states on Board, Inbox, Tasks, Agents and Trail (2975.960387ms) +✔ Queue, Business and Settings in their five states, with no move button (10184.597385ms) +✔ seeded secrets, Discord ids and paths reach no response and no page; business refusals in the module's words (2343.523176ms) +✔ the server log names no config path when the system config refuses (580.596691ms) +ℹ tests 50 +ℹ suites 0 +ℹ pass 50 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 58347.310973 diff --git a/agents/rocko/work/queue-73/out/mutants-base.txt b/agents/rocko/work/queue-73/out/mutants-base.txt new file mode 100644 index 000000000..264a588af --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base.txt @@ -0,0 +1,6 @@ +baseline: pass +role-keeps-reassign: NOT APPLIED (sed matched nothing) +broker-unlisted-cross: SURVIVED +resolve-cross-unnarrowed: killed (✖ an action outside the instance's authority has no tool;✖ limits.authority narrows cross-role actions too;) +classify-unlisted-cross: killed (✖ classify;✖ limits.authority narrows cross-role actions too;✖ limits.authority without role.launch leaves the launcher with no launch block;✖ limits narrow the definition and never widen it;✖ role.launch stays within-role only for the instance the launch block names;) +tools-all-task-verbs: killed (✖ an action outside the instance's authority has no tool;) diff --git a/agents/rocko/work/queue-73/out/mutants-base/baseline.log b/agents/rocko/work/queue-73/out/mutants-base/baseline.log new file mode 100644 index 000000000..bb983fa4a --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/baseline.log @@ -0,0 +1,67 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (41.10989ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (30.340056ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (27.301914ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (16.784646ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (16.117365ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (16.007796ms) +✔ task action subjects and linked decision trail are complete and ordered (33.402123ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (12.499912ms) +✔ business isolation includes inherited object names and cross-business message references (19.585889ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (27.095845ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (12.374754ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (21.007289ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (14.896337ms) +✔ both arbiters require human resolution when their cross-role route is themselves (21.130329ms) +✔ systemVars flattens the validated config (3.298819ms) +✔ precedence: system, business, project, project role, agent (9.974934ms) +✔ limits narrow the definition and never widen it (4.037503ms) +✔ role.launch stays within-role only for the instance the launch block names (10.06119ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (3.498072ms) +✔ limits.authority narrows cross-role actions too (1.527146ms) +✔ classify (1.816472ms) +✔ the record carries what the broker and launcher need (1.558999ms) +✔ digest: key order doesn't matter, any value change does (10.199487ms) +✔ refusals (4.176465ms) +✔ the four shipped version 2 roles load (14.372215ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.984217ms) +✔ shipped authority follows the note's table (1.084755ms) +✔ version 1 files keep loading with no authority (2.030792ms) +✔ the conductor policy isn't a role (0.422745ms) +✔ a missing role file is exit 4, a symbolic link too (0.604689ms) +✔ version 2 refusals (2.11256ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (3.892762ms) +✔ credentials: Gitea scopes (1.509172ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (2.083022ms) +✔ credentials: services (0.971694ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.069304ms) +✔ the PM gets launch, its task verbs and the reads (10.141611ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.092654ms) +✔ launch only when the business's launch block names the instance as launcher (3.195221ms) +✔ an action outside the instance's authority has no tool (2.493976ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (17.882552ms) +✔ task.create needs a recorded human request and a requirement id (62.327198ms) +✔ only labels named in the business file can be written (37.091411ms) +✔ task.schedule sets and clears a due date and relations (44.451536ms) +✔ assign and reassign move the role bots and record task.assigned (66.030754ms) +✔ task.update.assigned is for the assignee and records task.state (66.783287ms) +✔ a wrong expected digest records task.conflict and writes nothing (27.559383ms) +✔ a cross-role verb needs a resolved decision, used once (41.3223ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (39.501253ms) +✔ a lost answer is settled by a re-read and never retried (48.948392ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (45.537621ms) +✔ a task the sync bot cannot read refuses and records nothing (24.722852ms) +✔ verbs and polls for one business run one at a time (107.598043ms) +✔ a due date with milliseconds is written to the second (99.477546ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (51.18486ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (30.29597ms) +✔ a create whose final read fails succeeds and records task.created (43.712142ms) +✔ an edit between the last write and the final read shows as external on the next poll (60.844534ms) +✔ task.created is recorded when a later label write fails (43.90553ms) +ℹ tests 59 +ℹ suites 0 +ℹ pass 59 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1118.992245 diff --git a/agents/rocko/work/queue-73/out/mutants-base/broker-unlisted-cross.diff b/agents/rocko/work/queue-73/out/mutants-base/broker-unlisted-cross.diff new file mode 100644 index 000000000..b0bdc2685 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/broker-unlisted-cross.diff @@ -0,0 +1,11 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-base/orig 2026-10-11 18:09:25.811161905 -0500 ++++ packages/bus/src/broker.mjs 2026-10-11 18:09:27.269340616 -0500 +@@ -274,7 +274,7 @@ + ? 'within-role' + : a?.crossRole.includes(action) + ? 'cross-role' +- : 'gated'; ++ : 'cross-role'; + } + #decision(s, id) { + const d = this.#store.get('SELECT * FROM decisions WHERE id=? AND business=?', id, s.business); diff --git a/agents/rocko/work/queue-73/out/mutants-base/broker-unlisted-cross.log b/agents/rocko/work/queue-73/out/mutants-base/broker-unlisted-cross.log new file mode 100644 index 000000000..9a4393c1b --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/broker-unlisted-cross.log @@ -0,0 +1,67 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (52.058368ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (31.827945ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (32.343445ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (15.453301ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (16.112223ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (15.465475ms) +✔ task action subjects and linked decision trail are complete and ordered (34.817745ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (11.489008ms) +✔ business isolation includes inherited object names and cross-business message references (25.296217ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (31.184317ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (16.792175ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (22.551334ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (13.915971ms) +✔ both arbiters require human resolution when their cross-role route is themselves (23.619893ms) +✔ systemVars flattens the validated config (3.200801ms) +✔ precedence: system, business, project, project role, agent (7.711976ms) +✔ limits narrow the definition and never widen it (5.662494ms) +✔ role.launch stays within-role only for the instance the launch block names (11.879594ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (4.345739ms) +✔ limits.authority narrows cross-role actions too (1.909662ms) +✔ classify (2.20486ms) +✔ the record carries what the broker and launcher need (2.46906ms) +✔ digest: key order doesn't matter, any value change does (16.682292ms) +✔ refusals (3.683678ms) +✔ the four shipped version 2 roles load (5.36865ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.795612ms) +✔ shipped authority follows the note's table (1.155071ms) +✔ version 1 files keep loading with no authority (1.552767ms) +✔ the conductor policy isn't a role (0.342392ms) +✔ a missing role file is exit 4, a symbolic link too (0.602196ms) +✔ version 2 refusals (2.146247ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (3.688492ms) +✔ credentials: Gitea scopes (2.236086ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (2.557229ms) +✔ credentials: services (0.936797ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.47412ms) +✔ the PM gets launch, its task verbs and the reads (11.865141ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (4.766334ms) +✔ launch only when the business's launch block names the instance as launcher (3.204748ms) +✔ an action outside the instance's authority has no tool (2.992598ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (16.830589ms) +✔ task.create needs a recorded human request and a requirement id (67.154682ms) +✔ only labels named in the business file can be written (33.442526ms) +✔ task.schedule sets and clears a due date and relations (48.841556ms) +✔ assign and reassign move the role bots and record task.assigned (78.987774ms) +✔ task.update.assigned is for the assignee and records task.state (65.470032ms) +✔ a wrong expected digest records task.conflict and writes nothing (32.691954ms) +✔ a cross-role verb needs a resolved decision, used once (37.492507ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (45.183086ms) +✔ a lost answer is settled by a re-read and never retried (66.58075ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (47.459336ms) +✔ a task the sync bot cannot read refuses and records nothing (24.247305ms) +✔ verbs and polls for one business run one at a time (102.11683ms) +✔ a due date with milliseconds is written to the second (77.242581ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (48.960103ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (20.384311ms) +✔ a create whose final read fails succeeds and records task.created (40.019605ms) +✔ an edit between the last write and the final read shows as external on the next poll (48.872647ms) +✔ task.created is recorded when a later label write fails (28.904685ms) +ℹ tests 59 +ℹ suites 0 +ℹ pass 59 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1099.85091 diff --git a/agents/rocko/work/queue-73/out/mutants-base/classify-unlisted-cross.diff b/agents/rocko/work/queue-73/out/mutants-base/classify-unlisted-cross.diff new file mode 100644 index 000000000..6ace5fb95 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/classify-unlisted-cross.diff @@ -0,0 +1,9 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-base/orig 2026-10-11 18:09:25.812634433 -0500 ++++ packages/business/src/resolve.mjs 2026-10-11 18:09:29.450323415 -0500 +@@ -100,5 +100,5 @@ + if (!ACTIONS.includes(action)) refuse(`unknown action: ${JSON.stringify(action)}`); + if (resolved.limits.authority.withinRole.includes(action)) return "within"; + if (resolved.limits.authority.crossRole.includes(action)) return "cross"; +- return "gated"; ++ return "cross"; + } diff --git a/agents/rocko/work/queue-73/out/mutants-base/classify-unlisted-cross.log b/agents/rocko/work/queue-73/out/mutants-base/classify-unlisted-cross.log new file mode 100644 index 000000000..65310504e --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/classify-unlisted-cross.log @@ -0,0 +1,174 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (34.562762ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (48.881252ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (31.40005ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (19.163154ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (18.637808ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (23.106973ms) +✔ task action subjects and linked decision trail are complete and ordered (33.924385ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (12.548753ms) +✔ business isolation includes inherited object names and cross-business message references (18.991923ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (21.671041ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (12.2862ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (22.485066ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (14.168727ms) +✔ both arbiters require human resolution when their cross-role route is themselves (23.026ms) +✔ systemVars flattens the validated config (3.055626ms) +✔ precedence: system, business, project, project role, agent (7.376521ms) +✖ limits narrow the definition and never widen it (4.765621ms) +✖ role.launch stays within-role only for the instance the launch block names (5.845037ms) +✖ limits.authority without role.launch leaves the launcher with no launch block (2.382717ms) +✖ limits.authority narrows cross-role actions too (2.320376ms) +✖ classify (1.91099ms) +✔ the record carries what the broker and launcher need (1.859849ms) +✔ digest: key order doesn't matter, any value change does (16.863167ms) +✔ refusals (4.843702ms) +✔ the four shipped version 2 roles load (4.952568ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.790725ms) +✔ shipped authority follows the note's table (0.859956ms) +✔ version 1 files keep loading with no authority (1.580548ms) +✔ the conductor policy isn't a role (0.410542ms) +✔ a missing role file is exit 4, a symbolic link too (0.687476ms) +✔ version 2 refusals (2.208359ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (4.089476ms) +✔ credentials: Gitea scopes (1.522708ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.96425ms) +✔ credentials: services (1.096518ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.388238ms) +✔ the PM gets launch, its task verbs and the reads (10.881554ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (4.91844ms) +✔ launch only when the business's launch block names the instance as launcher (2.979843ms) +✔ an action outside the instance's authority has no tool (2.821761ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (16.298799ms) +✔ task.create needs a recorded human request and a requirement id (77.423799ms) +✔ only labels named in the business file can be written (39.818018ms) +✔ task.schedule sets and clears a due date and relations (52.774716ms) +✔ assign and reassign move the role bots and record task.assigned (70.210371ms) +✔ task.update.assigned is for the assignee and records task.state (71.320218ms) +✔ a wrong expected digest records task.conflict and writes nothing (24.030222ms) +✔ a cross-role verb needs a resolved decision, used once (35.582912ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (33.762759ms) +✔ a lost answer is settled by a re-read and never retried (33.963244ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (49.791704ms) +✔ a task the sync bot cannot read refuses and records nothing (28.959016ms) +✔ verbs and polls for one business run one at a time (103.849164ms) +✔ a due date with milliseconds is written to the second (77.623434ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (41.880183ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (18.077862ms) +✔ a create whose final read fails succeeds and records task.created (38.538489ms) +✔ an edit between the last write and the final read shows as external on the next poll (50.303392ms) +✔ task.created is recorded when a later label write fails (21.206701ms) +ℹ tests 59 +ℹ suites 0 +ℹ pass 54 +ℹ fail 5 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1016.65102 + +✖ failing tests: + +test at packages/business/tests/resolve.test.mjs:69:1 +✖ limits narrow the definition and never widen it (4.765621ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73-base/packages/business/tests/resolve.test.mjs:87:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:91:1 +✖ role.launch stays within-role only for the instance the launch block names (5.845037ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73-base/packages/business/tests/resolve.test.mjs:98:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:112:1 +✖ limits.authority without role.launch leaves the launcher with no launch block (2.382717ms) + AssertionError [ERR_ASSERTION]: agent + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73-base/packages/business/tests/resolve.test.mjs:119:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:124:1 +✖ limits.authority narrows cross-role actions too (2.320376ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73-base/packages/business/tests/resolve.test.mjs:130:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:135:1 +✖ classify (1.91099ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73-base/packages/business/tests/resolve.test.mjs:140:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/rocko/work/queue-73/out/mutants-base/resolve-cross-unnarrowed.diff b/agents/rocko/work/queue-73/out/mutants-base/resolve-cross-unnarrowed.diff new file mode 100644 index 000000000..77d60bb53 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/resolve-cross-unnarrowed.diff @@ -0,0 +1,11 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-base/orig 2026-10-11 18:09:25.812634433 -0500 ++++ packages/business/src/resolve.mjs 2026-10-11 18:09:28.444840244 -0500 +@@ -65,7 +65,7 @@ + if (vars["limits.network"]) network = narrowerNetwork(network, vars["limits.network"]); + if (vars["limits.authority"]) { + withinRole = withinRole.filter((a) => vars["limits.authority"].includes(a)); +- crossRole = crossRole.filter((a) => vars["limits.authority"].includes(a)); ++ crossRole = [...crossRole]; + } + // role.launch needs the business file's launch block naming this + // instance (addendum A section 8), and the verb must survive diff --git a/agents/rocko/work/queue-73/out/mutants-base/resolve-cross-unnarrowed.log b/agents/rocko/work/queue-73/out/mutants-base/resolve-cross-unnarrowed.log new file mode 100644 index 000000000..c32d8d957 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/resolve-cross-unnarrowed.log @@ -0,0 +1,127 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (32.184603ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (34.006489ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (38.37318ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (17.069074ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (18.894895ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (14.699724ms) +✔ task action subjects and linked decision trail are complete and ordered (34.571108ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (11.623471ms) +✔ business isolation includes inherited object names and cross-business message references (18.142067ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (23.301159ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (9.613466ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (19.23009ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (12.482528ms) +✔ both arbiters require human resolution when their cross-role route is themselves (19.85656ms) +✔ systemVars flattens the validated config (3.10758ms) +✔ precedence: system, business, project, project role, agent (8.111606ms) +✔ limits narrow the definition and never widen it (4.340763ms) +✔ role.launch stays within-role only for the instance the launch block names (7.7091ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (4.788773ms) +✖ limits.authority narrows cross-role actions too (4.913175ms) +✔ classify (2.31828ms) +✔ the record carries what the broker and launcher need (1.866404ms) +✔ digest: key order doesn't matter, any value change does (11.152959ms) +✔ refusals (4.229422ms) +✔ the four shipped version 2 roles load (4.850962ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.823772ms) +✔ shipped authority follows the note's table (0.832213ms) +✔ version 1 files keep loading with no authority (1.502179ms) +✔ the conductor policy isn't a role (0.338784ms) +✔ a missing role file is exit 4, a symbolic link too (0.574289ms) +✔ version 2 refusals (1.813974ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (3.519361ms) +✔ credentials: Gitea scopes (1.479096ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.986778ms) +✔ credentials: services (0.824537ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.067344ms) +✔ the PM gets launch, its task verbs and the reads (12.570361ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (4.699967ms) +✔ launch only when the business's launch block names the instance as launcher (3.180079ms) +✖ an action outside the instance's authority has no tool (6.26463ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (16.396169ms) +✔ task.create needs a recorded human request and a requirement id (68.567729ms) +✔ only labels named in the business file can be written (37.772712ms) +✔ task.schedule sets and clears a due date and relations (42.822471ms) +✔ assign and reassign move the role bots and record task.assigned (65.432289ms) +✔ task.update.assigned is for the assignee and records task.state (62.852511ms) +✔ a wrong expected digest records task.conflict and writes nothing (28.459203ms) +✔ a cross-role verb needs a resolved decision, used once (28.527583ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (28.982719ms) +✔ a lost answer is settled by a re-read and never retried (30.392592ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (38.949964ms) +✔ a task the sync bot cannot read refuses and records nothing (25.968994ms) +✔ verbs and polls for one business run one at a time (99.920681ms) +✔ a due date with milliseconds is written to the second (69.877437ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (40.473302ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (16.49068ms) +✔ a create whose final read fails succeeds and records task.created (38.315534ms) +✔ an edit between the last write and the final read shows as external on the next poll (45.052755ms) +✔ task.created is recorded when a later label write fails (19.326478ms) +ℹ tests 59 +ℹ suites 0 +ℹ pass 57 +ℹ fail 2 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 943.487341 + +✖ failing tests: + +test at packages/business/tests/resolve.test.mjs:124:1 +✖ limits.authority narrows cross-role actions too (4.913175ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + { + crossRole: [ + + 'task.reassign', + 'task.scope.change' + ], + withinRole: [ + 'task.update.assigned', + 'git.push.working' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73-base/packages/business/tests/resolve.test.mjs:129:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: { withinRole: [ 'task.update.assigned', 'git.push.working' ], crossRole: [ 'task.reassign', 'task.scope.change' ] }, + expected: { withinRole: [ 'task.update.assigned', 'git.push.working' ], crossRole: [ 'task.scope.change' ] }, + operator: 'deepStrictEqual', + diff: 'simple' + } + +test at packages/harness/tests/tools.test.mjs:44:1 +✖ an action outside the instance's authority has no tool (6.26463ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + [ + + 'task_reassign', + + 'task_scope_change', + 'raise_decision', + 'list_agents', + 'inbox', + 'trail', + 'list_tasks' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73-base/packages/harness/tests/tools.test.mjs:46:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [ 'task_reassign', 'task_scope_change', 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + expected: [ 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/rocko/work/queue-73/out/mutants-base/tools-all-task-verbs.diff b/agents/rocko/work/queue-73/out/mutants-base/tools-all-task-verbs.diff new file mode 100644 index 000000000..a67cdc1f4 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/tools-all-task-verbs.diff @@ -0,0 +1,11 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-base/orig 2026-10-11 18:09:25.821593099 -0500 ++++ packages/harness/src/tools.mjs 2026-10-11 18:09:30.532803215 -0500 +@@ -89,7 +89,7 @@ + } + if (tracker) { + for (const [action, [name, description, properties, required]] of Object.entries(TASK_TOOLS)) { +- if (held.has(action)) add(name, action, action, description, obj(properties, required)); ++ add(name, action, action, description, obj(properties, required)); + } + } + add("raise_decision", "decision.raise", null, "Ask for a decision before a gated or cross-role action, or when you need a choice made. The answer arrives as a message.", obj({ diff --git a/agents/rocko/work/queue-73/out/mutants-base/tools-all-task-verbs.log b/agents/rocko/work/queue-73/out/mutants-base/tools-all-task-verbs.log new file mode 100644 index 000000000..63e038c14 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-base/tools-all-task-verbs.log @@ -0,0 +1,104 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (68.304242ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (36.220226ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (28.451192ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (17.620543ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (17.134783ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (17.523052ms) +✔ task action subjects and linked decision trail are complete and ordered (28.196094ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (11.654167ms) +✔ business isolation includes inherited object names and cross-business message references (17.773328ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (63.640909ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (30.76888ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (72.884982ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (38.656622ms) +✔ both arbiters require human resolution when their cross-role route is themselves (86.595811ms) +✔ systemVars flattens the validated config (3.418009ms) +✔ precedence: system, business, project, project role, agent (15.12961ms) +✔ limits narrow the definition and never widen it (32.983425ms) +✔ role.launch stays within-role only for the instance the launch block names (11.91897ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (2.882384ms) +✔ limits.authority narrows cross-role actions too (3.171349ms) +✔ classify (3.090892ms) +✔ the record carries what the broker and launcher need (2.902871ms) +✔ digest: key order doesn't matter, any value change does (14.329947ms) +✔ refusals (3.553461ms) +✔ the four shipped version 2 roles load (6.936567ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.580417ms) +✔ shipped authority follows the note's table (10.829435ms) +✔ version 1 files keep loading with no authority (1.892986ms) +✔ the conductor policy isn't a role (0.383968ms) +✔ a missing role file is exit 4, a symbolic link too (0.600117ms) +✔ version 2 refusals (1.966349ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (4.284811ms) +✔ credentials: Gitea scopes (1.537433ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.912443ms) +✔ credentials: services (1.044154ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.05934ms) +✔ the PM gets launch, its task verbs and the reads (12.754906ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (4.823918ms) +✔ launch only when the business's launch block names the instance as launcher (3.337282ms) +✖ an action outside the instance's authority has no tool (6.565686ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (19.618993ms) +✔ task.create needs a recorded human request and a requirement id (57.310658ms) +✔ only labels named in the business file can be written (37.756552ms) +✔ task.schedule sets and clears a due date and relations (44.948474ms) +✔ assign and reassign move the role bots and record task.assigned (133.26048ms) +✔ task.update.assigned is for the assignee and records task.state (149.616551ms) +✔ a wrong expected digest records task.conflict and writes nothing (60.89642ms) +✔ a cross-role verb needs a resolved decision, used once (61.058916ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (43.717227ms) +✔ a lost answer is settled by a re-read and never retried (60.615688ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (50.786839ms) +✔ a task the sync bot cannot read refuses and records nothing (33.128318ms) +✔ verbs and polls for one business run one at a time (106.542625ms) +✔ a due date with milliseconds is written to the second (89.23896ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (52.735737ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (38.534275ms) +✔ a create whose final read fails succeeds and records task.created (48.772964ms) +✔ an edit between the last write and the final read shows as external on the next poll (64.248179ms) +✔ task.created is recorded when a later label write fails (23.685508ms) +ℹ tests 59 +ℹ suites 0 +ℹ pass 58 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 1367.254328 + +✖ failing tests: + +test at packages/harness/tests/tools.test.mjs:44:1 +✖ an action outside the instance's authority has no tool (6.565686ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + [ + + 'task_create', + + 'task_assign', + + 'task_reassign', + + 'task_schedule', + + 'task_priority_change', + + 'task_scope_change', + + 'task_update_assigned', + + 'task_close', + 'raise_decision', + 'list_agents', + 'inbox', + 'trail', + 'list_tasks' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73-base/packages/harness/tests/tools.test.mjs:46:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [ 'task_create', 'task_assign', 'task_reassign', 'task_schedule', 'task_priority_change', 'task_scope_change', 'task_update_assigned', 'task_close', 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + expected: [ 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/rocko/work/queue-73/out/mutants-candidate.txt b/agents/rocko/work/queue-73/out/mutants-candidate.txt new file mode 100644 index 000000000..6efae2c74 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate.txt @@ -0,0 +1,6 @@ +baseline: pass +role-keeps-reassign: killed (✖ a coder with a tracker gets its own task tools and no task_reassign;✖ classify;✖ shipped authority follows the note's table;✖ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role;) +broker-unlisted-cross: killed (✖ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role;) +resolve-cross-unnarrowed: killed (✖ an action outside the instance's authority has no tool;✖ limits.authority narrows cross-role actions too;) +classify-unlisted-cross: killed (✖ classify;✖ limits.authority narrows cross-role actions too;✖ limits.authority without role.launch leaves the launcher with no launch block;✖ limits narrow the definition and never widen it;✖ role.launch stays within-role only for the instance the launch block names;) +tools-all-task-verbs: killed (✖ a coder with a tracker gets its own task tools and no task_reassign;✖ an action outside the instance's authority has no tool;) diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/baseline.log b/agents/rocko/work/queue-73/out/mutants-candidate/baseline.log new file mode 100644 index 000000000..5ecd3b74a --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/baseline.log @@ -0,0 +1,69 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (22.59035ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (26.760387ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (25.941999ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (14.175334ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (18.000242ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (17.704479ms) +✔ task action subjects and linked decision trail are complete and ordered (27.462393ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (11.228427ms) +✔ business isolation includes inherited object names and cross-business message references (18.813263ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (22.467431ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (10.563551ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (15.243023ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (13.037666ms) +✔ both arbiters require human resolution when their cross-role route is themselves (24.729793ms) +✔ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (19.098206ms) +✔ systemVars flattens the validated config (1.823722ms) +✔ precedence: system, business, project, project role, agent (7.082391ms) +✔ limits narrow the definition and never widen it (4.101089ms) +✔ role.launch stays within-role only for the instance the launch block names (7.044571ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (3.176026ms) +✔ limits.authority narrows cross-role actions too (3.958115ms) +✔ classify (1.566137ms) +✔ the record carries what the broker and launcher need (1.679601ms) +✔ digest: key order doesn't matter, any value change does (9.40251ms) +✔ refusals (3.314557ms) +✔ the four shipped version 2 roles load (4.562073ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.373138ms) +✔ shipped authority follows the note's table (0.880774ms) +✔ version 1 files keep loading with no authority (1.340018ms) +✔ the conductor policy isn't a role (0.294463ms) +✔ a missing role file is exit 4, a symbolic link too (0.573454ms) +✔ version 2 refusals (2.142424ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (2.806218ms) +✔ credentials: Gitea scopes (1.390039ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.74487ms) +✔ credentials: services (1.066435ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.503718ms) +✔ the PM gets launch, its task verbs and the reads (7.458116ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (2.543347ms) +✔ a coder with a tracker gets its own task tools and no task_reassign (2.204646ms) +✔ launch only when the business's launch block names the instance as launcher (1.84137ms) +✔ an action outside the instance's authority has no tool (2.443015ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (11.834983ms) +✔ task.create needs a recorded human request and a requirement id (52.551332ms) +✔ only labels named in the business file can be written (36.191609ms) +✔ task.schedule sets and clears a due date and relations (42.137434ms) +✔ assign and reassign move the role bots and record task.assigned (61.839072ms) +✔ task.update.assigned is for the assignee and records task.state (64.945829ms) +✔ a wrong expected digest records task.conflict and writes nothing (26.65454ms) +✔ a cross-role verb needs a resolved decision, used once (33.944638ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (33.109479ms) +✔ a lost answer is settled by a re-read and never retried (34.373385ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (39.628552ms) +✔ a task the sync bot cannot read refuses and records nothing (18.56014ms) +✔ verbs and polls for one business run one at a time (99.689243ms) +✔ a due date with milliseconds is written to the second (72.921801ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (43.896182ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (18.194316ms) +✔ a create whose final read fails succeeds and records task.created (39.258208ms) +✔ an edit between the last write and the final read shows as external on the next poll (42.888728ms) +✔ task.created is recorded when a later label write fails (17.415777ms) +ℹ tests 61 +ℹ suites 0 +ℹ pass 61 +ℹ fail 0 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 906.528938 diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/broker-unlisted-cross.diff b/agents/rocko/work/queue-73/out/mutants-candidate/broker-unlisted-cross.diff new file mode 100644 index 000000000..be576a401 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/broker-unlisted-cross.diff @@ -0,0 +1,11 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-candidate/orig 2026-10-11 18:07:23.086216318 -0500 ++++ packages/bus/src/broker.mjs 2026-10-11 18:14:56.826892306 -0500 +@@ -274,7 +274,7 @@ + ? 'within-role' + : a?.crossRole.includes(action) + ? 'cross-role' +- : 'gated'; ++ : 'cross-role'; + } + #decision(s, id) { + const d = this.#store.get('SELECT * FROM decisions WHERE id=? AND business=?', id, s.business); diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/broker-unlisted-cross.log b/agents/rocko/work/queue-73/out/mutants-candidate/broker-unlisted-cross.log new file mode 100644 index 000000000..35622fbbf --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/broker-unlisted-cross.log @@ -0,0 +1,94 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (28.422584ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (25.633236ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (21.236303ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (14.292941ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (16.245186ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (14.466042ms) +✔ task action subjects and linked decision trail are complete and ordered (24.311959ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (9.415662ms) +✔ business isolation includes inherited object names and cross-business message references (17.125506ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (20.297014ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (11.125627ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (17.296304ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (11.986569ms) +✔ both arbiters require human resolution when their cross-role route is themselves (19.617388ms) +✖ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (18.46808ms) +✔ systemVars flattens the validated config (3.618153ms) +✔ precedence: system, business, project, project role, agent (7.398492ms) +✔ limits narrow the definition and never widen it (3.541406ms) +✔ role.launch stays within-role only for the instance the launch block names (7.555402ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (3.395477ms) +✔ limits.authority narrows cross-role actions too (1.804949ms) +✔ classify (2.023344ms) +✔ the record carries what the broker and launcher need (1.416391ms) +✔ digest: key order doesn't matter, any value change does (7.582607ms) +✔ refusals (6.552895ms) +✔ the four shipped version 2 roles load (3.303484ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.217421ms) +✔ shipped authority follows the note's table (0.789951ms) +✔ version 1 files keep loading with no authority (1.087748ms) +✔ the conductor policy isn't a role (0.215847ms) +✔ a missing role file is exit 4, a symbolic link too (0.407959ms) +✔ version 2 refusals (1.339954ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (2.502025ms) +✔ credentials: Gitea scopes (1.02232ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.91448ms) +✔ credentials: services (0.677159ms) +✔ contract: a non-empty regular Markdown file beside the role file (0.758295ms) +✔ the PM gets launch, its task verbs and the reads (7.934889ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (2.113216ms) +✔ a coder with a tracker gets its own task tools and no task_reassign (1.793071ms) +✔ launch only when the business's launch block names the instance as launcher (1.614854ms) +✔ an action outside the instance's authority has no tool (4.100632ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (10.303855ms) +✔ task.create needs a recorded human request and a requirement id (43.05711ms) +✔ only labels named in the business file can be written (27.611979ms) +✔ task.schedule sets and clears a due date and relations (39.061519ms) +✔ assign and reassign move the role bots and record task.assigned (62.22098ms) +✔ task.update.assigned is for the assignee and records task.state (55.970065ms) +✔ a wrong expected digest records task.conflict and writes nothing (25.10594ms) +✔ a cross-role verb needs a resolved decision, used once (27.276288ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (27.716914ms) +✔ a lost answer is settled by a re-read and never retried (29.052452ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (39.47631ms) +✔ a task the sync bot cannot read refuses and records nothing (20.196553ms) +✔ verbs and polls for one business run one at a time (92.77395ms) +✔ a due date with milliseconds is written to the second (67.659021ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (39.62171ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (16.201161ms) +✔ a create whose final read fails succeeds and records task.created (35.582005ms) +✔ an edit between the last write and the final read shows as external on the next poll (44.800687ms) +✔ task.created is recorded when a later label write fails (15.946503ms) +ℹ tests 61 +ℹ suites 0 +ℹ pass 60 +ℹ fail 1 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 829.410177 + +✖ failing tests: + +test at packages/bus/tests/broker.test.mjs:361:1 +✖ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (18.46808ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + actual - expected + + + 'cross-role' + - 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/bus/tests/broker.test.mjs:374:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross-role', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/classify-unlisted-cross.diff b/agents/rocko/work/queue-73/out/mutants-candidate/classify-unlisted-cross.diff new file mode 100644 index 000000000..1ca1bd35d --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/classify-unlisted-cross.diff @@ -0,0 +1,9 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-candidate/orig 2026-10-11 18:07:23.087807382 -0500 ++++ packages/business/src/resolve.mjs 2026-10-11 18:14:58.604372993 -0500 +@@ -100,5 +100,5 @@ + if (!ACTIONS.includes(action)) refuse(`unknown action: ${JSON.stringify(action)}`); + if (resolved.limits.authority.withinRole.includes(action)) return "within"; + if (resolved.limits.authority.crossRole.includes(action)) return "cross"; +- return "gated"; ++ return "cross"; + } diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/classify-unlisted-cross.log b/agents/rocko/work/queue-73/out/mutants-candidate/classify-unlisted-cross.log new file mode 100644 index 000000000..7545a7a94 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/classify-unlisted-cross.log @@ -0,0 +1,176 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (32.115093ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (20.806345ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (20.504225ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (15.031318ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (13.795536ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (12.743478ms) +✔ task action subjects and linked decision trail are complete and ordered (20.909183ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (11.281359ms) +✔ business isolation includes inherited object names and cross-business message references (14.550486ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (18.52182ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (11.841502ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (16.416647ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (10.122398ms) +✔ both arbiters require human resolution when their cross-role route is themselves (18.177921ms) +✔ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (16.866523ms) +✔ systemVars flattens the validated config (2.898361ms) +✔ precedence: system, business, project, project role, agent (7.459935ms) +✖ limits narrow the definition and never widen it (4.478519ms) +✖ role.launch stays within-role only for the instance the launch block names (5.021168ms) +✖ limits.authority without role.launch leaves the launcher with no launch block (1.627639ms) +✖ limits.authority narrows cross-role actions too (1.276774ms) +✖ classify (1.320238ms) +✔ the record carries what the broker and launcher need (1.382509ms) +✔ digest: key order doesn't matter, any value change does (7.774975ms) +✔ refusals (2.214875ms) +✔ the four shipped version 2 roles load (3.34149ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.017705ms) +✔ shipped authority follows the note's table (0.534057ms) +✔ version 1 files keep loading with no authority (0.917276ms) +✔ the conductor policy isn't a role (0.211232ms) +✔ a missing role file is exit 4, a symbolic link too (0.388821ms) +✔ version 2 refusals (1.302921ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (2.052877ms) +✔ credentials: Gitea scopes (0.840766ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.03215ms) +✔ credentials: services (0.560366ms) +✔ contract: a non-empty regular Markdown file beside the role file (0.659056ms) +✔ the PM gets launch, its task verbs and the reads (7.878729ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (2.195081ms) +✔ a coder with a tracker gets its own task tools and no task_reassign (1.922068ms) +✔ launch only when the business's launch block names the instance as launcher (1.571719ms) +✔ an action outside the instance's authority has no tool (2.458934ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (10.132477ms) +✔ task.create needs a recorded human request and a requirement id (42.270988ms) +✔ only labels named in the business file can be written (28.695884ms) +✔ task.schedule sets and clears a due date and relations (35.181345ms) +✔ assign and reassign move the role bots and record task.assigned (55.663835ms) +✔ task.update.assigned is for the assignee and records task.state (55.137406ms) +✔ a wrong expected digest records task.conflict and writes nothing (21.171762ms) +✔ a cross-role verb needs a resolved decision, used once (27.361206ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (28.545856ms) +✔ a lost answer is settled by a re-read and never retried (30.01709ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (37.911184ms) +✔ a task the sync bot cannot read refuses and records nothing (18.605202ms) +✔ verbs and polls for one business run one at a time (93.947085ms) +✔ a due date with milliseconds is written to the second (72.13725ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (45.828384ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (24.061498ms) +✔ a create whose final read fails succeeds and records task.created (47.741873ms) +✔ an edit between the last write and the final read shows as external on the next poll (43.688712ms) +✔ task.created is recorded when a later label write fails (19.256173ms) +ℹ tests 61 +ℹ suites 0 +ℹ pass 56 +ℹ fail 5 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 843.294318 + +✖ failing tests: + +test at packages/business/tests/resolve.test.mjs:69:1 +✖ limits narrow the definition and never widen it (4.478519ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/business/tests/resolve.test.mjs:87:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:91:1 +✖ role.launch stays within-role only for the instance the launch block names (5.021168ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/business/tests/resolve.test.mjs:98:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:112:1 +✖ limits.authority without role.launch leaves the launcher with no launch block (1.627639ms) + AssertionError [ERR_ASSERTION]: agent + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/business/tests/resolve.test.mjs:119:12) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: false, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:124:1 +✖ limits.authority narrows cross-role actions too (1.276774ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/business/tests/resolve.test.mjs:132:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:136:1 +✖ classify (1.320238ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/business/tests/resolve.test.mjs:141:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/resolve-cross-unnarrowed.diff b/agents/rocko/work/queue-73/out/mutants-candidate/resolve-cross-unnarrowed.diff new file mode 100644 index 000000000..c187eaa7a --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/resolve-cross-unnarrowed.diff @@ -0,0 +1,11 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-candidate/orig 2026-10-11 18:07:23.087807382 -0500 ++++ packages/business/src/resolve.mjs 2026-10-11 18:14:57.707967161 -0500 +@@ -65,7 +65,7 @@ + if (vars["limits.network"]) network = narrowerNetwork(network, vars["limits.network"]); + if (vars["limits.authority"]) { + withinRole = withinRole.filter((a) => vars["limits.authority"].includes(a)); +- crossRole = crossRole.filter((a) => vars["limits.authority"].includes(a)); ++ crossRole = [...crossRole]; + } + // role.launch needs the business file's launch block naming this + // instance (addendum A section 8), and the verb must survive diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/resolve-cross-unnarrowed.log b/agents/rocko/work/queue-73/out/mutants-candidate/resolve-cross-unnarrowed.log new file mode 100644 index 000000000..37e409e5b --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/resolve-cross-unnarrowed.log @@ -0,0 +1,129 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (33.103276ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (28.078672ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (23.400199ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (16.425704ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (12.498957ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (12.625172ms) +✔ task action subjects and linked decision trail are complete and ordered (23.3379ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (8.693012ms) +✔ business isolation includes inherited object names and cross-business message references (19.263813ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (21.458088ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (9.875642ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (17.784604ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (11.20225ms) +✔ both arbiters require human resolution when their cross-role route is themselves (18.979522ms) +✔ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (16.746697ms) +✔ systemVars flattens the validated config (3.032988ms) +✔ precedence: system, business, project, project role, agent (7.573478ms) +✔ limits narrow the definition and never widen it (3.723962ms) +✔ role.launch stays within-role only for the instance the launch block names (7.177622ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (3.083517ms) +✖ limits.authority narrows cross-role actions too (2.477071ms) +✔ classify (1.655321ms) +✔ the record carries what the broker and launcher need (1.756283ms) +✔ digest: key order doesn't matter, any value change does (8.241698ms) +✔ refusals (3.408223ms) +✔ the four shipped version 2 roles load (4.389377ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.557139ms) +✔ shipped authority follows the note's table (0.924885ms) +✔ version 1 files keep loading with no authority (1.425297ms) +✔ the conductor policy isn't a role (0.314017ms) +✔ a missing role file is exit 4, a symbolic link too (0.622313ms) +✔ version 2 refusals (2.290655ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (3.899517ms) +✔ credentials: Gitea scopes (1.46446ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.844948ms) +✔ credentials: services (0.874648ms) +✔ contract: a non-empty regular Markdown file beside the role file (0.942239ms) +✔ the PM gets launch, its task verbs and the reads (10.058394ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.002875ms) +✔ a coder with a tracker gets its own task tools and no task_reassign (2.268428ms) +✔ launch only when the business's launch block names the instance as launcher (1.651138ms) +✖ an action outside the instance's authority has no tool (4.595551ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (10.307219ms) +✔ task.create needs a recorded human request and a requirement id (50.783873ms) +✔ only labels named in the business file can be written (27.907976ms) +✔ task.schedule sets and clears a due date and relations (33.79153ms) +✔ assign and reassign move the role bots and record task.assigned (61.7935ms) +✔ task.update.assigned is for the assignee and records task.state (54.786754ms) +✔ a wrong expected digest records task.conflict and writes nothing (21.537052ms) +✔ a cross-role verb needs a resolved decision, used once (25.702853ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (25.182622ms) +✔ a lost answer is settled by a re-read and never retried (28.600271ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (39.54527ms) +✔ a task the sync bot cannot read refuses and records nothing (16.765549ms) +✔ verbs and polls for one business run one at a time (89.463681ms) +✔ a due date with milliseconds is written to the second (66.833039ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (64.467321ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (23.033961ms) +✔ a create whose final read fails succeeds and records task.created (36.136121ms) +✔ an edit between the last write and the final read shows as external on the next poll (39.918485ms) +✔ task.created is recorded when a later label write fails (13.988664ms) +ℹ tests 61 +ℹ suites 0 +ℹ pass 59 +ℹ fail 2 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 852.228915 + +✖ failing tests: + +test at packages/business/tests/resolve.test.mjs:124:1 +✖ limits.authority narrows cross-role actions too (2.477071ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + { + crossRole: [ + 'task.priority.change', + + 'task.scope.change' + ], + withinRole: [ + 'task.create', + 'task.close' + ] + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/business/tests/resolve.test.mjs:130:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: { withinRole: [ 'task.create', 'task.close' ], crossRole: [ 'task.priority.change', 'task.scope.change' ] }, + expected: { withinRole: [ 'task.create', 'task.close' ], crossRole: [ 'task.priority.change' ] }, + operator: 'deepStrictEqual', + diff: 'simple' + } + +test at packages/harness/tests/tools.test.mjs:52:1 +✖ an action outside the instance's authority has no tool (4.595551ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + [ + + 'task_scope_change', + 'raise_decision', + 'list_agents', + 'inbox', + 'trail', + 'list_tasks' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/harness/tests/tools.test.mjs:54:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [ 'task_scope_change', 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + expected: [ 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/role-keeps-reassign.diff b/agents/rocko/work/queue-73/out/mutants-candidate/role-keeps-reassign.diff new file mode 100644 index 000000000..6ff8920ed --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/role-keeps-reassign.diff @@ -0,0 +1,11 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-candidate/orig 2026-10-11 18:07:39.870939784 -0500 ++++ roles/coder.json 2026-10-11 18:14:55.818223939 -0500 +@@ -7,7 +7,7 @@ + "network": "api-only", + "authority": { + "withinRole": ["task.update.assigned", "git.push.working", "review.request", "message.send"], +- "crossRole": ["task.scope.change"] ++ "crossRole": ["task.reassign", "task.scope.change"] + }, + "credentials": [ + { diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/role-keeps-reassign.log b/agents/rocko/work/queue-73/out/mutants-candidate/role-keeps-reassign.log new file mode 100644 index 000000000..17f77e118 --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/role-keeps-reassign.log @@ -0,0 +1,169 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (25.610404ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (26.850363ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (23.84385ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (12.839692ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (14.696717ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (13.166518ms) +✔ task action subjects and linked decision trail are complete and ordered (19.883322ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (10.292636ms) +✔ business isolation includes inherited object names and cross-business message references (17.143026ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (20.432048ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (9.413307ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (17.112756ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (11.689255ms) +✔ both arbiters require human resolution when their cross-role route is themselves (22.916955ms) +✖ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (25.762402ms) +✔ systemVars flattens the validated config (3.032631ms) +✔ precedence: system, business, project, project role, agent (8.016805ms) +✔ limits narrow the definition and never widen it (3.808311ms) +✔ role.launch stays within-role only for the instance the launch block names (9.313641ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (4.009638ms) +✔ limits.authority narrows cross-role actions too (1.829767ms) +✖ classify (2.894526ms) +✔ the record carries what the broker and launcher need (1.969378ms) +✔ digest: key order doesn't matter, any value change does (9.350735ms) +✔ refusals (2.563428ms) +✔ the four shipped version 2 roles load (4.282478ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.481512ms) +✖ shipped authority follows the note's table (1.731521ms) +✔ version 1 files keep loading with no authority (1.117387ms) +✔ the conductor policy isn't a role (0.251829ms) +✔ a missing role file is exit 4, a symbolic link too (0.421436ms) +✔ version 2 refusals (1.742865ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (2.625104ms) +✔ credentials: Gitea scopes (2.325317ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (2.201409ms) +✔ credentials: services (1.168802ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.325241ms) +✔ the PM gets launch, its task verbs and the reads (8.84067ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (2.555972ms) +✖ a coder with a tracker gets its own task tools and no task_reassign (3.580158ms) +✔ launch only when the business's launch block names the instance as launcher (1.736644ms) +✔ an action outside the instance's authority has no tool (3.187475ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (10.303208ms) +✔ task.create needs a recorded human request and a requirement id (47.944003ms) +✔ only labels named in the business file can be written (26.77445ms) +✔ task.schedule sets and clears a due date and relations (33.848522ms) +✔ assign and reassign move the role bots and record task.assigned (61.702775ms) +✔ task.update.assigned is for the assignee and records task.state (68.22306ms) +✔ a wrong expected digest records task.conflict and writes nothing (26.375322ms) +✔ a cross-role verb needs a resolved decision, used once (45.781054ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (58.667462ms) +✔ a lost answer is settled by a re-read and never retried (47.540574ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (48.995082ms) +✔ a task the sync bot cannot read refuses and records nothing (21.496242ms) +✔ verbs and polls for one business run one at a time (115.361345ms) +✔ a due date with milliseconds is written to the second (77.442629ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (44.709765ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (20.37596ms) +✔ a create whose final read fails succeeds and records task.created (36.039383ms) +✔ an edit between the last write and the final read shows as external on the next poll (40.908102ms) +✔ task.created is recorded when a later label write fails (16.705741ms) +ℹ tests 61 +ℹ suites 0 +ℹ pass 57 +ℹ fail 4 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 962.043519 + +✖ failing tests: + +test at packages/bus/tests/broker.test.mjs:361:1 +✖ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (25.762402ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + actual - expected + + + 'cross-role' + - 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/bus/tests/broker.test.mjs:374:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross-role', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/resolve.test.mjs:136:1 +✖ classify (2.894526ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly equal: + + 'cross' !== 'gated' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/business/tests/resolve.test.mjs:141:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: 'cross', + expected: 'gated', + operator: 'strictEqual', + diff: 'simple' + } + +test at packages/business/tests/role.test.mjs:61:1 +✖ shipped authority follows the note's table (1.731521ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + [ + + 'task.reassign', + 'task.scope.change' + ] + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/business/tests/role.test.mjs:65:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [ 'task.reassign', 'task.scope.change' ], + expected: [ 'task.scope.change' ], + operator: 'deepStrictEqual', + diff: 'simple' + } + +test at packages/harness/tests/tools.test.mjs:38:1 +✖ a coder with a tracker gets its own task tools and no task_reassign (3.580158ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + [ + 'send_message', + + 'task_reassign', + 'task_scope_change', + 'task_update_assigned', + 'raise_decision', + 'list_agents', + 'inbox', + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/harness/tests/tools.test.mjs:40:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [ 'send_message', 'task_reassign', 'task_scope_change', 'task_update_assigned', 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + expected: [ 'send_message', 'task_scope_change', 'task_update_assigned', 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/tools-all-task-verbs.diff b/agents/rocko/work/queue-73/out/mutants-candidate/tools-all-task-verbs.diff new file mode 100644 index 000000000..a18790b8a --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/tools-all-task-verbs.diff @@ -0,0 +1,11 @@ +--- /mnt/storage/scratch/rocko-r73-out/mutants-candidate/orig 2026-10-11 18:07:23.096112289 -0500 ++++ packages/harness/src/tools.mjs 2026-10-11 18:14:59.504647794 -0500 +@@ -89,7 +89,7 @@ + } + if (tracker) { + for (const [action, [name, description, properties, required]] of Object.entries(TASK_TOOLS)) { +- if (held.has(action)) add(name, action, action, description, obj(properties, required)); ++ add(name, action, action, description, obj(properties, required)); + } + } + add("raise_decision", "decision.raise", null, "Ask for a decision before a gated or cross-role action, or when you need a choice made. The answer arrives as a message.", obj({ diff --git a/agents/rocko/work/queue-73/out/mutants-candidate/tools-all-task-verbs.log b/agents/rocko/work/queue-73/out/mutants-candidate/tools-all-task-verbs.log new file mode 100644 index 000000000..e8eb463fb --- /dev/null +++ b/agents/rocko/work/queue-73/out/mutants-candidate/tools-all-task-verbs.log @@ -0,0 +1,142 @@ +✔ launch identity is stamped, payload identity is refused and stale holder cannot send (36.639909ms) +✔ decision classes route from policy; gated resolution is human-only, choice and target must match (33.673177ms) +✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (32.106496ms) +✔ launch events require a human CLI capability; generic emit cannot forge authority events (18.481664ms) +✔ within-role decisions close atomically and invalid options or blocking omissions refuse (16.132294ms) +✔ observer capabilities read human inbox but cannot mutate or forge launch identity (16.873703ms) +✔ task action subjects and linked decision trail are complete and ordered (24.302336ms) +✔ launch binding is durable and reconnecting requires the identical trusted record (10.520395ms) +✔ business isolation includes inherited object names and cross-business message references (17.798456ms) +✔ authority never transfers between action, run, target, unresolved or replaced role holder (25.213949ms) +✔ task projection uses schema current view, skipping earlier and equal-start polls (13.067758ms) +✔ revocation permanently bars the old run from reclaiming first, including after broker restart (20.466512ms) +✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (12.744716ms) +✔ both arbiters require human resolution when their cross-role route is themselves (19.443375ms) +✔ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (17.797876ms) +✔ systemVars flattens the validated config (3.526166ms) +✔ precedence: system, business, project, project role, agent (8.517006ms) +✔ limits narrow the definition and never widen it (4.025856ms) +✔ role.launch stays within-role only for the instance the launch block names (7.700117ms) +✔ limits.authority without role.launch leaves the launcher with no launch block (5.183853ms) +✔ limits.authority narrows cross-role actions too (1.75868ms) +✔ classify (2.147984ms) +✔ the record carries what the broker and launcher need (1.566134ms) +✔ digest: key order doesn't matter, any value change does (10.446916ms) +✔ refusals (3.104062ms) +✔ the four shipped version 2 roles load (5.416941ms) +✔ shipped role scopes match addendum B section 2 and the SR runbook (1.42006ms) +✔ shipped authority follows the note's table (0.78467ms) +✔ version 1 files keep loading with no authority (1.197489ms) +✔ the conductor policy isn't a role (0.278589ms) +✔ a missing role file is exit 4, a symbolic link too (0.489048ms) +✔ version 2 refusals (1.578833ms) +✔ authority: closed vocabulary, no gated-only action, no overlap (2.399299ms) +✔ credentials: Gitea scopes (1.394806ms) +✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (1.771779ms) +✔ credentials: services (1.393594ms) +✔ contract: a non-empty regular Markdown file beside the role file (1.18444ms) +✔ the PM gets launch, its task verbs and the reads (9.197271ms) +✔ a coder gets no launch, no resolve_decision, and no task tools without a tracker (3.379526ms) +✖ a coder with a tracker gets its own task tools and no task_reassign (5.596139ms) +✔ launch only when the business's launch block names the instance as launcher (3.973547ms) +✖ an action outside the instance's authority has no tool (3.762374ms) +✔ callTool: one JSON line out, the result back, a refusal rejects (15.066181ms) +✔ task.create needs a recorded human request and a requirement id (62.733557ms) +✔ only labels named in the business file can be written (34.096604ms) +✔ task.schedule sets and clears a due date and relations (44.787245ms) +✔ assign and reassign move the role bots and record task.assigned (66.206408ms) +✔ task.update.assigned is for the assignee and records task.state (57.83302ms) +✔ a wrong expected digest records task.conflict and writes nothing (26.848484ms) +✔ a cross-role verb needs a resolved decision, used once (26.339943ms) +✔ task.close needs a verdict; after it every verb refuses with task-done (30.531726ms) +✔ a lost answer is settled by a re-read and never retried (28.266487ms) +✔ a create whose answer is lost is reported uncertain, and the poll finds the task (39.805487ms) +✔ a task the sync bot cannot read refuses and records nothing (21.989204ms) +✔ verbs and polls for one business run one at a time (99.205086ms) +✔ a due date with milliseconds is written to the second (75.658928ms) +✔ every write landed and the final read failed: the verb succeeds and records what it wrote (39.315806ms) +✔ some writes landed and the final read failed: write-uncertain, and nothing is recorded (19.951694ms) +✔ a create whose final read fails succeeds and records task.created (42.258201ms) +✔ an edit between the last write and the final read shows as external on the next poll (97.83506ms) +✔ task.created is recorded when a later label write fails (26.007172ms) +ℹ tests 61 +ℹ suites 0 +ℹ pass 59 +ℹ fail 2 +ℹ cancelled 0 +ℹ skipped 0 +ℹ todo 0 +ℹ duration_ms 987.057475 + +✖ failing tests: + +test at packages/harness/tests/tools.test.mjs:38:1 +✖ a coder with a tracker gets its own task tools and no task_reassign (5.596139ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + [ + 'send_message', + + 'task_create', + + 'task_assign', + + 'task_reassign', + + 'task_schedule', + + 'task_priority_change', + 'task_scope_change', + 'task_update_assigned', + + 'task_close', + 'raise_decision', + 'list_agents', + 'inbox', + 'trail', + 'list_tasks' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/harness/tests/tools.test.mjs:40:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [ 'send_message', 'task_create', 'task_assign', 'task_reassign', 'task_schedule', 'task_priority_change', 'task_scope_change', 'task_update_assigned', 'task_close', 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + expected: [ 'send_message', 'task_scope_change', 'task_update_assigned', 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + operator: 'deepStrictEqual', + diff: 'simple' + } + +test at packages/harness/tests/tools.test.mjs:52:1 +✖ an action outside the instance's authority has no tool (3.762374ms) + AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal: + + actual - expected + + [ + + 'task_create', + + 'task_assign', + + 'task_reassign', + + 'task_schedule', + + 'task_priority_change', + + 'task_scope_change', + + 'task_update_assigned', + + 'task_close', + 'raise_decision', + 'list_agents', + 'inbox', + 'trail', + 'list_tasks' + + at TestContext. (file:///mnt/storage/scratch/rocko-r73/packages/harness/tests/tools.test.mjs:54:10) + at Test.runInAsyncScope (node:async_hooks:226:14) + at Test.run (node:internal/test_runner/test:1402:25) + at Test.processPendingSubtests (node:internal/test_runner/test:974:18) + at Test.postRun (node:internal/test_runner/test:1542:19) + at Test.run (node:internal/test_runner/test:1467:12) + at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) { + generatedMessage: true, + code: 'ERR_ASSERTION', + actual: [ 'task_create', 'task_assign', 'task_reassign', 'task_schedule', 'task_priority_change', 'task_scope_change', 'task_update_assigned', 'task_close', 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + expected: [ 'raise_decision', 'list_agents', 'inbox', 'trail', 'list_tasks' ], + operator: 'deepStrictEqual', + diff: 'simple' + } diff --git a/agents/rocko/work/queue-73/out/old-narrow-test-under-mutant.txt b/agents/rocko/work/queue-73/out/old-narrow-test-under-mutant.txt new file mode 100644 index 000000000..5db6ce228 --- /dev/null +++ b/agents/rocko/work/queue-73/out/old-narrow-test-under-mutant.txt @@ -0,0 +1,2 @@ +ℹ pass 1 +ℹ fail 0 diff --git a/agents/rocko/work/queue-73/out/pre.md5 b/agents/rocko/work/queue-73/out/pre.md5 new file mode 100644 index 000000000..941a3e9c3 --- /dev/null +++ b/agents/rocko/work/queue-73/out/pre.md5 @@ -0,0 +1,4 @@ +900b080b9d61e9aa00fd7e6aaf04d84d roles/coder.json +3773d12359d85a4ec93bcdd2c2b96101 packages/bus/src/broker.mjs +0b70de33a0391963899fa3d98613bf40 packages/business/src/resolve.mjs +e26512bb2646ce69ef9bd127ab6c6b96 packages/harness/src/tools.mjs diff --git a/agents/rocko/work/queue-73/out/probe-base.txt b/agents/rocko/work/queue-73/out/probe-base.txt new file mode 100644 index 000000000..2f0d7ca61 --- /dev/null +++ b/agents/rocko/work/queue-73/out/probe-base.txt @@ -0,0 +1,3 @@ +task.reassign class cross-role route_to pm +task.scope.change class cross-role route_to pm +coder tools with tracker: send_message,task_reassign,task_scope_change,task_update_assigned,raise_decision,list_agents,inbox,trail,list_tasks diff --git a/agents/rocko/work/queue-73/out/probe-candidate.txt b/agents/rocko/work/queue-73/out/probe-candidate.txt new file mode 100644 index 000000000..6486006d0 --- /dev/null +++ b/agents/rocko/work/queue-73/out/probe-candidate.txt @@ -0,0 +1,3 @@ +task.reassign class gated route_to human +task.scope.change class cross-role route_to pm +coder tools with tracker: send_message,task_scope_change,task_update_assigned,raise_decision,list_agents,inbox,trail,list_tasks diff --git a/agents/rocko/work/queue-73/out/probe.mjs b/agents/rocko/work/queue-73/out/probe.mjs new file mode 100644 index 000000000..77f1bb766 --- /dev/null +++ b/agents/rocko/work/queue-73/out/probe.mjs @@ -0,0 +1,27 @@ +// Probe: what the broker and harness do today with the shipped coder role. +import { mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +const tree = process.argv[2]; +const { Store } = await import(join(tree, 'packages/bus/src/store.mjs')); +const { Broker } = await import(join(tree, 'packages/bus/src/broker.mjs')); +const { busBusiness } = await import(join(tree, 'packages/bus/src/business.mjs')); +const { validateBusinessDocument, resolveInstance } = await import(join(tree, 'packages/business/src/index.mjs')); +const { businessDoc, REPO_ROLES, systemFor } = await import(join(tree, 'packages/business/tests/helpers.mjs')); +const { typedTools } = await import(join(tree, 'packages/harness/src/tools.mjs')); +const root = mkdtempSync(join(tmpdir(), 'r73-probe-')); +try { + const business = validateBusinessDocument(businessDoc(root, 'demo'), join(root, 'businesses', 'demo.json'), { rolesDir: REPO_ROLES }); + const resolved = Object.fromEntries(Object.keys(business.roles).map((i) => [i, resolveInstance({ system: systemFor(root), business, instance: i })])); + const store = new Store(root); + const b = new Broker({ store, businesses: { demo: busBusiness(business, resolved) } }); + const c = b.bindLaunch({ business: 'demo', role: 'coder', run: 'coder-run', harness: 'pi', address: 'coder-run' }); + b.request(c, { verb: 'role.claim', args: {} }); + const options = [{ key: 'yes', text: 'Allow' }, { key: 'no', text: 'Decline' }]; + for (const action of ['task.reassign', 'task.scope.change']) { + const d = b.request(c, { verb: 'decision.raise', args: { action, question: 'Allow?', options, recommendation: 'no', blocking: false } }); + console.log(action, 'class', d.class, 'route_to', d.route_to); + } + console.log('coder tools with tracker:', typedTools({ resolved: resolved.coder, tracker: true }).map((t) => t.name).join(',')); + store.close(); +} finally { rmSync(root, { recursive: true, force: true }); } diff --git a/agents/rocko/work/queue-73/packet-manifest.sha256 b/agents/rocko/work/queue-73/packet-manifest.sha256 new file mode 100644 index 000000000..6c081668e --- /dev/null +++ b/agents/rocko/work/queue-73/packet-manifest.sha256 @@ -0,0 +1,53 @@ +a101b9dc7a08d79018dd8c6ac77dcf451901b0b8910de1a792367cf1f4a35b1a ./base.txt +57e963e58c1f17fb0cb8cbf008ba5e305fc4555d4f0696723c85edc7871f8256 ./BUILD.md +63db27a4bd80eec09da09c1a3b7de7977d096447de313b2f42de5c60efbeeb60 ./build.patch +bf4e5ed646301d06617004770aaaf9599e743f1e00d226f8a9e0c2450f12710d ./candidate-manifest.sha256 +516fbe81e33a9d44351758deca7d18d580a7a1d640510ec2941906ed277bdadd ./files.txt +e3300acd1f85f7c7c495dc2228ec904c0af992f9ea09693adcf3e5b1121d5f83 ./mutants.sh +f8b54deb8f32f8c420ed5a503d4623e89bee762ff2af5ce74185b1fc9809024b ./out/gate/business.log +b364089f6df19de5086c1c15258696fd9a719cfcbb672ec5d504a065fc01178e ./out/gate/bus.log +bbbf01cda98f6710f35e48a0ed93277b98b010bfa27d7bad1c13d46d40ea4bd4 ./out/gate/cli.log +cb7eb33230c15549e0d6cccf84125db76c4f08a420da585560d4d2cea3fc3935 ./out/gate/end.txt +0eb63fc07e1e77a362a26513b46be8fd77547c033082b4ce969c4819cd4b9898 ./out/gate/harness.log +84dfcd7429af68d3c9e1cff2044dc3c8a33524931333f6b6c7842107c1809058 ./out/gate/seat.log +bb11ccdba6113bd6441edffadbfc31889ad31a8ae5a1b7730efd76479f70a0f5 ./out/gate.sh +f594c4c232b18e1c5e943a5bbe0776c34768a850923ee6d796f1bcc6cd81ca3b ./out/gate/start.txt +9c18698db3974473d3f5c4adf65d959050c9dcc356daff8a307274fb7274be53 ./out/gate/summary.txt +afefb840318fad067fd0080e65559080c09e2e58d3bd6bdd95ce1133cbe4954d ./out/gate/tasks.log +f91fc95a173339137f981e24fbf630acfde957e32c3cd71e28304532083c6a77 ./out/gate/test-auth.log +e1206366f07f3d9029530dcdcb55c0282d3f052adc60fc7fd51642d5d4ec3600 ./out/gate/test-conductor.log +52d211444489ea729dafc3c9745d4474d9dfd50f41055cbad792424197f04073 ./out/gate/test-config.log +7d5016ded1994048642f8b9ae845e52e8af4a069ba05c056c8f580a4589bacbe ./out/gate/test-discord.log +1ae08907ecdf1fa939b6f051b22d28462086a9d9f0f76c2d35b9ba2b21132e27 ./out/gate/test-extension-package.log +83dfaa21c4e4ad941088efab3f69e87ebd2f6bd3cc72ede938e21dc06da8a34f ./out/gate/test-foundation.log +b413b13dda4ccebcf63dd3d5958e0d6cdfcacc124a8f478b712bccc8c69ffd52 ./out/gate/test-queue.log +fa832794ee35025fb4559d58d01a270f6bff2eb65e863e9075b797f47fa68545 ./out/gate/test-release.log +ccea37f4ffde1f160dcd1a1864988083a645d974e892065c956b338d0f8c853a ./out/gate/test-task.log +025ce7565cacda5a0e84d23a87ee040eeca76605178a9da0344f1de85ed51284 ./out/gate/webui.log +405f17ea5490a22cd8175ad3d70383a0c7df6a9e9f4b8a0a773117bf97a1a667 ./out/mutants-base/baseline.log +c473c06ab442b60be7352c16b42de590c32d981f666b32c8bca8a7ca57fc37eb ./out/mutants-base/broker-unlisted-cross.diff +92c8cf650edd7ec6d7fdbe456b28e6d2cb1c99b5e9bf772a4468db91d2e2e5ff ./out/mutants-base/broker-unlisted-cross.log +98b872bc68686436afa6024a4a86466dfaefa0eebd24eef583248dab2fdd52a7 ./out/mutants-base/classify-unlisted-cross.diff +5b48e8dc706edc1df9a93471aca575efc4cadca283c5acfe0dc3c6d332d74b0c ./out/mutants-base/classify-unlisted-cross.log +149190c6f27c506716dbb90df1edd4872ad44c58b78cc77f4a0cf40e9d5e2e8b ./out/mutants-base/resolve-cross-unnarrowed.diff +5edaee8eba9467a5f9c78fcf55c13dff593412e20d44f2a85638035775335adb ./out/mutants-base/resolve-cross-unnarrowed.log +4fbcfbcd1a3b2307e1e3fc0ff4bcf1ffa3e90e6c600257a99c93aeeb9719b722 ./out/mutants-base/tools-all-task-verbs.diff +6c92f1d4b6e77ac5a2cb9c5a744a0c49d068b6fe0367716fd2529e553c70a8c3 ./out/mutants-base/tools-all-task-verbs.log +4ecd1ba8a8515846f15fe3af3ade57b5e04abb758f05d50a52e3c54f25c971f1 ./out/mutants-base.txt +a410b4ab2f7718bf7dc424f4fa3394ab9f59f70e396acd4dbd54a5933d3b2e53 ./out/mutants-candidate/baseline.log +cc6be3793b2e5e77dde9adaeda87d73153c2e5286a6582b26f8ca54699a7a1a9 ./out/mutants-candidate/broker-unlisted-cross.diff +f8d26304746eeeec72dd4b7f0e4bfa34a9b393156dd89ae0cc4df338bfe27774 ./out/mutants-candidate/broker-unlisted-cross.log +61e5bf405c309604799f1bfa3a87c04c5900673a55891c80a8859a8357985212 ./out/mutants-candidate/classify-unlisted-cross.diff +500f3837c9bea02e2228a8ade0f143649225ff6854d3d9468c9b4dddb50ffd92 ./out/mutants-candidate/classify-unlisted-cross.log +2bb9f2a49ec99852ce2c7ed19e6f01fc061c0f1a1a0aaa9e4a8f7469c41efe29 ./out/mutants-candidate/resolve-cross-unnarrowed.diff +9a7aadcaa01dc7b92d4180f4cd6a9ae266cfbcf4f7b49c4854b2dc13f06e0986 ./out/mutants-candidate/resolve-cross-unnarrowed.log +ca8f11dedc9de9bda0ea127548680b9c8cbdd0d8a9bf9352b0a42ff37f686f0c ./out/mutants-candidate/role-keeps-reassign.diff +96d653c7368821d451fae7cf57ea2bf005b4ab542e1a3d1c27294fe832b58c2f ./out/mutants-candidate/role-keeps-reassign.log +c3d83cbbb17b3bd788089610b3ee440f2c7e8124a4a8032e4f475e48d030ca55 ./out/mutants-candidate/tools-all-task-verbs.diff +75a35b18ea42f629fb45e620703c6647eff0e3efaf6968739e5d66ef718e40c7 ./out/mutants-candidate/tools-all-task-verbs.log +60d077be2cfad3dc9c365a0701b535b48cbaea5a87def47832992aa1f4138481 ./out/mutants-candidate.txt +719ccf9999d00adaaab22be5247a231e84d1e3077f9b8687c09caf4ab7bf63aa ./out/old-narrow-test-under-mutant.txt +82479aa50e513a3c764d3364298ddb1a3d148c38e32942de3f0f91c7c8df874b ./out/pre.md5 +42475e9e7238f9daa54b54c1d37512ca172116918c48150ec6abc86047d7aa62 ./out/probe-base.txt +ae7e5be038f5b5db667bb7f4d08a00e6b1d5827c8024857ac642a8b1f8128452 ./out/probe-candidate.txt +3d44b91cd0e2b40e935812b35c41ef40df5e267e517f51af217ab38feb8507e1 ./out/probe.mjs diff --git a/docs/SESSIONS.md b/docs/SESSIONS.md index 914e4c112..38922b831 100644 --- a/docs/SESSIONS.md +++ b/docs/SESSIONS.md @@ -687,3 +687,5 @@ are never rewritten or removed; corrections are new entries. - 2026-10-11T23:06:07Z, Sage (lead): row 72 (#1566) round 1. I posted the review request as jarvis for Rocko, comment 27454 (revs 527-528), and committed Rocko's packet (candidate e6531a53) with their revs 524-526 and their BUILD-LOG and SESSIONS appends. Reviewer: Filbert. Also row 74 goes to round 2 for Filbert's and Darkwing's sign-in findings (notes revs 521, 523); and 166cba45, my queue-commit with subject 'x', was rewritten locally with the same tree as ebd90554 before any push. 2026-10-11T23:12:50Z | filbert | row 72 (#1566) round 1 review, Claude pin tests | approve, comment 27460, rev 529 in 0a4b7a4e; Rocko's 6 mutants killed (all survive on base), 7 of my 8 extra killed; N1 the default path skips no test of the checks (non-exec claude, PATH dir with a space), follow-up; cli 113, harness 58 green 2026-10-11T23:14:17Z | dewey | row 58 (#1547) round 1 review, task priority and requirement | approve, comment 27461, rev 530 in 05d9863c; 7 of my 10 mutants killed, 2 equivalent; N1 priority 0 'unset' isn't pinned in the view (priority-zero-none survives), N2 Filbert's N1 and N2 into the same follow-up; gate green on ae428a54, discord 178/0 +2026-10-11T23:17:20Z | rocko | row 73 (#1567) round 1 candidate, drop the coder task.reassign grant | in-review rev 533, request failed rev 534 (no credential, Sage to post as jarvis); packet agents/rocko/work/queue-73 uncommitted, candidate manifest bf4e5ed6, packet 41ffcd5c; 5/5 mutants killed (broker-unlisted-cross survives base); gate green; reviewer Dewey +- 2026-10-11T23:20:28Z, Sage (lead): row 73 (#1567) round 1. I posted the review request as jarvis for Rocko, comment 27467 (revs 537-538), and committed Rocko's packet (candidate bf4e5ed6, packet 41ffcd5c) with their BUILD-LOG and SESSIONS appends. Reviewer: Dewey. The three stale places Rocko named (business README example, tasks README lines 193-196, tasks live/run.mjs line 32) go to row 79 (#1573, rev 539), owner Rocko after 73, reviewer Dewey, so round 1 isn't restarted.