Files
jason.woltjeandClaude Sonnet 5.5 8a73f713cf agents: Researcher row 132 packet (#1628, end_run and change_organization harness tools)
Round 1 packet in agents/researcher/work/queue-132/: row132.patch (8 files, +162 -19) on b6a588cd2,
candidate manifest, build.md, 28 mutants killed, full gate green. No candidate change applied here.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-15 13:05:03 -05:00

8.7 KiB
Raw Permalink Blame History

Row 132 (#1628): harness tools for ending a run and changing the organization file

Seat: Researcher. Reviewer: Filbert (broker authority, no sandbox change). Gate owner: Sage. Requirements: REQ-ROLE-2, REQ-COS-1, REQ-LIMIT-1. Brief: docs/plans/2026-10-14_prd-1.2-build.md, section "Harness tools for ending a run and changing the organization file".

Base: b6a588cd2 (detached worktree). Rows 119, 120, 122 and 123 are in it. No path under packages/harness, packages/bus or packages/business changed between b6a588cd2 and canonical HEAD 4a34fb0d6 (checked with git diff --name-only; later commits are docs and queue only). row132.patch is a diff of my changes only: 8 files, +162 −19. It applies with git apply --cached --check on b6a588cd2 and round-trips to the candidate tree 85056b71653ac02634d1742d2e72e4f3588bcbbd. candidate-manifest.sha256 lists the 8 files (packages/bus/src/broker.mjs among them), file sha256 ba644f8d97cfa88175fe0157d9f77523cee7e5821ddbd676b29aae46fa73cf07. Nothing is committed in the worktree, nothing is pushed, and no live store, unit, credential or ~/.mosaic file was touched.

For the 3d re-pin window: the chief's bundle manifest

The chief of staff's bundle manifest lists both tools in typed and untyped is [], for both harnesses. Test: packages/harness/tests/bundle.test.mjs:85, "a chief-of-staff bundle lists end_run and change_organization as typed and nothing untyped, for either harness". It builds a bundle for the chief instance (definition chief-of-staff) with buildBundle and asserts, per harness:

Harness manifest.typed manifest.untyped
pi send_message, launch, end_run, change_organization, raise_decision, list_agents, inbox, trail, list_tasks, get_task []
claude-code the same ten, each as mcp__mosaic__<name> (so mcp__mosaic__end_run, mcp__mosaic__change_organization) []

The same test checks the prompt's Bus tools: line and that the "Actions you hold that have no bus tool yet" line is absent. tools.test.mjs:33 asserts untypedActions(chief, tools) is [] (it was ["role.end", "organization.change"] after row 123). Controls and mutants m3b and m4b (below) fail this test if either tool goes missing from typed.

What the row does

  1. end_run (packages/harness/src/tools.mjs:141): a session gets it when its resolved limits.authority holds role.end. Verb role.revoke, parameters role and reason (1 to 500 characters), no decision. The broker already refuses the caller's own run and the assistant's with role-end-refused; the runner passes that code through (refused: role-end-refused).
  2. change_organization (tools.mjs:147): a session gets it when it holds organization.change. Verb organization.set, parameters revision (64 hex characters, required), limits, models, instances. A stale revision fails with revision-conflict.
  3. Key list in one place, with a failing test. ORGANIZATION_KEYS is exported from tools.mjs for the harness; the broker's own list at packages/bus/src/broker.mjs:99 is now exported too, and tools.test.mjs:64 fails if the two differ (mutants m15, m16).
  4. Bundle text (bundle.mjs:92-96): the "only the human stops a run" bullet is now chosen by whether the session has end_run. A role.end holder is told to use end_run with a reason and what is still the human's (mosaic stop, and a role.revoke decision for anything the broker refuses). Every other role keeps today's text byte for byte (test bundle.test.mjs:98).
  5. README text in packages/harness/README.md and packages/business/README.md.

Bus change: the export is the only one

packages/bus/src/broker.mjs changes by one word, const to export const, on the line that declares ORGANIZATION_KEYS (line 99; +1 −1). No bus behaviour changes. No verb, check, schema, migration or message text in packages/bus differs. The bus suite is 191/191 on this candidate.

Out of scope: the chief cannot read the revision (row 134)

change_organization needs the file's current revision. The only read, the broker's limits verb, is human-only (broker.mjs:729: if (!role && !s.human) fail("human-required")), and organization.set takes the keys at line 732 with revision required. So today the tool works only when the chief already has the current revision from somewhere else. A stale or unknown revision fails with revision-conflict (packages/business/src/organization.mjs:185), so change_organization fails closed. This does not block the 3d window, which checks the manifest only. The gap is row 134, queued at rev 1327, brief docs/plans/2026-10-15_organization-revision-read.md (commit 26f4f9701). Row 132 does not grow to cover it.

Other items I did not touch: P19 task 299 (outcome-unknown after the writer) is not part of this row; the reason control-character decision from row 123 round 2 stands.

Tests

File Change
packages/harness/tests/tools.test.mjs chief test renamed and its tool list updated, untypedActions back to [] (line 33); shape test (46); parity with the broker's list (64); non-grant roles and per-grant (69)
packages/harness/tests/bundle.test.mjs chief Bus tools regex (74); typed/untyped for both harnesses (85); stop-line variants (98)
packages/harness/tests/runner.test.mjs fixture gains chief and assistant, setup() takes as/organization; test 377 runs both tools through a real broker with a fake organization writer: {"revoked":true}, refused: role-end-refused for the self and assistant cases, the writer called with ["demo","limits.set",args,"chief-of-staff.chief"], refused: invalid-request for a key outside the list, refused: revision-conflict for a stale revision

Mutants

mutants.sh <worktree> <outdir>, started 2026-10-15T18:00:05Z (mutants-started.txt), results in mutants-run.txt, one .out, .rc and .patch per mutant in mutants/. Three controls (the tools, bundle and runner tests on the unmutated candidate) pass: 16/16, 11/11, 23/23. All 28 mutants fail their tests. The worktree was restored after the run (git status shows the same 8 files).

Mutant What it breaks Killed by
m1, m2 end_run / change_organization for every role tools test (7 failures each)
m3, m3b / m4, m4b either tool never offered (tools, bundle) tools 3, bundle 3 / tools 3, bundle 2
m5, m5b end_run verb wrong (tools; runner) shape test; runner test 377
m6 end_run carries no action, so no grant is checked tools tests
m7, m7b change_organization verb wrong (tools; runner) shape test; runner test 377
m8 change_organization carries no action, so no grant is checked tools tests
m9 reason optional shape test
m10 end_run takes a decision shape test
m11 reason unbounded shape test
m12 revision optional shape test
m13 revision pattern dropped shape test
m14 end_run description loses the own-run, assistant and role-end-refused sentence shape test
m15 a key dropped from the harness list shape test, parity test
m16 a key added to the broker list parity test
m17 the bundle keeps the old stop line for the chief stop-line test
m18 the new stop line for every role stop-line test, pi bundle test
m19, m20, m21 the new text loses the reason requirement, the own-run and assistant sentence, or the "anything the broker refuses" wording stop-line test
m22 the runner drops the tool's arguments runner test 377, capability test
m23 the runner sends the tool name as the verb runner test 377, capability test
m24 the runner hides the broker's refusal code runner test 377, capability test

Gate

suites.sh <worktree> <outdir>, 2026-10-15T18:01:54Z to 18:03:33Z (gate-started.txt, gate-finished.txt, suites-run.txt, output per suite in suites/). All rc=0; the full set, including the harness, bus and business suites the brief asks for:

Suite Result
business 92/92
bus 191/191
plugins 21/21
tasks 97/97
cli 195/195
webui 112/112
harness 90/90
seat 132/132
scripts/test-land-work.sh 84 passed, 0 failed

No flake (#258, #261, #262, #263) recurred. The gate left no Docker network (before and after docker network ls identical). A busy check (by exit status, /proc cwd links only) was clear at 2026-10-15T17:59:14Z before the run.

Not covered

  • The live chief session: no session was launched. The evidence is the bundle test and the runner test against a real broker.
  • Whether a model uses end_run well. The text tells it what to do; nothing tests the model.