Unclaimed files left in the canonical checkout. Inventory: canonical-cleanup-inventory.md (commit-as-evidence groups). detect-secrets scan clean on 2026-11-02: hits are sha256 pins, git object ids, test sentinels already in tracked tests and unit-file lines.
6.7 KiB
Row 170 (#1667, P19 380): a tester's message to a role nobody holds is refused
Builder: Dewey. Reviewer: Filbert. Gate owner: Sage.
Brief: docs/plans/2026-10-19_tester-no-holder-refusal.md, blob 70e4939330 (commit 97cc7f0a3),
approved in mos-0854. Assignment sage-1018; slot sage-1025.
Base: 000730949 (base.txt, origin/refactor). The brief's line numbers are at 42817065e;
git log 42817065e..000730949 -- packages/bus/src/broker.mjs packages/cli/src/cli.mjs is empty,
so they still hold. Candidate: 0b6ff260f (candidate.txt), one commit on the base, in Dewey's
worktree. build.patch is git diff 000730949 0b6ff260f. candidate-manifest.sha256 lists the 6
changed paths with their sha256.
What ships
packages/bus/src/broker.mjs,message.send: once#threadForhas picked the thread, a tester's send refusestester-target-not-runningwhen#recipient(business, to, thread)is null. The check sits before theINSERT INTO messages, so a refused send writes no messages row, no delivery and no_busnotice. A launched run that hasn't claimed counts as no holder, as in#waiting. Human and agent sends are unchanged. The#waitingcomment now says a tester's message to a role nobody holds never reaches it.packages/cli/src/cli.mjs:talk's catch turns a--testersend refusedtester-target-not-runningintoCliError("<role> isn't running, so the tester's message was refused and nothing was stored", 3). The check needs both the code and--tester, so a human send is never rewritten.- The
!w.toldline inwaitingLinesis removed, along with its comment. - Both hunks are in
waitingLinesand thetalkcatch, away from row 171'schannelCallFor/callForhunk (sage-1022).
transport.mjsis untouched (channel-proof.test.mjs:13 pins it). Its EXIT map would send this code to exit 2; the CLI branch gives exit 3 instead.packages/cli/README.md: the row 146 paragraph drops the tester line and points to--tester. The--testerparagraph says what the refusal prints and that it exits 3.docs/TOOLS.mdhas no tester talk line, so it is unchanged.
Tests (the brief's five)
- bus tester.test.mjs, "a tester message to a role no run holds refuses
tester-target-not-running and stores nothing": cto is never held. The messages, deliveries and
_busnotice counts are unchanged. The prefix check still comes first. - bus tester.test.mjs, "a tester message is refused while the run is only launched, and routes
once it claims": cto launched and unclaimed refuses with counts unchanged. After
role.claim, the send returns nowaiting, has onerouteddelivery tocto-run, and cto receives it. - bus tester.test.mjs, "a human message to a role no run holds still waits and tells launch.by":
the business has a launch block (
by: pm). The tester's send refuses; the human's send to cto is stored, returnswaitingwithtold: true, and writes one notice to pm in reply to it. - cli tester.test.mjs, "talk --tester to a stopped role exits 3, prints no sent line and stores
nothing": replaces the row 146 test at :130-136. Exit 3, the exact message, empty stdout, zero
messages, and one tester call (
message.send). - cli tester.test.mjs, "only a --tester send refused tester-target-not-running is rewritten":
a stand-in tester transport refusing
tester-off,tester-required,tester-refusedandunknown-rolekeeps each error's own code and message. A humantalkwhose stand-in transport refusestester-target-not-runningkeeps the bus error.
Existing tests changed beyond the brief's list
Both follow from the brief's change; Sage cleared them for BUILD.md in sage-1025.
packages/bus/tests/launch-notice.test.mjs:190-192sent a tester message to the stopped pm and assertedwaiting.told === false. The send now refuses, so it assertstester-target-not-runningand an unchanged message count. The test title says "a refused one from a tester". The later tester send to the claimed coder (:197) is unchanged.packages/bus/tests/tester.test.mjs, "tester-cli.mjs binds through the runtime ...": it sent through the shim to pm, which no run held in that runtime. The runtime now gets a launch record for pm, withpid: process.pidandstartTime: '1', the same shape as process.test.mjs. Since no process has that start time, the shim doesn't see this test as a managed-run ancestor. Before pm claims, a send to cto through the shim returns{ status: 2, err: 'tester-target-not-running' }.
I checked every other tester message.send in packages/*/tests (messaging, names,
instances-verb, staff-request, chief-of-staff, routes-verb, limits, the cli files). Each one
either targets a claimed role or sends nothing.
Mutants (run/mutants.mjs, driven by run/mutants.sh)
A mutant counts as killed only when its test run exits non-zero and every title listed for it
failed (mutants.mjs expect).
- M1-bus-no-tester-check deletes the broker line. It must fail items 1, 2 and 4, and runs bus and cli tester.test.mjs.
- M2-cli-no-tester-branch deletes the CLI branch. It must fail item 4, and runs cli tester.test.mjs.
Path readers
packages/bus/tests/project-runtime.test.mjs:13reads broker.mjs's import lines. No import changed.packages/cli/tests/host.test.mjs:826reads the cli README for the unit file name. That text is unchanged.- No test pins a sha256 of a changed path. The only 64-hex pin near these files is channel-proof.test.mjs:12, on human-cli.mjs.
Run
The run used the slot from sage-1025 and ran 18:34:29Z-18:37:12Z on 0b6ff260f. The worktree
matched the manifest before and after. Scripts and output are in run/ (run.sh, mutants.sh,
mutants.mjs, touched.txt, run.out).
-
Five files run singly (the 3 changed test files plus the 2 path readers): tests 74, pass 74, fail 0.
File Pass bus tester 14 launch-notice 8 cli tester 8 project-runtime 3 host 41 -
Suites: bus 423/423 and cli 345/345, so tests 768, pass 768, fail 0, skipped 0.
-
Mutants: both controls pass. Killed 2, survived 0, timeouts 0.
- M1 failed items 1, 2, 3 and 4, plus the tester-cli runtime test.
- M2 failed item 4.
-
Not run: the scripts/test-*.sh suites. Sage's gate covers them.
Notes
#waiting'ssender !== 'tester'term is now unreachable for a message with no holder. I kept it, since the brief changes only the comment.- The CLI and the bus run from one pinned copy, so a CLI with this change never talks to a bus
without it. With the
!w.toldline gone, an older bus'stold: falsewould print the "has been told" line. - Out of scope, per the brief: message 02f0e5d6 and other stored messages, expiry of messages
already waiting,
thread.send, the launcher, and the live stack. No re-pin is scheduled.