Files
jason.woltje 6bad02612a lead: commit dewey's untracked evidence (721 files: queue-124-review queue-143 queue-149 queue-165-review queue-170 queue-175 queue-177 queue-184 queue-191)
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.
2026-11-02 15:05:14 -06:00

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 #threadFor has picked the thread, a tester's send refuses tester-target-not-running when #recipient(business, to, thread) is null. The check sits before the INSERT INTO messages, so a refused send writes no messages row, no delivery and no _bus notice. A launched run that hasn't claimed counts as no holder, as in #waiting. Human and agent sends are unchanged. The #waiting comment now says a tester's message to a role nobody holds never reaches it.
  • packages/cli/src/cli.mjs:
    • talk's catch turns a --tester send refused tester-target-not-running into CliError("<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.told line in waitingLines is removed, along with its comment.
    • Both hunks are in waitingLines and the talk catch, away from row 171's channelCallFor/callFor hunk (sage-1022).
  • transport.mjs is 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 --tester paragraph says what the refusal prints and that it exits 3.
  • docs/TOOLS.md has no tester talk line, so it is unchanged.

Tests (the brief's five)

  1. 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 _bus notice counts are unchanged. The prefix check still comes first.
  2. 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 no waiting, has one routed delivery to cto-run, and cto receives it.
  3. 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, returns waiting with told: true, and writes one notice to pm in reply to it.
  4. 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).
  5. 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-refused and unknown-role keeps each error's own code and message. A human talk whose stand-in transport refuses tester-target-not-running keeps 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-192 sent a tester message to the stopped pm and asserted waiting.told === false. The send now refuses, so it asserts tester-target-not-running and 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, with pid: process.pid and startTime: '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:13 reads broker.mjs's import lines. No import changed.
  • packages/cli/tests/host.test.mjs:826 reads 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's sender !== '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.told line gone, an older bus's told: false would 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.