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.
82 lines
5.2 KiB
Diff
82 lines
5.2 KiB
Diff
diff --git a/packages/bus/src/broker.mjs b/packages/bus/src/broker.mjs
|
|
index d5e6f2bc3..b18965feb 100644
|
|
--- a/packages/bus/src/broker.mjs
|
|
+++ b/packages/bus/src/broker.mjs
|
|
@@ -1848,6 +1848,11 @@ export class Broker {
|
|
if (a.class === 'BLOCK') this.#checkBlock(s, to, a.in_reply_to);
|
|
if (a.decision) this.#decision(s, a.decision);
|
|
const thread = this.#threadFor(s, to, a.in_reply_to);
|
|
+ // Row 170 (#1667): a tester's message to a role nobody holds is refused before it is
|
|
+ // stored, so a PM test never waits for the role's next run. A run launched but not yet
|
|
+ // claimed counts as no holder, as in #waiting. No lock: a holder that releases once the
|
|
+ // message is routed leaves it like any other message it held.
|
|
+ if (s.tester && !this.#recipient(s.business, to, thread)) fail('tester-target-not-running');
|
|
const mid = randomUUID();
|
|
this.#store.run(
|
|
'INSERT INTO messages(id,at,business,from_role,from_run,to_role,to_name,class,in_reply_to,decision,corrects,body) VALUES(?,?,?,?,?,?,?,?,?,?,?,?)',
|
|
@@ -2489,7 +2494,8 @@ export class Broker {
|
|
// told and whether launch.by itself has a holder. A run launched but not yet claimed counts as
|
|
// no holder; the instance-running refusal stops a second launch. launch.by isn't told of a
|
|
// message to it, of its own message (this result tells it) or of a tester's (a PM test
|
|
- // authorizes nothing). Row 152 (#1646): launchable says whether the target is one of
|
|
+ // authorizes nothing); since row 170 (#1667) message.send refuses a tester's message to a role
|
|
+ // nobody holds before it gets here. Row 152 (#1646): launchable says whether the target is one of
|
|
// launch.instances, so the sender learns at once that no launch can follow. launch.by is
|
|
// still told: the Console shows the notice as the reply to the human's message.
|
|
#waiting(s, mid, to, thread) {
|
|
diff --git a/packages/cli/README.md b/packages/cli/README.md
|
|
index fb3ad8350..3ed8916d0 100644
|
|
--- a/packages/cli/README.md
|
|
+++ b/packages/cli/README.md
|
|
@@ -127,8 +127,8 @@ mosaic launches list [--json]
|
|
when the bus told `launch.by`; `pm isn't running, and the business names
|
|
no launch.by` with no launch block; `pm isn't running and isn't in the
|
|
launch block, so chief can't launch it` when the role isn't one of
|
|
- `launch.instances` (row 152, #1646); `pm isn't running; a tester's message
|
|
- tells nobody to launch it` for `--tester`. When `launch.by` itself isn't
|
|
+ `launch.instances` (row 152, #1646). A `--tester` message to such a role is
|
|
+ refused instead (see `--tester` below). When `launch.by` itself isn't
|
|
running, talk prints `<launch.by> isn't running` (or `isn't running
|
|
either` after the told line, but not after the launch-block line) and the
|
|
command that starts it:
|
|
@@ -168,8 +168,12 @@ mosaic launches list [--json]
|
|
(`tester-off`), each exit 3. Like the human commands, `--tester` works
|
|
only from the tree the bus runs from ("One pinned copy" below).
|
|
`talk --tester` text must start with
|
|
- `[mos test]`, else exit 2 before any call. The role's reply comes back to
|
|
- the tester, not to the human's inbox. `decide`, `stop`, `launches` and
|
|
+ `[mos test]`, else exit 2 before any call. When no run holds the role
|
|
+ (row 170, #1667), the bus refuses the message with
|
|
+ `tester-target-not-running` and stores nothing, and talk prints `pm isn't
|
|
+ running, so the tester's message was refused and nothing was stored` and
|
|
+ exits 3. A run launched but not yet claimed counts as not running. The
|
|
+ role's reply comes back to the tester, not to the human's inbox. `decide`, `stop`, `launches` and
|
|
`inbox --read` or `--read-all` take no `--tester` (exit 4).
|
|
|
|
## The app
|
|
diff --git a/packages/cli/src/cli.mjs b/packages/cli/src/cli.mjs
|
|
index 6a4f68be6..35a70a5d3 100644
|
|
--- a/packages/cli/src/cli.mjs
|
|
+++ b/packages/cli/src/cli.mjs
|
|
@@ -339,8 +339,6 @@ function waitingLines(w, business) {
|
|
// Row 152 (#1646): launch.by can launch only launch.instances. An older bus sends no
|
|
// launchable, so only an explicit false prints this line.
|
|
if (w.launchable === false) return `${w.role} isn't running and isn't in the launch block, so ${w.launcher} can't launch it\n`;
|
|
- // A human's message to another role always tells launch.by; a tester's never does.
|
|
- if (!w.told) return `${w.role} isn't running; a tester's message tells nobody to launch it\n`;
|
|
return `${w.role} isn't running, ${w.launcher} has been told\n` + (w.launcherRunning ? "" : restart(w.launcher, " either"));
|
|
}
|
|
|
|
@@ -383,6 +381,11 @@ async function talk(rest, io, deps, receiveOnly = false) {
|
|
if (e.code === "thread-required-use-thread-send") {
|
|
throw new CliError(`${to} runs in threads, so a message to it names one: mosaic talk --thread <thread> <text>; mosaic threads lists yours`, 2);
|
|
}
|
|
+ // Row 170 (#1667): the bus stores no tester message to a role nobody holds. Exit 3 like the
|
|
+ // other tester refusals; transport.mjs's EXIT map stays as row 164 pinned it.
|
|
+ if (e.code === "tester-target-not-running" && parsed.flags.has("--tester")) {
|
|
+ throw new CliError(`${to} isn't running, so the tester's message was refused and nothing was stored`, 3);
|
|
+ }
|
|
throw e;
|
|
}
|
|
io.stdout.write(`sent ${shortId(sent.id)} to ${to}\n`);
|