agents: Dewey row 152 round 1 packet (#1646)
Candidate on 56639c99b: waiting gains launchable, and a message to a role
outside launch.instances gets a notice saying the launch is refused and a
talk line saying launch.by can't launch it. Mutants 8/8 killed; gate green
(bus, cli, business, webui and every scripts/test-*.sh).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
56639c99b0
commit
ecf1cec070
32 files changed
+2223
No files matched your search
@@ -0,0 +1,152 @@
|
||||
# Row 152 (#1646): a message to a role launch.by can't launch says so at once
|
||||
|
||||
Builder: Dewey. Reviewer: Filbert. Gate owner: Sage.
|
||||
Brief: docs/plans/2026-10-15_landing-followups.md, the second `##` section. Assignment: sage-0479 (row
|
||||
briefed at rev 1494, claimed at rev 1495). Source: Filbert's row 146 note 2.
|
||||
|
||||
Base: 56639c99b (base.txt, origin/refactor after rows 151 and 153). The candidate is build.patch on that
|
||||
base. candidate-manifest.sha256 lists the seven changed paths with their sha256. repro.sh applies the
|
||||
patch to a fresh detached worktree and checks the digests; it printed DIGESTS_OK.
|
||||
|
||||
Owned files: the brief's six, plus `packages/cli/README.md`, the talk waiting-lines paragraph only.
|
||||
Sage added that file in sage-0481 without re-pinning the brief. The paragraph lists every line talk
|
||||
prints after `sent`, so without it the new line would be undocumented there. docs/TOOLS.md lists none of
|
||||
the lines.
|
||||
|
||||
## The change
|
||||
|
||||
- **packages/bus/src/broker.mjs**, `#waiting` and `#notice` only.
|
||||
- `waiting` gains `launchable`. It's `true` when the target is one of `launch.instances`, `false`
|
||||
when it isn't, and `null` with no launch block, the same as `launcherRunning`. For a message to
|
||||
`launch.by` itself it's `false`: business.mjs refuses an `instances` list that includes the
|
||||
launcher. Nothing else changes in the result, and a reader that ignores the new key sees row 146's
|
||||
shape.
|
||||
- When the target isn't launchable, the message is still stored and routed as before, so a later
|
||||
claim delivers it. `launch.by` is still told (see the call below), but the notice's body says
|
||||
the launch would be refused:
|
||||
`Message <id> from <sender> to <role> waits: <role> has no running session and isn't in the launch block's instances, so a launch of <role> is refused. Tell <sender> why not with message.send in_reply_to <id>.`
|
||||
A launchable target keeps row 146's text, byte for byte.
|
||||
- **packages/cli/src/cli.mjs**, `waitingLines` only. An explicit `launchable: false` prints
|
||||
`<role> isn't running and isn't in the launch block, so <launch.by> can't launch it`, in place of
|
||||
"has been told". No restart line follows, since starting `launch.by` wouldn't launch the role.
|
||||
- This check comes after the no-launch-block and the message-to-`launch.by` cases, so their lines
|
||||
are unchanged.
|
||||
- It comes before the tester line, so a tester's message to an unlaunchable role gets the more
|
||||
specific launch-block line.
|
||||
- An older bus sends no `launchable`. `undefined` isn't `false`, so talk against that bus prints
|
||||
what it prints today.
|
||||
- **Docs.**
|
||||
- packages/bus/README.md: the second notice body, why `launch.by` is still told, and the new key
|
||||
in the `waiting` shape.
|
||||
- packages/cli/README.md: the new line, and that no restart line follows it.
|
||||
- docs/TOOLS.md: one sentence in the talk paragraph pointing at the cli README's list.
|
||||
- **Tests.**
|
||||
- launch-notice.test.mjs: the five existing `waiting` deepEquals now include `launchable`: `true`
|
||||
twice, `false` for the message to chief (launch.by), `null` with no launch block, and `true` for
|
||||
chief's own message to pm.
|
||||
- A new bus test sets `instances: ['pm']`, so coder can't be launched. It asserts:
|
||||
- the whole `waiting` object, with `launchable: false` and `told: true`;
|
||||
- the message stored with `to_role` coder;
|
||||
- one notice, to chief, in_reply_to the message, with the exact new body;
|
||||
- pm, in the same business, still gets `launchable: true` and row 146's text;
|
||||
- coder's later claim receives the stored message.
|
||||
- A new cli test adds a `qa` role outside `instances: ['cto', 'coder']`. In it:
|
||||
- `talk qa` prints only the launch-block line, with pm down and no restart line;
|
||||
- `talk cto` in the same business still prints "pm has been told" and pm's restart line;
|
||||
- pm got both notices, the first with the new text and the second with row 146's.
|
||||
|
||||
## The call: launch.by is still told
|
||||
|
||||
The brief leaves to me whether `launch.by` hears about a message to a role it can't launch. It is still
|
||||
told, for three reasons.
|
||||
|
||||
1. **The Console's only signal is the notice.** The Console never reads `waiting`: no file under
|
||||
packages/webui/src reads it. Its web-send receipt lists the replies to the human's message
|
||||
(bus.js, the row 81 comment: "a sent receipt lists the replies to that message"). The notice is
|
||||
`in_reply_to` that message, and the bus README says "The Console's replies under a human's sent
|
||||
message include the notice". With no notice, a human who sends from the Console sees "No reply
|
||||
yet" and nothing else. With the new notice text, they see at once that no launch can follow, which
|
||||
is this row's problem stated for the Console.
|
||||
2. **The contract already covers the answer.** roles/chief-of-staff.md: "A message from `_bus` is
|
||||
the bus telling you that a message waits for a role with no running session. ... Launch that role
|
||||
within the launch block's limits, or tell the sender why not with a message `in_reply_to` the
|
||||
waiting message." It also says to launch "for the instances and within the limits the business
|
||||
file's launch block lists. A launch outside them is refused, not queued." The new text names the
|
||||
refusal up front and asks only for the second branch, so chief needs no contract change and
|
||||
spends no turn on a launch the bus would refuse. The contract file isn't an owned file, and this
|
||||
reading doesn't need it to change.
|
||||
3. **The message still waits, and chief owns the structure.** The message is stored and reaches the
|
||||
role at a later claim. The contract makes chief keep "the organization's structure: which role
|
||||
instances exist, who holds them and what they may do". Telling chief keeps the role that owns the
|
||||
structure aware of a message no launch can serve. The contract doesn't say which change would add
|
||||
a role to `launch.instances`, so the notice doesn't name one.
|
||||
|
||||
The cost is one chief turn per such message, the same as row 146 already spends for a launchable one.
|
||||
Mutant B4 (not told when unlaunchable) is killed, so this call is pinned.
|
||||
|
||||
### Other choices
|
||||
|
||||
- **The name `launchable`**, a boolean or `null`. It answers the question the sender has ("can this
|
||||
launch at all?"), it matches `launcherRunning`'s nullability, and it's additive.
|
||||
- **`false` for launch.by itself.** It's true to the data: `instances` can't list the launcher. talk
|
||||
checks the launcher case first, so the line for it doesn't change.
|
||||
- **No restart line after the launch-block line.** The restart starts `launch.by`, which still
|
||||
couldn't launch the role. Mutant C2 pins this.
|
||||
- **Not covered by a test: talk against an older bus** (`launchable` absent). waitingLines isn't
|
||||
exported, and a broker in the tests always sends the key. The `=== false` check and its comment
|
||||
carry it. A mutant to `!w.launchable` would survive the suite today, because no test sends a
|
||||
`waiting` without the key. I note it here and don't add an export only for a test.
|
||||
|
||||
## Mutants
|
||||
|
||||
mutants.py applies one fault at a time, runs the owning test file with the spec reporter, and restores
|
||||
the source after each one. Preflight: each target occurs once. Run 2026-10-16T00:41:24Z to 00:41:36Z on
|
||||
56639c99b plus the candidate, in the sage-0483 slot: 8 of 8 killed, `restored True` (mutants-run.log,
|
||||
logs in mutants/).
|
||||
|
||||
| Mutant | Fault | Runs | Result | Failing tests |
|
||||
|---|---|---|---|---|
|
||||
| B1-always-launchable | every target is launchable | bus launch-notice | KILLED | the new unlaunchable test; the launch.by/tester/human/thread test (chief's `launchable: false`) |
|
||||
| B2-no-block-false | no launch block gives `false`, not `null` | bus launch-notice | KILLED | the no-launch-block test only |
|
||||
| B3-launcher-launchable | launch.by counts as launchable | bus launch-notice | KILLED | the launch.by/tester/human/thread test only |
|
||||
| B4-not-told-unlaunchable | launch.by isn't told for an unlaunchable target | bus launch-notice | KILLED | the new unlaunchable test only |
|
||||
| B5-launch-text-always | the notice keeps row 146's text | bus launch-notice | KILLED | the new unlaunchable test only |
|
||||
| B6-field-dropped | `launchable` dropped from `waiting` | bus launch-notice | KILLED | four tests: no launch block, the new unlaunchable test, the stopped-role test, the launch.by/tester/human/thread test |
|
||||
| C1-no-launch-block-line | talk drops the launch-block line | cli verbs | KILLED | the new talk test only |
|
||||
| C2-restart-after-line | talk adds launch.by's restart line after it | cli verbs | KILLED | the new talk test only |
|
||||
|
||||
## Receipts
|
||||
|
||||
Single files on the candidate, without the slot, TMPDIR in my scratch, 0 fail and 0 skipped, on
|
||||
56639c99b: bus launch-notice 8/8, cli verbs 9/9.
|
||||
|
||||
Slot granted by Sage in sage-0483 (busy.sh CLEAR at 00:41:02Z).
|
||||
|
||||
- **Mutants**, 00:41:24Z to 00:41:36Z: 8 of 8 killed, source restored. See the kill table above.
|
||||
- **Gate**, gate.sh from this packet on ~/dewey-scratch/r152/wt (56639c99b plus the candidate),
|
||||
2026-10-16T00:42:47Z to 00:46:38Z, exit 0 (gate-run.log, logs under gate/). It covers the bus,
|
||||
cli, business and webui suites (each with its package.json test command) and every
|
||||
scripts/test-*.sh, as the brief's gate names them:
|
||||
|
||||
| Step | Result |
|
||||
|---|---|
|
||||
| bus | 276 pass, 0 fail, 0 skipped |
|
||||
| cli | 215 pass, 0 fail, 0 skipped |
|
||||
| business | 108 pass, 0 fail, 0 skipped |
|
||||
| webui | 113 pass, 0 fail, 0 skipped |
|
||||
| test-auth | 15 passed, 0 failed |
|
||||
| test-conductor | 17 passed, 0 failed |
|
||||
| test-config | 24 passed, 0 failed |
|
||||
| test-discord | 78 passed, 0 failed |
|
||||
| test-extension-package | 18 passed, 0 failed |
|
||||
| test-foundation | 44 passed, 0 failed |
|
||||
| test-land-work | 84 passed, 0 failed |
|
||||
| test-queue | 28 passed, 0 failed |
|
||||
| test-release | 14 passed, 0 failed |
|
||||
| test-task | 98 passed, 0 failed |
|
||||
|
||||
No recurrence of flakes #258, #261, #262 or #263. gate.sh exports
|
||||
`COMPOSE_PROJECT_NAME=dewey-r152`, and its EXIT trap printed `removed network
|
||||
dewey-r152_default`. Afterwards no network named dewey* or wt* exists.
|
||||
- **Candidate:** candidate-manifest.sha256, sha256
|
||||
c333f4beffec1d901ca23200365698e42003c8256a609ad662429d15e63747c1, 7 files.
|
||||
@@ -0,0 +1 @@
|
||||
56639c99b03ddca8f5fa84826b19322cd09a713e
|
||||
@@ -0,0 +1,239 @@
|
||||
diff --git a/docs/TOOLS.md b/docs/TOOLS.md
|
||||
index 045b14eaf..e5c2cc0ff 100644
|
||||
--- a/docs/TOOLS.md
|
||||
+++ b/docs/TOOLS.md
|
||||
@@ -265,7 +265,10 @@ crashed host left as `host-lost` and refuses with exit 3 on a
|
||||
`sessions.json` it can't read. `talk` sends a REQUEST and prints only the
|
||||
reply to it, marking only that read (polls every 2 s, `--wait` default 900;
|
||||
`0` only sends); other messages stay unread for `mosaic inbox`, and
|
||||
-`--follow` and `follow` print and read everything. `stop` sends SIGTERM to
|
||||
+`--follow` and `follow` print and read everything. When no run holds the
|
||||
+role, a line after `sent` says whether `launch.by` was told, or that the role
|
||||
+isn't in the launch block and `launch.by` can't launch it (row 152); the cli
|
||||
+README, "Human commands", lists the lines. `stop` sends SIGTERM to
|
||||
a run's runner after checking it in
|
||||
`sessions.json`. `launches off|on` revokes and restores `role.launch` for
|
||||
the business; running sessions keep running. `launches list` reads
|
||||
diff --git a/packages/bus/README.md b/packages/bus/README.md
|
||||
index ce50f8d7b..acf77bea0 100644
|
||||
--- a/packages/bus/README.md
|
||||
+++ b/packages/bus/README.md
|
||||
@@ -380,6 +380,17 @@ any other, so a stopped `launch.by` gets it at its next claim. The body is
|
||||
Message <id> from <sender> to <role> waits: <role> has no running session. Launch <role> within the launch block's limits, or tell <sender> why not with message.send in_reply_to <id>.
|
||||
```
|
||||
|
||||
+When the role isn't one of `launch.instances` (row 152, #1646), `launch.by`
|
||||
+can't launch it, and the body says so:
|
||||
+
|
||||
+```
|
||||
+Message <id> from <sender> to <role> waits: <role> has no running session and isn't in the launch block's instances, so a launch of <role> is refused. Tell <sender> why not with message.send in_reply_to <id>.
|
||||
+```
|
||||
+
|
||||
+`launch.by` is still told in that case. The message stays stored and reaches
|
||||
+the role at a later claim, and the Console shows the notice as a reply to the
|
||||
+human's message; it doesn't read the `waiting` field.
|
||||
+
|
||||
`_bus` can't be a role: an instance name matches the business `ID_PATTERN`,
|
||||
which starts with `[a-z0-9]`. So `message.send` to `_bus` refuses
|
||||
`unknown-role`, and a caller can't set `from_role` or `from_run` (unknown keys
|
||||
@@ -388,9 +399,12 @@ automatic RESULT reply to every other class, and the bus would refuse a reply
|
||||
to `_bus`; the runner would log it and skip the `message.read`. On a RESULT
|
||||
the runner takes one turn, sends nothing and marks it read.
|
||||
|
||||
-The result's `waiting` is `{role,launcher,told,launcherRunning}`: the target,
|
||||
-`launch.by` (`null` with no launch block), whether the notice went out, and
|
||||
-whether a run holds `launch.by` (`null` with no launch block). No `waiting`
|
||||
+The result's `waiting` is `{role,launcher,told,launcherRunning,launchable}`:
|
||||
+the target, `launch.by` (`null` with no launch block), whether the notice went
|
||||
+out, whether a run holds `launch.by` (`null` with no launch block), and whether
|
||||
+the target is one of `launch.instances` (`null` with no launch block; `false`
|
||||
+for `launch.by` itself, which `instances` can't list). `launchable` came with
|
||||
+row 152; a reader that ignores it sees row 146's shape. No `waiting`
|
||||
field means a run held the target, or the message went to the human, the
|
||||
tester, or a thread instance inside its thread (row 121's thread launcher starts
|
||||
that session). `told` is `false` and no notice goes out for a message to
|
||||
diff --git a/packages/bus/src/broker.mjs b/packages/bus/src/broker.mjs
|
||||
index bd0cd0ae7..b8f9f1da5 100644
|
||||
--- a/packages/bus/src/broker.mjs
|
||||
+++ b/packages/bus/src/broker.mjs
|
||||
@@ -1897,20 +1897,24 @@ 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).
|
||||
+ // authorizes nothing). 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) {
|
||||
if (to === 'human' || to === 'tester' || (thread && this.#threaded(s.business, to))) return null;
|
||||
if (this.#recipient(s.business, to, thread)) return null;
|
||||
- const by = this.#business(s.business).launch?.by ?? null;
|
||||
+ const launch = this.#business(s.business).launch;
|
||||
+ const by = launch?.by ?? null;
|
||||
+ const launchable = launch ? launch.instances.includes(to) : null;
|
||||
const sender = this.#sender(s);
|
||||
const told = by !== null && to !== by && sender !== by && sender !== 'tester';
|
||||
- if (told) this.#notice(s.business, mid, by, to, sender);
|
||||
- return { role: to, launcher: by, told, launcherRunning: by === null ? null : this.#recipient(s.business, by, null) !== null };
|
||||
+ if (told) this.#notice(s.business, mid, by, to, sender, launchable);
|
||||
+ return { role: to, launcher: by, told, launcherRunning: by === null ? null : this.#recipient(s.business, by, null) !== null, launchable };
|
||||
}
|
||||
// One notice per waiting message: only message.send calls this, once for the message it stores, so
|
||||
// a re-route at a claim or a broker restart never sends another. Its class is RESULT: the runner
|
||||
// takes a turn on it and sends no automatic reply, which NOTICE_ROLE could not receive.
|
||||
- #notice(business, mid, by, to, sender) {
|
||||
+ #notice(business, mid, by, to, sender, launchable) {
|
||||
const nid = randomUUID();
|
||||
this.#store.run(
|
||||
'INSERT INTO messages(id,at,business,from_role,from_run,to_role,class,in_reply_to,decision,corrects,body) VALUES(?,?,?,?,?,?,?,?,?,?,?)',
|
||||
@@ -1924,7 +1928,9 @@ export class Broker {
|
||||
mid,
|
||||
null,
|
||||
null,
|
||||
- `Message ${mid} from ${sender} to ${to} waits: ${to} has no running session. Launch ${to} within the launch block's limits, or tell ${sender} why not with message.send in_reply_to ${mid}.`,
|
||||
+ launchable
|
||||
+ ? `Message ${mid} from ${sender} to ${to} waits: ${to} has no running session. Launch ${to} within the launch block's limits, or tell ${sender} why not with message.send in_reply_to ${mid}.`
|
||||
+ : `Message ${mid} from ${sender} to ${to} waits: ${to} has no running session and isn't in the launch block's instances, so a launch of ${to} is refused. Tell ${sender} why not with message.send in_reply_to ${mid}.`,
|
||||
);
|
||||
this.#route(business, nid, by, null);
|
||||
}
|
||||
diff --git a/packages/bus/tests/launch-notice.test.mjs b/packages/bus/tests/launch-notice.test.mjs
|
||||
index 0bf1703a2..a4121bdb8 100644
|
||||
--- a/packages/bus/tests/launch-notice.test.mjs
|
||||
+++ b/packages/bus/tests/launch-notice.test.mjs
|
||||
@@ -68,7 +68,7 @@ function setup(t, businesses = demo()) {
|
||||
test('a message to a stopped role sends launch.by one notice, and the result says so', (t) => {
|
||||
const ctx = setup(t);
|
||||
const sent = ctx.call('human', 'message.send', { to: 'pm', body: 'is the plan current?', class: 'REQUEST' });
|
||||
- assert.deepEqual(sent.waiting, { role: 'pm', launcher: 'chief', told: true, launcherRunning: false });
|
||||
+ assert.deepEqual(sent.waiting, { role: 'pm', launcher: 'chief', told: true, launcherRunning: false, launchable: true });
|
||||
const [n, ...more] = ctx.notices();
|
||||
assert.deepEqual(more, []);
|
||||
assert.equal(n.from_run, 'bus');
|
||||
@@ -90,6 +90,7 @@ test('a message to a stopped role sends launch.by one notice, and the result say
|
||||
launcher: 'chief',
|
||||
told: true,
|
||||
launcherRunning: true,
|
||||
+ launchable: true,
|
||||
});
|
||||
assert.equal(ctx.notices().length, 2);
|
||||
// Row 151 (#1645): the notice is routed to launch.by's holder, which the Console's waiting lists read.
|
||||
@@ -106,6 +107,31 @@ test('a message to a stopped role sends launch.by one notice, and the result say
|
||||
assert.match(ctx.notices().at(-1).body, / from coder to pm waits: /);
|
||||
});
|
||||
|
||||
+// Row 152 (#1646): a target outside launch.instances. The result says so at once, the message is
|
||||
+// stored for a later claim, and launch.by is still told, in words that say no launch can follow.
|
||||
+test('a message to a role outside launch.instances says so in its result and in the notice', (t) => {
|
||||
+ const ctx = setup(t, demo({ launch: { by: 'chief', instances: ['pm'], models: {}, limits: {} } }));
|
||||
+ const sent = ctx.call('human', 'message.send', { to: 'coder', body: 'can you take this?', class: 'REQUEST' });
|
||||
+ assert.deepEqual(sent.waiting, { role: 'coder', launcher: 'chief', told: true, launcherRunning: false, launchable: false });
|
||||
+ assert.equal(ctx.store().get('SELECT to_role FROM messages WHERE id=?', sent.id).to_role, 'coder');
|
||||
+ const [n, ...more] = ctx.notices();
|
||||
+ assert.deepEqual(more, []);
|
||||
+ assert.equal(n.to_role, 'chief');
|
||||
+ assert.equal(n.in_reply_to, sent.id);
|
||||
+ assert.equal(
|
||||
+ n.body,
|
||||
+ `Message ${sent.id} from human to coder waits: coder has no running session and isn't in the launch block's instances, so a launch of coder is refused. Tell human why not with message.send in_reply_to ${sent.id}.`,
|
||||
+ );
|
||||
+ // The same business's launchable target keeps row 146's text.
|
||||
+ assert.equal(ctx.call('human', 'message.send', { to: 'pm', body: 'and you?' }).waiting.launchable, true);
|
||||
+ assert.match(ctx.notices().at(-1).body, / waits: pm has no running session\. Launch pm within /);
|
||||
+ // A later claim still delivers the stored message.
|
||||
+ ctx.launch('coder', 'coder');
|
||||
+ ctx.claim('coder');
|
||||
+ assert.deepEqual(ctx.call('coder', 'message.receive').map((m) => m.id), [sent.id]);
|
||||
+ assert.equal(ctx.notices().length, 2);
|
||||
+});
|
||||
+
|
||||
test('a message to a running role sends no notice and its result is unchanged', (t) => {
|
||||
const ctx = setup(t);
|
||||
ctx.launch('pm', 'pm');
|
||||
@@ -149,6 +175,7 @@ test('no notice for a message to launch.by, from it, from a tester, to the human
|
||||
launcher: 'chief',
|
||||
told: false,
|
||||
launcherRunning: false,
|
||||
+ launchable: false,
|
||||
});
|
||||
// From launch.by: the result tells it.
|
||||
ctx.launch('chief', 'chief');
|
||||
@@ -158,6 +185,7 @@ test('no notice for a message to launch.by, from it, from a tester, to the human
|
||||
launcher: 'chief',
|
||||
told: false,
|
||||
launcherRunning: true,
|
||||
+ launchable: true,
|
||||
});
|
||||
// From a tester: a PM test authorizes nothing, so it wakes no launcher.
|
||||
ctx.caps.tester = ctx.b.bindTester({ business: 'demo' });
|
||||
@@ -186,6 +214,7 @@ test('a business with no launch block tells nobody and says there is no launcher
|
||||
launcher: null,
|
||||
told: false,
|
||||
launcherRunning: null,
|
||||
+ launchable: null,
|
||||
});
|
||||
assert.deepEqual(ctx.notices(), []);
|
||||
});
|
||||
diff --git a/packages/cli/README.md b/packages/cli/README.md
|
||||
index 2a32f158a..2fca3224c 100644
|
||||
--- a/packages/cli/README.md
|
||||
+++ b/packages/cli/README.md
|
||||
@@ -69,10 +69,13 @@ mosaic launches list [--json]
|
||||
`mosaic inbox` shows it. When no run holds the role (row 146, #1640),
|
||||
a line after `sent` says so: `pm isn't running, chief has been told`
|
||||
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; a tester's message
|
||||
+ 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
|
||||
running, talk prints `<launch.by> isn't running` (or `isn't running
|
||||
- either` after the told line) and the command that starts it:
|
||||
+ either` after the told line, but not after the launch-block line) and the
|
||||
+ command that starts it:
|
||||
`systemctl --user restart mosaic-bus@<business>`, which starts it only if
|
||||
the unit runs with `--pm` (`scripts/bus-service.sh status <business>`
|
||||
shows `pm: on`) and stops running sessions. A hand-started host takes
|
||||
diff --git a/packages/cli/src/cli.mjs b/packages/cli/src/cli.mjs
|
||||
index 26cddd24f..113f93137 100644
|
||||
--- a/packages/cli/src/cli.mjs
|
||||
+++ b/packages/cli/src/cli.mjs
|
||||
@@ -221,6 +221,9 @@ function waitingLines(w, business) {
|
||||
`${role} isn't running${either}. systemctl --user restart mosaic-bus@${business()} starts it if the unit runs with --pm (scripts/bus-service.sh status ${business()} shows pm: on). The restart stops running sessions.\n`;
|
||||
if (w.launcher === null) return `${w.role} isn't running, and the business names no launch.by\n`;
|
||||
if (w.role === w.launcher) return restart(w.role);
|
||||
+ // 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"));
|
||||
diff --git a/packages/cli/tests/verbs.test.mjs b/packages/cli/tests/verbs.test.mjs
|
||||
index c9d0b9d17..e0d6f0dc3 100644
|
||||
--- a/packages/cli/tests/verbs.test.mjs
|
||||
+++ b/packages/cli/tests/verbs.test.mjs
|
||||
@@ -118,6 +118,24 @@ test("talk says when the role isn't running, whether launch.by was told, and how
|
||||
assert.equal(await text(s, "coder"), "");
|
||||
});
|
||||
|
||||
+// Row 152 (#1646): a role outside launch.instances. talk says so instead of "has been told", and
|
||||
+// prints no restart line for launch.by, whose start wouldn't launch the role.
|
||||
+test("talk to a role launch.by can't launch says it isn't in the launch block", async (t) => {
|
||||
+ const roles = { ...BUSINESSES.demo.roles, qa: { authority: { withinRole: ["message.send"], crossRole: [] } } };
|
||||
+ const s = setup(t, {}, { demo: { ...BUSINESSES.demo, roles, launch: { by: "pm", instances: ["cto", "coder"], models: {}, limits: {} } } });
|
||||
+ const text = async (role) => {
|
||||
+ const r = await s.run(["talk", role, "hello", "--wait", "0", "--business", "demo"]);
|
||||
+ assert.equal(r.code, 0, r.error);
|
||||
+ return r.io.out.text.replace(/^sent [0-9a-f]{8} to \S+\n/, "");
|
||||
+ };
|
||||
+ assert.equal(await text("qa"), "qa isn't running and isn't in the launch block, so pm can't launch it\n");
|
||||
+ assert.equal(await text("cto"), "cto isn't running, pm has been told\n" + `pm isn't running either. systemctl --user restart mosaic-bus@demo starts it if the unit runs with --pm (scripts/bus-service.sh status demo shows pm: on). The restart stops running sessions.\n`);
|
||||
+ const notices = s.store.all("SELECT body FROM messages WHERE from_role='_bus' ORDER BY seq").map((m) => m.body);
|
||||
+ assert.equal(notices.length, 2, "pm is told of both");
|
||||
+ assert.match(notices[0], / waits: qa has no running session and isn't in the launch block's instances, so a launch of qa is refused\. /);
|
||||
+ assert.match(notices[1], / waits: cto has no running session\. Launch cto within /);
|
||||
+});
|
||||
+
|
||||
// Row 151 (#1645): rows 146 and 142 in one talk. The waiting line prints once after "sent", a
|
||||
// message that isn't the reply arrives first and stays unread, then the reply prints and talk exits 0.
|
||||
test("talk to a stopped role prints the waiting line once, skips a non-reply and prints the reply", async (t) => {
|
||||
@@ -0,0 +1,7 @@
|
||||
2d242f560553d81ed4ee3dd2d430fccc565c10644ba5e7b802a1803ce7644eae docs/TOOLS.md
|
||||
07efa828f9581e90b35ad1e800b08f04abaf3ccbad8a8e69bca49204e025e5bf packages/bus/README.md
|
||||
e491b01841fb74c0edaeafcc365df980bfc59f520640bda6ae62c027fc05e148 packages/bus/src/broker.mjs
|
||||
4eeaefda4dfc0991ce5566fb390b5b4c302cbc28b60b5540f03ffdfd3301782f packages/bus/tests/launch-notice.test.mjs
|
||||
d3cba2d9eb2ace4bf625c992a75c04e19704e70bec53253c972564dc98241083 packages/cli/README.md
|
||||
0daf33cb484a8407008af13ffe665e16f12de7fadb048153a08bfa9ec4a34116 packages/cli/src/cli.mjs
|
||||
4c45b04fa6494df0b1cdf680b40a78245e81bdbb8edddf9eb75f0057ccf91e47 packages/cli/tests/verbs.test.mjs
|
||||
@@ -0,0 +1,17 @@
|
||||
start 2026-10-16T00:42:47Z
|
||||
pkg-bus start=2026-10-16T00:42:47Z end=2026-10-16T00:42:59Z rc=0 tests=276 pass=276 fail=0 skipped=0
|
||||
pkg-cli start=2026-10-16T00:42:59Z end=2026-10-16T00:43:20Z rc=0 tests=215 pass=215 fail=0 skipped=0
|
||||
pkg-business start=2026-10-16T00:43:20Z end=2026-10-16T00:43:22Z rc=0 tests=108 pass=108 fail=0 skipped=0
|
||||
pkg-webui start=2026-10-16T00:43:22Z end=2026-10-16T00:44:16Z rc=0 tests=113 pass=113 fail=0 skipped=0
|
||||
test-auth start=2026-10-16T00:44:16Z end=2026-10-16T00:44:17Z rc=0
|
||||
test-conductor start=2026-10-16T00:44:17Z end=2026-10-16T00:44:22Z rc=0
|
||||
test-config start=2026-10-16T00:44:22Z end=2026-10-16T00:44:24Z rc=0
|
||||
test-discord start=2026-10-16T00:44:24Z end=2026-10-16T00:44:30Z rc=0
|
||||
test-extension-package start=2026-10-16T00:44:30Z end=2026-10-16T00:44:32Z rc=0
|
||||
test-foundation start=2026-10-16T00:44:32Z end=2026-10-16T00:45:10Z rc=0
|
||||
test-land-work start=2026-10-16T00:45:10Z end=2026-10-16T00:45:21Z rc=0
|
||||
test-queue start=2026-10-16T00:45:21Z end=2026-10-16T00:45:52Z rc=0
|
||||
test-release start=2026-10-16T00:45:52Z end=2026-10-16T00:46:04Z rc=0
|
||||
test-task start=2026-10-16T00:46:04Z end=2026-10-16T00:46:37Z rc=0
|
||||
removed network dewey-r152_default
|
||||
end 2026-10-16T00:46:38Z rc=0
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# Row 152 owner's gate (sage-0479): the bus, cli, business and webui suites and every scripts/test-*.sh,
|
||||
# on base.txt plus build.patch. One log per step under gate/. Each suite runs its package.json test.
|
||||
set -uo pipefail
|
||||
WT=${1:-$HOME/dewey-scratch/r152/wt}
|
||||
OUT=$(cd "$(dirname "$0")" && pwd)/gate
|
||||
mkdir -p "$OUT"
|
||||
export TMPDIR=$HOME/dewey-scratch/tmp
|
||||
# test-task.sh's live cases run `docker compose run` from $WT (mosaic-task.mjs passes its env through).
|
||||
# An explicit project name keeps them off the dir-named `wt` project; its network goes at exit (Mos, sage-0447).
|
||||
export COMPOSE_PROJECT_NAME=dewey-r152
|
||||
trap 'docker network rm "${COMPOSE_PROJECT_NAME}_default" >/dev/null 2>&1 && echo "removed network ${COMPOSE_PROJECT_NAME}_default"' EXIT
|
||||
status=0
|
||||
for p in bus cli business webui; do
|
||||
start=$(date -u +%FT%TZ)
|
||||
case $p in bus|cli) t=(tests/*.test.mjs) ;; *) t=(tests/) ;; esac
|
||||
(cd "$WT/packages/$p" && node --test "${t[@]}") >"$OUT/pkg-$p.log" 2>&1
|
||||
rc=$?
|
||||
counts=$(grep -E '^ℹ (tests|pass|fail|skipped) ' "$OUT/pkg-$p.log" | awk '{printf "%s=%s ", $2, $3}')
|
||||
echo "pkg-$p start=$start end=$(date -u +%FT%TZ) rc=$rc $counts"
|
||||
[ "$rc" -eq 0 ] || status=1
|
||||
done
|
||||
for s in "$WT"/scripts/test-*.sh; do
|
||||
n=$(basename "$s" .sh)
|
||||
start=$(date -u +%FT%TZ)
|
||||
(cd "$WT" && bash "scripts/$n.sh") >"$OUT/$n.log" 2>&1
|
||||
rc=$?
|
||||
echo "$n start=$start end=$(date -u +%FT%TZ) rc=$rc"
|
||||
[ "$rc" -eq 0 ] || status=1
|
||||
done
|
||||
exit $status
|
||||
@@ -0,0 +1,284 @@
|
||||
✔ agents: a held role with nothing on the bus is idle; a role session gets the claim rows unchanged (154.908692ms)
|
||||
✔ agents: working counts what the holder received and has not read; routed alone is not working (212.39013ms)
|
||||
✔ agents: input needed is the role's open decisions routed to the human, gated first, then oldest (337.629855ms)
|
||||
✔ agents: working wins over waiting, and Input needed still shows (181.702722ms)
|
||||
✔ agents: a new holder doesn't inherit what the last one left unread; decisions stay with the role (198.68229ms)
|
||||
✔ agents: state reads only its own business, even for a run name both use (179.517533ms)
|
||||
✔ agents: a message the holder released unread is stranded; the next holder gets nothing and cannot read it (233.134047ms)
|
||||
✔ agents: a message the holder read is not stranded; one the current holder has not read is not listed (244.412716ms)
|
||||
✔ agents: stranded is oldest first and capped at 50 for a role (976.732504ms)
|
||||
✔ agents: stranded is per role and per business (362.294934ms)
|
||||
✔ agents: a message routed to a held role and not yet received is not stranded (150.691375ms)
|
||||
✔ REQ-DEC an approval outlives its run and a broker restart; a new run of the instance consumes it once (288.7355ms)
|
||||
✔ REQ-DEC another instance of the same definition cannot consume an approval, and its refusal consumes nothing (179.769963ms)
|
||||
✔ REQ-DEC REQ-THREAD-1 a thread approval is consumed only by a run holding the same thread (264.429162ms)
|
||||
✔ REQ-DEC a later run of the same instance supersedes an open decision; another instance cannot (237.043456ms)
|
||||
✔ REQ-DEC REQ-THREAD-1 a thread decision is superseded only from the same thread (245.450797ms)
|
||||
✔ REQ-DEC REQ-THREAD-1 a thread instance decision raised before row 121 is not consumed or superseded by any thread run (374.868431ms)
|
||||
✔ launch identity is stamped, payload identity is refused and stale holder cannot send (188.637947ms)
|
||||
✔ decision classes route from policy; gated resolution is human-only, choice and target must match (274.642508ms)
|
||||
✔ claim exclusion, holder release, gated revoke and rerouting to a new holder are atomic (295.770472ms)
|
||||
✔ launch events require a human CLI capability; generic emit cannot forge authority events (169.695459ms)
|
||||
✔ within-role decisions close atomically and invalid options or blocking omissions refuse (178.399958ms)
|
||||
✔ a recommendation that is not exactly one option key refuses invalid-recommendation after the options (279.265217ms)
|
||||
✔ observer capabilities read human inbox but cannot mutate or forge launch identity (194.922705ms)
|
||||
✔ task action subjects and linked decision trail are complete and ordered (214.937162ms)
|
||||
✔ launch binding is durable and reconnecting requires the identical trusted record (151.540023ms)
|
||||
✔ business isolation includes inherited object names and cross-business message references (198.663289ms)
|
||||
✔ authority never transfers between action, target, unresolved or replaced role holder; a later run of the instance keeps it (329.582276ms)
|
||||
✔ task projection uses schema current view, skipping earlier and equal-start polls (206.263841ms)
|
||||
✔ revocation permanently bars the old run from reclaiming first, including after broker restart (235.675423ms)
|
||||
✔ empty message references refuse before storage; refusal-evidence failure stays a typed error (172.275142ms)
|
||||
✔ both arbiters require human resolution when their cross-role route is themselves (262.366935ms)
|
||||
✔ the shipped coder role raises task.reassign as gated to the human; task.scope.change stays cross-role (222.393933ms)
|
||||
✔ S1 adapter takes resolved limits and refs, rejects mismatched instance, never mutates input (2.335873ms)
|
||||
✔ REQ-COS-1, REQ-ROLE-2: the chief of staff ends a run with a reason and no decision, and the reason is logged (253.045704ms)
|
||||
✔ REQ-ROLE-2: a role without role.end still needs a resolved decision to revoke (343.963994ms)
|
||||
✔ REQ-ROLE-2: storage accepts a revoke with a reason or a decision and aborts one with neither (247.038759ms)
|
||||
✔ REQ-ROLE-2: the chief of staff may still cite a decision, and a decision alone is the old path (231.07081ms)
|
||||
✔ REQ-ROLE-2: a role without role.end still ends a run through a resolved decision, which is recorded and has no reason (249.753741ms)
|
||||
✔ REQ-ROLE-2: a reason is required, bounded, and never sent with a decision (334.92577ms)
|
||||
✔ REQ-COS-1: the chief of staff cannot end its own run or the assistant's through role.end (288.987398ms)
|
||||
✔ REQ-LIMIT-1, REQ-COS-1: organization.set from the chief of staff reaches the shared writer, named as the actor (240.323801ms)
|
||||
✔ REQ-LIMIT-1, REQ-COS-1: a refused organization.set logs action.refused and no action.allowed, like a refused limits.set (384.094393ms)
|
||||
✔ REQ-LIMIT-1: organization.set is refused for every caller whose role file lacks organization.change (335.845595ms)
|
||||
✔ REQ-LIMIT-1: the chief of staff is logged as allowed, and organization.set takes only the human's keys (398.20837ms)
|
||||
✔ REQ-ROLE-3, REQ-LIMIT-1: a chief-of-staff change is validated, written and logged like a human's; an invalid one is refused (608.436018ms)
|
||||
✔ REQ-ROLE-2, REQ-COS-1: the 3c→3d migration lets the chief of staff end a held role with a reason; neither is still refused (975.669857ms)
|
||||
✔ comment cursors isolate businesses, move only forward and remain append-only (149.289339ms)
|
||||
✔ only trusted sync writes validated cursors; events and cursor share rollback (128.153175ms)
|
||||
✔ explicit 3b copy migration preserves evidence and opens as 3e; normal startup never migrates (873.767171ms)
|
||||
✔ migration refuses active writers and drifted legacy schemas, with no partial upgrade (1602.793878ms)
|
||||
✔ named migration registry chains 3b through 3e to a fixture-only future version in order (914.254697ms)
|
||||
✔ migration refuses mismatched source metadata without changing schema or evidence (876.936722ms)
|
||||
✔ offline command migrates only the supplied fixture root and reports usage errors (915.955501ms)
|
||||
✔ credentials gives human and reader sessions service, account, role, date and state, and nothing else (114.976001ms)
|
||||
✔ credentials refuses a role session and any argument (184.979163ms)
|
||||
✔ credentials reads the status on each request, and a broker without one lists none (227.475759ms)
|
||||
✔ the broker process answers credentials without a token, path or variable in its output, log or store (224.772714ms)
|
||||
✔ only validated broker references load; returned data and exceptions cannot expose a known token (3.840548ms)
|
||||
✔ bad file modes, symlinks, repository/data paths, malformed tokens and missing dates refuse (2.940443ms)
|
||||
✔ expiry refuses use and env references never become client data (0.821859ms)
|
||||
✔ S1 parsed service refs work, service mismatch refuses, Gitea rotation due is a warning state (2.064689ms)
|
||||
✔ opaque tokens shorter than 16 characters refuse before use (0.556881ms)
|
||||
✔ each C-suite role file carries the same two lists: human, chief-of-staff, pm, cto (2.366965ms)
|
||||
✔ chief-executive-officer: messages to and from the user, chief of staff, pm and cto pass (513.59278ms)
|
||||
✔ chief-executive-officer: a message to or from the coder, reviewer or assistant is refused and logged, and nothing is stored (464.585661ms)
|
||||
✔ chief-executive-officer: another C-suite role isn't on the lists either (392.082677ms)
|
||||
✔ chief-financial-officer: messages to and from the user, chief of staff, pm and cto pass (527.506756ms)
|
||||
✔ chief-financial-officer: a message to or from the coder, reviewer or assistant is refused and logged, and nothing is stored (490.557192ms)
|
||||
✔ chief-financial-officer: another C-suite role isn't on the lists either (462.108584ms)
|
||||
✔ chief-information-officer: messages to and from the user, chief of staff, pm and cto pass (520.622547ms)
|
||||
✔ chief-information-officer: a message to or from the coder, reviewer or assistant is refused and logged, and nothing is stored (510.116945ms)
|
||||
✔ chief-information-officer: another C-suite role isn't on the lists either (463.072467ms)
|
||||
✔ chief-information-security-officer: messages to and from the user, chief of staff, pm and cto pass (503.171432ms)
|
||||
✔ chief-information-security-officer: a message to or from the coder, reviewer or assistant is refused and logged, and nothing is stored (486.361951ms)
|
||||
✔ chief-information-security-officer: another C-suite role isn't on the lists either (408.168732ms)
|
||||
✔ chief-marketing-officer: messages to and from the user, chief of staff, pm and cto pass (454.343186ms)
|
||||
✔ chief-marketing-officer: a message to or from the coder, reviewer or assistant is refused and logged, and nothing is stored (400.80893ms)
|
||||
✔ chief-marketing-officer: another C-suite role isn't on the lists either (359.104508ms)
|
||||
✔ a human resolve sends the raising role one message from the human, and its request is the answer (251.765471ms)
|
||||
✔ a cross-role decision resolved by its arbiter comes from that role and run, with no request (247.929104ms)
|
||||
✔ a human withdraw sends one message with the note (254.839038ms)
|
||||
✔ a human seen before the close leaves the request on the close's answer, not the seen (285.546059ms)
|
||||
✔ the raising run's withdraw, a supersede, a within-role raise and seen send nothing (270.310246ms)
|
||||
✔ refused closes send nothing: invalid-choice, decision-closed, not-resolver (341.154617ms)
|
||||
✔ a raising role nobody holds at the close gets the message on the next claim (293.727206ms)
|
||||
✔ a human DECISION send keeps its own instruction as the request, not a close's answer (243.403725ms)
|
||||
✔ a cross-role raise whose arbiter the raiser does not hear from is refused and stores nothing (314.457689ms)
|
||||
✔ a gated raise by a role that does not hear from the human is refused and stores nothing (309.883814ms)
|
||||
✔ a route the raiser hears from is allowed, checked from the route to the raiser (345.455132ms)
|
||||
✔ a refused supersede withdraws nothing (279.810244ms)
|
||||
✔ the assistant's within-role and gated raises still work (346.172834ms)
|
||||
✔ roles lists open decisions routed to a role, and never the human inbox (260.852495ms)
|
||||
✔ recent lists closed decisions of every route, newest close first, with how each closed (291.648323ms)
|
||||
✔ recent gives the closing event as closed when the decision was seen first (311.058573ms)
|
||||
✔ recent stops at RECENT rows (844.056921ms)
|
||||
✔ every row is what trail already gives the same session for that id (300.440799ms)
|
||||
✔ a role session can't list decisions, so it can't read another role's open decisions (433.454522ms)
|
||||
✔ decisions is a read: one business, strict arguments, nothing written (442.454517ms)
|
||||
✔ endLaunch writes session.ended, releases the run claim and kills its capabilities (158.740681ms)
|
||||
✔ endLaunch refuses an unknown run, a second end and a rebind of the ended run (142.855332ms)
|
||||
✔ a restarted broker refuses to rebind an ended run; a refused rebind leaves the run unbound (148.343448ms)
|
||||
✔ endLaunch leaves a claim another run took alone (198.403409ms)
|
||||
✔ refuse records action.refused against the caller with the code only (140.490101ms)
|
||||
✔ launches off refuses role.launch with launch-revoked until launches on (197.580063ms)
|
||||
✔ broker process: launch ops authorize role.launch, record refusals and end runs (310.64086ms)
|
||||
✔ human proof binds CLI entry, process start and nonce; agents and incomplete ancestry refuse (2.50335ms)
|
||||
✔ process reader gets own kernel identity without exposing environment values (0.693821ms)
|
||||
✔ EACCES ancestor environments skip only markers; commands and registered launches still refuse (1.036132ms)
|
||||
✔ real pid 1 remains inspectable when its environment is protected (0.410715ms)
|
||||
✔ a message to a stopped role sends launch.by one notice, and the result says so (223.8843ms)
|
||||
✔ a message to a role outside launch.instances says so in its result and in the notice (159.518298ms)
|
||||
✔ a message to a running role sends no notice and its result is unchanged (172.539549ms)
|
||||
✔ a re-route at a claim, a release and claim, and a broker restart send no second notice (237.912306ms)
|
||||
✔ a run launched but not yet claimed counts as no holder (146.631478ms)
|
||||
✔ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (259.320908ms)
|
||||
✔ a business with no launch block tells nobody and says there is no launcher (132.897849ms)
|
||||
✔ the notice sender stays internal: no role is named _bus and no caller can send as it or to it (391.612366ms)
|
||||
✔ limits binds actor from human proof and rejects role, reader, tester and forged actor (231.926196ms)
|
||||
✔ runtime wires verified human settings to the actual shared file writer and actor receipt (308.165334ms)
|
||||
✔ uncertain organization receipts leave bus startup and reads alone but refuse writes until reconciled (421.210006ms)
|
||||
✔ within-role sends cite an open gated launch decision without spending it or naming it in grants (222.386377ms)
|
||||
✔ missing and foreign-business citations refuse and roll back message and grant (188.100629ms)
|
||||
✔ cross-role sends still need a matching resolved decision and consume it once (264.848852ms)
|
||||
✔ messages pages all human messages newest first without writes; read state is history (2737.721682ms)
|
||||
✔ messages refuses role callers, invalid paging and cursors outside this human feed (295.238506ms)
|
||||
✔ views messages passes only its paging arguments through (0.271947ms)
|
||||
✔ messages isolates businesses even with a valid foreign cursor (227.03928ms)
|
||||
✔ the assistant sends to the user and to the chief of staff only (312.596515ms)
|
||||
✔ an assistant send to any other role, or to the tester, is refused and logged (367.601018ms)
|
||||
✔ only the user and the chief of staff may send to the assistant; the tester is refused by default (408.561146ms)
|
||||
✔ REQ-ASSIST-2 REQ-THREAD-1 thread.send to an instance that does not hear from the user is refused and stores nothing (331.398156ms)
|
||||
✔ a sender-side list alone refuses a send to a role that has no list (391.532474ms)
|
||||
✔ a target-side list alone refuses a send from a role that has no list (370.229458ms)
|
||||
✔ the sender list is checked before the target list (316.492908ms)
|
||||
✔ roles without the field behave exactly as before (485.246426ms)
|
||||
✔ a business with no role definitions at all is unlimited (383.535966ms)
|
||||
✔ a malformed messaging field refuses at boot (119.795255ms)
|
||||
✔ the assistant's review.request to a reviewer is refused and logged, even with an approved decision (376.637639ms)
|
||||
✔ a review.verdict to the assistant from a role outside its receiveFrom is refused and logged (401.827805ms)
|
||||
✔ review requests and verdicts between roles without the field are unchanged (370.337023ms)
|
||||
✔ plugins and plugins.set refuse every non-human session and a forged actor, and pass only the patch with the verified actor (201.210538ms)
|
||||
✔ runtime: the switch changes the organization file, the receipt carries the actor, and a bad shape, an unknown module and a stale revision are refused with nothing written (486.882414ms)
|
||||
✔ vikunja:19/309 through the broker, a patch switches the kinds it names and keeps the rest; null removes one kind and is trailed (469.231164ms)
|
||||
✔ broker process binds trusted launches, offers reader capabilities, refuses human mutation, closes cleanly (183.630077ms)
|
||||
✔ startup token refusal returns safe code without value or partial listening broker (62.851548ms)
|
||||
✔ loaded fixture token is absent from socket replies and SQLite, including refusal evidence (218.732912ms)
|
||||
✔ killed broker leaves an explicit stale lock; another process cannot silently reclaim it (241.086941ms)
|
||||
✔ trusted host registers later launches; socket clients never have a registration verb (242.013703ms)
|
||||
✔ runtime excludes declared project roots even when host supplies no repoRoots (62.977815ms)
|
||||
✔ a refused launch binding leaves the broker and existing capabilities alive; bad protocol stops it (228.870639ms)
|
||||
✔ a reply is listed for human and reader sessions, and its delivery rows are unchanged (258.203669ms)
|
||||
✔ the reply still reaches the human message.receive (mosaic talk) after the Console showed it (214.531249ms)
|
||||
✔ a message with no reply gives an empty list (197.714133ms)
|
||||
✔ replies come oldest first and stop at REPLIES (838.439106ms)
|
||||
✔ an id that names no message in the business refuses message-not-found, and the refusal is recorded (317.784467ms)
|
||||
✔ strict arguments; a role session gets human-required (441.945841ms)
|
||||
✔ views passes replies through as one call with the id (0.229173ms)
|
||||
✔ requirements returns the committed list to a holding role session, and no one else (240.446401ms)
|
||||
✔ the PM's prd.approve with no task, when no id fits, reaches the human's Inbox (178.394177ms)
|
||||
✔ the PM's non-blocking role.revoke with no task reaches the human's Inbox (183.156302ms)
|
||||
✔ a push is recorded as the action.allowed for git.push.working on the task, and only the host records one (257.511933ms)
|
||||
✔ review.request names the latest pushed commit and sends the reviewer a REVIEW-REQUEST (263.724294ms)
|
||||
✔ review.request says which run holds the reviewer role, or null, and a null request waits for a claim (346.699176ms)
|
||||
✔ review.request refuses a commit that isn't the latest push, a non-reviewer and a role without the action (414.129395ms)
|
||||
✔ reviewFetch answers only the addressed reviewer, for the request it cites (246.655258ms)
|
||||
✔ review.verdict answers one request once, to the role that asked (356.743531ms)
|
||||
✔ task.close on a pushed task needs an approve verdict for the latest push (410.897101ms)
|
||||
✔ a refusal the host decided is filed on the task it names, and only a task ref counts (288.079605ms)
|
||||
✔ v3b prototype refusals, views and append-only mutations (1624.711466ms)
|
||||
✔ gated approval authorizes once, survives store reopen, and fresh approval works (247.588947ms)
|
||||
✔ another run of the same instance consumes an approval once; a failed check leaves it usable (269.246714ms)
|
||||
✔ two scheduled callers have exactly one grant and one consumed refusal (192.777388ms)
|
||||
✔ failed commit rolls consumption back; cross-role consumes and within-role stays reusable (326.638813ms)
|
||||
✔ class drift gated to cross-role refuses before consumption (235.432736ms)
|
||||
✔ class drift cross-role to gated refuses before consumption (303.255273ms)
|
||||
✔ class drift gated to within-role refuses before consumption (245.327295ms)
|
||||
✔ class drift cross-role to within-role refuses before consumption (305.293818ms)
|
||||
✔ class drift within-role to gated refuses before consumption (233.018788ms)
|
||||
✔ class drift within-role to cross-role refuses before consumption (225.003307ms)
|
||||
✔ message.send consumes approval and prevents a later send or authorize (242.309318ms)
|
||||
✔ role.revoke consumes approval and prevents a later revoke or authorize (266.378882ms)
|
||||
✔ REQ-COS-1: the pm asks the chief of staff for roles and counts; the chief receives a STAFF-REQUEST and answers it (266.485672ms)
|
||||
✔ REQ-COS-1: only the pm can send a staff request; every other session is refused and the chief of staff hears nothing (369.579236ms)
|
||||
✔ REQ-COS-1: a pm without message.send is refused like any other gated action (169.003119ms)
|
||||
✔ REQ-COS-1: the request goes to the business launcher, and only when that is a chief of staff (477.534065ms)
|
||||
✔ REQ-COS-1: the sender is judged by definition: an instance `lead` of the pm definition can ask, an instance `pm` of the coder definition can't (421.360891ms)
|
||||
✔ REQ-COS-1: the launcher is judged by definition: an instance `boss` of the chief-of-staff definition receives, a `chief` of the coder definition gives no-chief-of-staff (449.266298ms)
|
||||
✔ REQ-COS-1: a refused staff request leaves no staff.request action.allowed event (250.990314ms)
|
||||
✔ REQ-ASSIST-2: the role definitions' messaging lists hold for a staff request, sender and recipient (676.173728ms)
|
||||
✔ a staff request names a task, 1 to 10 distinct roles and counts of 1 to 20; nothing else is accepted (459.780761ms)
|
||||
✔ REQ-COS-1: a staff request grants nothing: the pm still can't launch and the chief of staff launches as before (227.135461ms)
|
||||
✔ a business that never switched launches reads allowed with no time and no event (139.193708ms)
|
||||
✔ launches revoked and then restored read allowed, with the restore time and event id (212.543725ms)
|
||||
✔ a task closed on the tracker leaves the open list, and total counts the open ones (156.648156ms)
|
||||
✔ a tombstone is not open (139.004831ms)
|
||||
✔ the open list stops at the cap and says so; total still counts every open task (155.941463ms)
|
||||
✔ a role and a reader session read state; arguments, and an unbound cap, refuse (149.634929ms)
|
||||
✔ a human session reads the same state, with the same cap (165.238794ms)
|
||||
✔ reading state writes nothing: every table keeps its row count (178.159594ms)
|
||||
✔ creates private WAL store and excludes a second writer until explicit close (137.355479ms)
|
||||
✔ rollback is atomic and schema metadata is checked against trusted DDL, not just itself (234.403563ms)
|
||||
✔ existing empty database and symlink runtime directory refuse, never initialize over damage (173.340443ms)
|
||||
✔ crash during a transaction recovers no partial event after explicit fixture-only lock removal (186.903789ms)
|
||||
✔ writer refuses mixed at/read_at forms atomically, even through trusted SQL helpers (107.608926ms)
|
||||
✔ async transactions refuse before invoking their function (110.569531ms)
|
||||
✔ the session default fits under the reply cap and pages to the end with next (291.359329ms)
|
||||
✔ the short form: no description, assignees by role, every listed key (286.295723ms)
|
||||
✔ each filter, alone and together, and total counts every match (354.949192ms)
|
||||
✔ task_ref reads one task in full, as the whole board has it (319.29922ms)
|
||||
✔ no arguments is the read the Console and mosaic make, unchanged (279.810421ms)
|
||||
✔ an unknown argument or a bad value refuses invalid-request (984.509234ms)
|
||||
✔ tasks rows carry priority and requirement for every session that reads tasks (376.891538ms)
|
||||
✔ the read model rebuilds from the ledger: a reopened bus and each trail give the same values (361.41104ms)
|
||||
✔ an empty business and one with snapshots but no task.created read cleanly (138.320619ms)
|
||||
✔ recordTask keeps sync reads and a role write apart (232.863401ms)
|
||||
✔ read_at must be one canonical UTC format, so the projection compares strings safely (113.488524ms)
|
||||
✔ a bad entry refuses the whole record (103.358172ms)
|
||||
✔ taskView reads the projection for one business (150.865405ms)
|
||||
✔ requestTask hands only a holder and a task verb to the handler, and records refusals (281.038898ms)
|
||||
✔ the server sends task verbs to the adapter with its own timeout; other verbs stay synchronous (441.965489ms)
|
||||
✔ without an adapter the server refuses every task verb (231.403478ms)
|
||||
✔ the runtime refuses an invalid adapter and closes a valid one (229.186245ms)
|
||||
✔ the process loads the S3 adapter from plain-data trackers (382.33213ms)
|
||||
✔ the tester binds only when the business sets bus.tester to exactly true (888.549975ms)
|
||||
✔ a business may not name a role tester, so the tester address is never a role (267.344754ms)
|
||||
✔ every verb outside the tester list refuses tester-refused and is recorded against the tester (615.641964ms)
|
||||
✔ a tester message is from tester, starts [mos test], and writes no human.input or authority (242.046528ms)
|
||||
✔ a role answers a tester only in reply to a tester message, and the answer never reaches the human (266.143866ms)
|
||||
✔ the tester reads the human views a reader reads (177.707663ms)
|
||||
✔ tester proof binds its own CLI, start time and nonce, refuses a managed run and allows an agent (1.07901ms)
|
||||
✔ neither CLI's nonce proves the other: each proof is bound to its own CLI and nonce variable (0.34943ms)
|
||||
✔ testerNonce reads only the tester's variable and gives null on any read error (0.218829ms)
|
||||
✔ an envelope carries exactly one of cap, human and tester; no tester authenticator refuses (115.582448ms)
|
||||
✔ tester-cli.mjs binds through the runtime when the switch is on, and refuses off or under a run marker (904.291066ms)
|
||||
✔ REQ-THREAD-1 REQ-ORG-2: the 3d→3e migration adds the thread tables and leaves messages from before threads as written (1061.393057ms)
|
||||
✔ REQ-THREAD-1: a 3d bus with a changed schema is refused and keeps its version and tables (897.018349ms)
|
||||
✔ REQ-THREAD-1: the offline command prints the kept-message counts before the ready line (789.475645ms)
|
||||
✔ REQ-ROLE-2 REQ-THREAD-1: one holder per thread, through the broker and the trigger (364.496771ms)
|
||||
✔ REQ-ROLE-2 REQ-THREAD-1: the 3e triggers refuse writes that skip the broker (1244.639016ms)
|
||||
✔ REQ-MSG-1: a message to or from the assistant names its thread, or is refused (396.301411ms)
|
||||
✔ REQ-MSG-1: the chief of staff's reply comes back to the thread that sent the work (3984.784063ms)
|
||||
✔ REQ-MSG-1: a reply can't carry one thread instance's thread to another thread instance (103.979898ms)
|
||||
✔ REQ-THREAD-1 REQ-USER-2: one thread's messages never reach another thread's holder (158.414362ms)
|
||||
✔ REQ-LAUNCH-1: a message to a thread with no holder waits, and the next holder gets it (163.861003ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1: threadIdle releases only a thread with nothing waiting, and only for its holder (172.022656ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1: a message delivered to a run that ended unread doesn't hold up the next holder (148.417933ms)
|
||||
✔ REQ-ROLE-2 REQ-THREAD-1: an approved role.revoke never reaches a thread run, and the thread stays held (135.323552ms)
|
||||
✔ REQ-USER-2: the human verbs refuse another owner's thread (145.617444ms)
|
||||
✔ REQ-THREAD-1: thread.create refuses when the business has no thread instance or more than one (109.817904ms)
|
||||
✔ REQ-ORG-2: projects and threads are named once, and the repo names a business project (160.104333ms)
|
||||
✔ REQ-THREAD-2: thread.messages returns the thread's history in pages and writes nothing (472.151424ms)
|
||||
✔ socket capability stamps launch identity; shared views use wire, no SQL client (158.466321ms)
|
||||
✔ two wire claims serialize; a lost reply never automatically retries (208.010206ms)
|
||||
✔ malformed, oversized and identity-forging envelopes refuse without echoing input (130.715712ms)
|
||||
✔ client preserves UTF-8 when a response divides a multibyte character (11.796966ms)
|
||||
✔ committed mutation followed by dropped reply reports unknown and is never retried (140.679026ms)
|
||||
✔ web.search: a granted role gets labelled results, and the call is trailed with role, run, verb and query (151.466377ms)
|
||||
✔ web.fetch: a granted role gets the page as labelled text, and the call is trailed with the url (202.52736ms)
|
||||
✔ a role without the grant is refused, the refusal is logged with the verb, and nothing is fetched (217.336668ms)
|
||||
✔ a broker with no web service refuses a granted role (157.005894ms)
|
||||
✔ bad requests are refused: unknown verb, extra or missing argument, not a string, a human or reader session (216.927434ms)
|
||||
✔ a session that is not the role holder is refused (128.904908ms)
|
||||
✔ web.mjs's fences hold on the broker side: refusals are normal results with the fixed reason (414.209216ms)
|
||||
✔ web.search with no search source configured is a refused result, not an error (178.468402ms)
|
||||
✔ a search source that fails with its own refusal, or that throws, is handled (211.010558ms)
|
||||
✔ a slow search source ends in a refusal at the deadline (194.002147ms)
|
||||
✔ a secret in the arguments is refused before anything is trailed or fetched (126.703672ms)
|
||||
✔ over the socket: the server routes web verbs to the service; other roles are refused; no service is web-not-configured (235.583377ms)
|
||||
✔ busBusiness: the web grant comes from "web" in the resolved tool limit (0.233348ms)
|
||||
✔ webServices: the business's search-source plug-in and web.searxng var make web.search work; without either it is refused as not configured (215.334338ms)
|
||||
✔ an ungranted call is refused at once: no admission, no wait, nothing touched (179.754718ms)
|
||||
✔ over the socket an ungranted caller is dropped by the server timeout and a granted one gets the longer wait (468.957576ms)
|
||||
✔ a search that never answers is aborted at the deadline, the module sees the signal, and the call is trailed as refused (timeout) (167.18367ms)
|
||||
✔ a fetch that stalls is cut off at the deadline: the request is destroyed, not left running (193.246924ms)
|
||||
✔ one query limit: over SEARCH_MAX_QUERY_CHARS or empty is refused with the same reason before any backend, and the tool schema carries the same number (305.355951ms)
|
||||
ℹ tests 276
|
||||
ℹ suites 0
|
||||
ℹ pass 276
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 11498.151929
|
||||
@@ -0,0 +1,116 @@
|
||||
✔ the role file loads and resolves through loadBusiness (9.29589ms)
|
||||
✔ the shipped file is exactly the approved list (1.170056ms)
|
||||
✔ the assistant's authority is message.send within role and nothing else (2.332318ms)
|
||||
✔ the assistant talks to the user and the chief of staff only, and no other shipped role is limited (0.741145ms)
|
||||
✔ a business grant through limits does not widen the role (2.23023ms)
|
||||
✔ a launch block whose by is the assistant is refused (3.036411ms)
|
||||
✔ the instance takes no credential references and no tracker (4.24926ms)
|
||||
✔ an arbiter whose role definition declares messaging lists is refused, for each kind (5.560694ms)
|
||||
✔ an arbiter without messaging lists is accepted beside the limited assistant (4.708107ms)
|
||||
✔ the contract passes work to the chief of staff and directs no one (0.907494ms)
|
||||
✔ REQ-HARN-2: the assistant holds the web grant, and no other role file does (1.860521ms)
|
||||
✔ config directory and file path follow MOSAIC_CONFIG (2.135871ms)
|
||||
✔ the fixture business validates and comes back frozen (6.845236ms)
|
||||
✔ two instances may share a definition (2.519856ms)
|
||||
✔ top-level refusals (7.767277ms)
|
||||
✔ arbiters and projects (13.870107ms)
|
||||
✔ role instances (11.069582ms)
|
||||
✔ Vikunja bots (6.947659ms)
|
||||
✔ a role without Vikunja takes no tracker block (2.85592ms)
|
||||
✔ credential references match the definition's services (2.593821ms)
|
||||
✔ launch (7.773045ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1 launch.threadIdleSeconds: absent is the default, a positive integer is used, anything else refuses (3.95897ms)
|
||||
✔ loadBusiness: file checks (1.754302ms)
|
||||
✔ loadBusiness: not a regular file (38.4453ms)
|
||||
✔ loading writes nothing (1.014698ms)
|
||||
✔ names that are Object.prototype properties don't count as declared (2.661763ms)
|
||||
✔ the shipped example refuses as written and validates once filled in (0.748449ms)
|
||||
✔ the role file loads and resolves through loadBusiness (9.31659ms)
|
||||
✔ the shipped file is exactly the approved list (0.315532ms)
|
||||
✔ the resolved record matches the approved list, so a widened file fails (2.445784ms)
|
||||
✔ the chief of staff holds role.launch, message.send, role.end and organization.change; every other action is gated (1.956825ms)
|
||||
✔ the pm does not hold role.launch (2.659476ms)
|
||||
✔ a business grant of a gated action through limits does not widen the role (3.550264ms)
|
||||
✔ a limit that drops role.launch leaves the chief of staff with no launch block (1.701328ms)
|
||||
✔ a launch block whose by is the pm instance is refused (4.830348ms)
|
||||
✔ the contract names no duty to talk to the human and the pm contract no launch (0.463198ms)
|
||||
✔ the instance takes no credential references and no tracker (3.981387ms)
|
||||
✔ usage errors exit 4 (288.629481ms)
|
||||
✔ validate: a good business exits 0 and prints instance digests (67.97257ms)
|
||||
✔ validate: project files (305.501067ms)
|
||||
✔ validate: missing files and a broken system config (232.335858ms)
|
||||
✔ validate: credential reference problems exit 2 and name each one (62.9049ms)
|
||||
✔ validate: a token file inside the repository is refused (63.913341ms)
|
||||
✔ validate: role definitions come from MOSAIC_ROLES_DIR (185.482785ms)
|
||||
✔ resolve: prints one instance's record (246.780496ms)
|
||||
✔ resolve: refusals (362.200665ms)
|
||||
✔ parse: exactly one of file or env, plus the service's date (3.620295ms)
|
||||
✔ check: a good file has no problems (1.100838ms)
|
||||
✔ check never opens the file: a write-only token passes (0.519023ms)
|
||||
✔ check: file problems (1.594448ms)
|
||||
✔ check: token files can't live in the repository or dataRoot, even through a linked directory (1.194472ms)
|
||||
✔ check: dates and environment references (0.599474ms)
|
||||
✔ each definition loads, with a contract file, and is exactly the approved list (4.178143ms)
|
||||
✔ an organization file that declares them passes, and each resolves to least privilege (7.55719ms)
|
||||
✔ the chief of staff launches each one; no other role does (5.341511ms)
|
||||
✔ a C-suite role can't be made the launcher: launch.by must hold role.launch (3.852882ms)
|
||||
✔ limits can narrow a C-suite role but never widen it (3.123605ms)
|
||||
✔ any unknown key, tool, action or version in a role file is refused (0.85769ms)
|
||||
✔ REQ-LIMIT-1 schema: every scope unset or zero, adjustable above four, bad values and unknown models refuse (25.33219ms)
|
||||
✔ REQ-LIMIT-1 counts each exact scope at/over limit, unlimited and old tuple after model reassignment (1.143516ms)
|
||||
✔ REQ-ROLE-3 writer: atomic validated revision, immutable previous bytes and authenticated actor/old/new receipt (207.279681ms)
|
||||
✔ REQ-ROLE-3 writer: pre-rename fault leaves old file, post-rename recovery records commit, conflicting recovery refuses (210.5406ms)
|
||||
✔ REQ-LIMIT-1 / decision145 migration prints only, preserves values, rejects ambiguity, and is idempotent (2.911526ms)
|
||||
✔ REQ-LIMIT-1 shared settings validates the complete proposed selection and logs exact actor (176.799891ms)
|
||||
✔ REQ-LIMIT-1 provider is table data: another provider routes separately and aliases share exact counts (1.777541ms)
|
||||
✔ REQ-ROLE-3 refuses live writer locks, symlink targets and uncertain recovery without changing bytes (99.027391ms)
|
||||
✔ REQ-PLUG-1 schema: plugins is optional, names known kinds and checked module names (16.661484ms)
|
||||
✔ REQ-PLUG-1 REQ-ROLE-3 the setter writes plugins through the organization writer and logs old and new names (254.450101ms)
|
||||
✔ vikunja:19/309 a patch changes only the kinds it names; null removes one kind, explicitly and in the trail (304.360478ms)
|
||||
✔ vikunja:19/309 an unknown kind (set or removed), a bad module, an empty patch and null on the wrong shape are refused, nothing written (1.400213ms)
|
||||
✔ REQ-PLUG-1 REQ-ROLE-3 the writer checks the bytes it writes: a Date in plugins is refused there too (35.620259ms)
|
||||
✔ REQ-PLUG-1 REQ-ROLE-3 a refused setter write throws a code, changes nothing and logs nothing (1.513443ms)
|
||||
✔ vikunja:19/305 with an exists check, the setter refuses a module no tree file answers to, before anything is written (89.687665ms)
|
||||
✔ optional project repo is preserved and must be a normalized absolute path (13.473057ms)
|
||||
✔ loaded business project repo cannot be nested in any declared code checkout (6.160658ms)
|
||||
✔ path and load (3.08598ms)
|
||||
✔ refusals (2.012928ms)
|
||||
✔ systemVars flattens the validated config (2.881418ms)
|
||||
✔ precedence: system, business, project, project role, agent (10.045936ms)
|
||||
✔ limits narrow the definition and never widen it (10.794271ms)
|
||||
✔ role.launch stays within-role only for the instance the launch block names (5.414098ms)
|
||||
✔ limits.authority without role.launch leaves the launcher with no launch block (1.92917ms)
|
||||
✔ limits.authority narrows cross-role actions too (1.040391ms)
|
||||
✔ classify (1.033541ms)
|
||||
✔ the record carries what the broker and launcher need (1.217809ms)
|
||||
✔ digest: key order doesn't matter, any value change does (7.414729ms)
|
||||
✔ refusals (2.089232ms)
|
||||
✔ the four shipped version 2 roles load (4.906734ms)
|
||||
✔ shipped role scopes match addendum B section 2 and the SR runbook (1.906849ms)
|
||||
✔ shipped authority follows the note's table (1.342596ms)
|
||||
✔ every role file in roles/ loads through the validator, and a v2 contract exists (1.355798ms)
|
||||
✔ version 1 files keep loading with no authority (7.821305ms)
|
||||
✔ the conductor policy isn't a role (0.231104ms)
|
||||
✔ a missing role file is exit 4, a symbolic link too (0.391111ms)
|
||||
✔ version 2 refusals (1.5083ms)
|
||||
✔ authority: closed vocabulary, no gated-only action, no overlap (2.606897ms)
|
||||
✔ messaging: optional, role definitions and human, never the tester (1.853207ms)
|
||||
✔ credentials: Gitea scopes (0.822247ms)
|
||||
✔ credentials: Vikunja scopes are a group-to-verbs map from the grantable list (0.830299ms)
|
||||
✔ credentials: services (0.461665ms)
|
||||
✔ contract: a non-empty regular Markdown file beside the role file (1.131459ms)
|
||||
✔ every key names known layers and a merge rule (1.409537ms)
|
||||
✔ unknown keys and wrong layers refuse (1.021348ms)
|
||||
✔ types (3.07625ms)
|
||||
✔ merge: defaults, then the most specific layer wins (0.40074ms)
|
||||
✔ merge: limits only narrow, and provenance lists each source (0.436095ms)
|
||||
✔ merge doesn't change its inputs (0.184751ms)
|
||||
✔ web.searxng takes https anywhere and http on loopback, so Jason's 127.0.0.1:8888 passes (0.215465ms)
|
||||
ℹ tests 108
|
||||
ℹ suites 0
|
||||
ℹ pass 108
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1899.103013
|
||||
@@ -0,0 +1,225 @@
|
||||
✔ every screen and overlay fits 120x36, 80x24 and the narrow layout, row for row (1553.124889ms)
|
||||
✔ width counts terminal cells: wide CJK and emoji 2, U+FE0F after a one-cell base 1, marks 0 (70.749122ms)
|
||||
✔ broker text is shown, never interpreted: no raw control character or bidi override reaches the terminal (154.622084ms)
|
||||
✔ NO_COLOR: no escape codes, except reverse video on the selected row (233.708024ms)
|
||||
✔ 1-9 shows the decide flow's own lines and question; only y resolves (347.6136ms)
|
||||
✔ the app shows the same decide text as mosaic decide (126.942285ms)
|
||||
✔ any key but y or Y at the question answers No; nothing is sent (3230.126642ms)
|
||||
✔ below 40x10 the question is hidden, so every key answers it No, y included (Filbert R3) (511.099792ms)
|
||||
✔ under 40 columns a tall terminal shows the too-small screen even where the decide box would fit; y sends nothing (Filbert N10) (2088.772979ms)
|
||||
✔ a hidden decide box names the way out, and the status line under it does not promise y (Filbert N12) (149.050037ms)
|
||||
✔ a throw while answering the question goes to crash, sends nothing and leaves no job pending (170.87012ms)
|
||||
✔ type-ahead never answers the question: a paste, keys typed before it is drawn, keys inside askMs (1228.37667ms)
|
||||
✔ quitting at the question answers No and sends nothing, armed or not (226.434933ms)
|
||||
✔ a timer tick reads nothing under an overlay, never answers the question, and keeps a resolved status (139.782041ms)
|
||||
✔ a long question is cut inside the question; the action, target, choice and prompt stay (Dewey B1) (126.768281ms)
|
||||
✔ a decide box too big for the terminal says so, and every key answers it No, y included (Dewey B1, round 3) (932.724842ms)
|
||||
✔ at every size the decide box shows each line y depends on, or says it is hidden (8357.92467ms)
|
||||
✔ outcome unknown: the CLI's sentence, no retry, then the trail or a re-read (154.115746ms)
|
||||
✔ refused and failed reads keep the last list, marked stale; a refused decide says refused (111.840126ms)
|
||||
✔ help or a detail box cut to fit keeps its last line, Esc included (Dewey) (55.500597ms)
|
||||
✔ keys: views, moving, trail of a selection, the command line, help and quit (231.021983ms)
|
||||
✔ one option: the status line says Press 1, not 1-1 (94.346908ms)
|
||||
✔ no business: the app says so and :business picks one (50.004472ms)
|
||||
✔ mosaic with no argument: exit 3 in an agent run, exit 4 with the usage off a terminal, the app on one (1.763209ms)
|
||||
✔ scripts/mosaic with no argument reaches the app entry; the seat usage it printed before has not drifted (174.654653ms)
|
||||
✔ strings to keep exactly live once, in the decide flow and the transport; the app does not restate them (0.43588ms)
|
||||
✔ decide with --note still asks; a No sends nothing (62.185491ms)
|
||||
✔ the app's business comes from a live bus host only (0.989161ms)
|
||||
✔ runApp leaves the terminal as it found it on q, end of input, SIGTERM, SIGINT, SIGHUP and an error, the first frame's included (6.977997ms)
|
||||
✔ draw is pure: same state, same frame (0.731149ms)
|
||||
✔ recordBootRefused keeps the last good load across refusals; recordBootOk clears the refusal (8.966367ms)
|
||||
✔ an unknown key and a JSON syntax error each leave the bus down with the reason and path in the status (886.187429ms)
|
||||
✔ a missing file is recorded too, and a valid file clears the status on the next start (462.580459ms)
|
||||
✔ inbox lists only decisions routed to the human, with what approving authorizes and how to decide (196.027004ms)
|
||||
✔ decide resolves by id prefix with --yes, and the trail shows it in broker order with the task to follow (147.418501ms)
|
||||
✔ decide refuses without a terminal or --yes, on an unknown option and on a short reference (115.531619ms)
|
||||
✔ decide prints a declining choice as declining (188.628023ms)
|
||||
✔ an unknown outcome is reported once and never resent (173.228871ms)
|
||||
✔ a decision closed before the answer arrives exits 2 and points at its trail (122.080331ms)
|
||||
✔ a prefix that matches two open decisions exits 2 and resolves neither (119.482355ms)
|
||||
✔ without --business a command uses the live host's business, and a stale host.json is not a host (167.236844ms)
|
||||
✔ every human command refuses inside an agent run before it touches the bus (120.313824ms)
|
||||
✔ usage errors exit 4; no business and no host is a usage error (113.076056ms)
|
||||
✔ agents and tasks print through the broker (100.327087ms)
|
||||
✔ notify.json: missing, loose, malformed and extra keys refuse; a binding or null passes (1.36039ms)
|
||||
✔ bootConfig builds the broker's boot message for one business, with no trackers key when no project names one (72.940276ms)
|
||||
✔ trackers come from the tracker.* variables of the one project that names a tracker project (114.14513ms)
|
||||
✔ with two projects, the one that sets tracker.project supplies the tracker and the other is no conflict (61.651974ms)
|
||||
✔ two projects that each name a tracker project refuse, since the boot shape holds one (44.770796ms)
|
||||
✔ a business without tracker.baseUrl gets no trackers entry (35.308334ms)
|
||||
✔ an unknown business and a broken system config refuse with exit 3 (82.537601ms)
|
||||
✔ follow prints an unsolicited message after plain talk returned (256.317595ms)
|
||||
✔ talk --follow continues after reply and prints a later unsolicited message (197.814349ms)
|
||||
✔ inbox lists all unread human messages under decisions, does not deliver or read them (4289.636776ms)
|
||||
✔ follow refuses agent context and bad arguments (702.66954ms)
|
||||
✔ follow Ctrl-C wakes the poll sleep and removes its handler; transport errors also clean up (111.167344ms)
|
||||
✔ plain talk leaves the process SIGINT handlers unchanged (161.970928ms)
|
||||
✔ empty views say so (1.177191ms)
|
||||
✔ the trail keeps the broker's order and names a decision's task without its rows (1.549272ms)
|
||||
✔ tasks print the tracker fields the snapshot carries (0.243063ms)
|
||||
✔ the review loop: the coder pushes and asks, the reviewer fetches and approves, and the task's trail holds each step (962.649311ms)
|
||||
✔ refusals: no action, non-fast-forward, an unknown commit or request, and a push for another task moves only that task's ref (754.210956ms)
|
||||
✔ the size cap refuses a push before any byte (488.747952ms)
|
||||
✔ a fetch over the cap refuses before any byte reaches the reviewer (678.275816ms)
|
||||
✔ the socket refuses a request with no capability, an unknown one, and a bad request line (721.422272ms)
|
||||
✔ a rigged clone runs nothing: hooks, fsmonitor, a filter, a gitlink and a symlinked .git/config leave no marker (2060.254345ms)
|
||||
✔ an identity with no role, or of another business, refuses not-a-role and moves no ref (442.401555ms)
|
||||
✔ a review of a project the business no longer has refuses unknown-project (673.998115ms)
|
||||
✔ past maxActive connections the socket refuses git-busy, and a hung-up connection frees its slot (493.237722ms)
|
||||
✔ close() answers host-closing to a connection still sending its request line (377.330651ms)
|
||||
✔ a bundle that trickles in refuses body-timeout at its deadline and frees its slot (1051.119871ms)
|
||||
✔ a reviewer gone before its bundle was sent is filed fetch-aborted, not as the host's fault (1160.162921ms)
|
||||
✔ a reviewer that hangs up the moment it has the whole bundle was served, not aborted (714.528085ms)
|
||||
✔ send: a close after every byte left is served; one that fails a queued write is fetch-aborted (42.143581ms)
|
||||
✔ a bundle with no bytes for bodyIdle refuses body-timeout long before its deadline (630.149389ms)
|
||||
✔ send: a close once the loop is past its last chunk is served, and a failed write there is fetch-aborted (5.552895ms)
|
||||
✔ letGo waits for an answer to leave for at most its cap, then destroys the socket (301.445719ms)
|
||||
✔ a record that fails and can't be undone refuses rollback-failed, which the host logs (492.978315ms)
|
||||
✔ the host boots the broker, binds a launch in process, and the notifier DMs a blocking decision exactly once (1054.893592ms)
|
||||
✔ a notifier that dies takes the host down with exit 1, so the unit restarts the pair (357.624666ms)
|
||||
✔ a second host for the same data root refuses with exit 3 while the first runs (201.447807ms)
|
||||
✔ two bus starts racing for one data root leave one host running; the other refuses that a host already runs (629.853634ms)
|
||||
✔ a host takes over a host.lock its dead host left, and puts back a live claim that replaced it meanwhile (2.30686ms)
|
||||
✔ a host.lock that goes between the check and the read is tried again; one that can't be parsed still refuses as unreadable (0.871467ms)
|
||||
✔ a live host's lock stays, however old the file is (0.519055ms)
|
||||
✔ a host.lock left by a host killed with SIGKILL doesn't stop the next bus start (979.021135ms)
|
||||
✔ while a host boots, a reader sees no host: the human commands still ask for --business, stop and status find none (211.191797ms)
|
||||
✔ a host started before host.lock existed, holding only host.json, still refuses a second start, which leaves no lock (29.04545ms)
|
||||
✔ a broker fork that throws leaves no host.lock and no host.json (50.705396ms)
|
||||
✔ a broker send that throws leaves no host.lock and no host.json (52.045501ms)
|
||||
✔ a broker that misses its boot wait leaves no host.lock and no host.json (30.505061ms)
|
||||
✔ a notifier fork that throws stops the broker and leaves no host.lock and no host.json (790.644681ms)
|
||||
✔ a notifier send that throws stops the broker and leaves no host.lock and no host.json (1048.091365ms)
|
||||
✔ a boot reply with no reader for the business refuses with exit 3 naming it, before the notifier starts, and leaves no host.lock and no live broker (191.169554ms)
|
||||
✔ a boot reply with no reader for the business refuses with exit 3 naming it, with no notifier, and leaves no host.lock and no live broker (197.264549ms)
|
||||
✔ a host.json that can't be written stops both children and leaves no host.lock (285.819708ms)
|
||||
✔ an error event on the broker before it replies fails the start at once, and leaves no host.lock and no live child (29.137098ms)
|
||||
✔ an error event on the notifier before it replies fails the start at once, and leaves no host.lock and no live child (242.978677ms)
|
||||
✔ an error event on the broker while the notifier starts fails the start once the notifier replies (556.15572ms)
|
||||
✔ an error event on the broker once the host is up stops the host with exit 1, and leaves no host.lock and no host.json (489.20325ms)
|
||||
✔ an error event on the notifier once the host is up stops the host with exit 1, and leaves no host.lock and no host.json (492.25482ms)
|
||||
✔ a broker reply that misses the wait breaks the channel: the late reply answers nothing, later requests refuse, the host exits 1 (1413.872541ms)
|
||||
✔ a broker reply with another request's id, or none, breaks the channel and the host exits 1 (462.155678ms)
|
||||
✔ a broker reply with no request waiting breaks the channel and the host exits 1 (187.380996ms)
|
||||
✔ a notifier that refuses stops the broker and the host refuses with exit 3 (237.565939ms)
|
||||
✔ a notifier that refuses after the broker died still refuses with exit 3, without a send to the dead broker (214.541847ms)
|
||||
✔ a notifier that dies before it replies, after the broker died, still refuses, without a send to the dead broker (181.038549ms)
|
||||
✔ a close send that fails with EPIPE after the notifier refuses still gives the notifier's refusal, exit 3 (236.993814ms)
|
||||
✔ a close send that fails with EPIPE after the notifier dies unanswered still gives the notifier's error (155.794765ms)
|
||||
✔ close() whose stop and close sends fail with EPIPE still finishes, with exit 1 (230.781074ms)
|
||||
✔ watchChildren reports a child that died before it was called, and one that dies later (24.086473ms)
|
||||
✔ bus stop refuses to signal a live pid that is not a bus host (202.351736ms)
|
||||
✔ bus start refuses with exit 3 and the code when the broker refuses to boot; bus status names the lock (277.448103ms)
|
||||
✔ bus start refuses with exit 3 without a notifier config (113.175271ms)
|
||||
✔ bus start runs until bus stop; status reports it while it runs (759.400202ms)
|
||||
✔ bus-service.sh renders the unit and installs it into a given directory (61.567857ms)
|
||||
✔ bus-service.sh pins the claude binary, refuses one the unit can't carry, and renders without one (79.169519ms)
|
||||
✔ bus-service.sh refuses a directory pin and keeps a symlink default unresolved (15.125434ms)
|
||||
✔ bus-service.sh refuses a default claude without the execute bit, or in a PATH dir with a space (10.504379ms)
|
||||
✔ each launch rereads limits and model selections; lowered limits keep sessions and log exact hit (50.491886ms)
|
||||
✔ bus start --pm: the launcher instance (the chief of staff) runs under its own PID namespace, registered, with a manifest (1474.337745ms)
|
||||
✔ the chief of staff launches a coder through its launch tool; the coder answers; refusals name their code (1103.848766ms)
|
||||
✔ a launched pm's request_staff reaches the chief of staff; no other session has the tool and the launch limits still hold (3073.257089ms)
|
||||
✔ each launch makes sure the workspace has a clone of the project: cloned, fast-forwarded, or fetched and logged (2075.347053ms)
|
||||
✔ a project clone that can't be made refuses checkout-failed, from --chief and from a session, with no run and no clone left (625.925278ms)
|
||||
✔ a runner that stops at once ends its launch with the runner's reason (458.847138ms)
|
||||
✔ a Claude Code launch with no session credential refuses before it starts (541.639957ms)
|
||||
✔ a pi launch needs no session credential: pi logs in through its own ENV_ALLOW variables (349.825701ms)
|
||||
✔ a runner killed from the host ends its launch as killed, not failed (335.920551ms)
|
||||
✔ a missing or failing bwrap refuses sandbox-unavailable before anything starts; there is no unconfined fallback (208.682105ms)
|
||||
✔ a real Claude Code coder's shell can't read a stand-in secret or anything else its sandbox doesn't hold (1383.954971ms)
|
||||
✔ 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 (833.756196ms)
|
||||
✔ 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 (3746.088607ms)
|
||||
✔ a malformed sessions.json refuses the host start with exit 3 and stays as it was (147.919687ms)
|
||||
✔ an over-long launch request is refused at once, not at the 10 s idle timeout (173.956985ms)
|
||||
✔ a launch client that never closes its side doesn't hold the host's close (174.105713ms)
|
||||
✔ a runner that ignores SIGTERM is killed when the host closes (1277.608708ms)
|
||||
✔ claudeVersion asks MOSAIC_CLAUDE_BIN when set, else claude on PATH (4.317736ms)
|
||||
✔ migration needs no bus/config, prints whole converted document, is idempotent and never writes (18.599023ms)
|
||||
✔ limits view/set use the human bus transport and pass only the explicit patch (2.581022ms)
|
||||
✔ post-119 example and Jason fixture migrate with checked inherited models; wrong or absent config refuses (273.298633ms)
|
||||
✔ plugins view/set use the human bus transport and pass only the explicit patch (vikunja:19/305) (2.281392ms)
|
||||
✔ zoned uses the IANA zone across DST (24.515663ms)
|
||||
✔ each open blocking decision is DM'd once, across polls and a restart; non-blocking ones are not (188.63433ms)
|
||||
✔ two blocking decisions get two DMs with different nonces (143.332402ms)
|
||||
✔ the digest nonce differs per business and per day and fits Discord's 25 characters (0.287601ms)
|
||||
✔ a failed DM is journaled, backs off, and is retried until it lands (119.466824ms)
|
||||
✔ five definite refusals stop a DM: one gave-up line, one log line, and a restart keeps the count (167.578376ms)
|
||||
✔ 429s, 5xx-style unknowns and refusals without a status never count toward the limit (194.674483ms)
|
||||
✔ a crash between the fifth refusal and its gave-up line: the next poll appends it and sends nothing (123.816442ms)
|
||||
✔ 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 (219.114022ms)
|
||||
✔ a restart after the second refusal does not send before that refusal's 30 min are up (248.191592ms)
|
||||
✔ the digest goes at 08:00 Chicago once a day, with blocking ones marked as DM'd (134.846508ms)
|
||||
✔ a late start with no digest for the day sends one at once; an empty inbox gets one line (96.133815ms)
|
||||
✔ an inbox read failure is logged and the next poll retries (0.712957ms)
|
||||
✔ no Discord id reaches the journal or the log (252.760705ms)
|
||||
✔ the journal: a torn tail is copied out and truncated, so an append after it reopens cleanly (26.54626ms)
|
||||
✔ the journal: a crash between the copy and the truncate leaves a tail the next open repairs (55.088651ms)
|
||||
✔ the journal: a whole file that is one torn line truncates to empty (28.677726ms)
|
||||
✔ the journal: a malformed complete line refuses and leaves the file and any torn tail alone (2.55322ms)
|
||||
✔ the journal: a loose file mode, a loose directory or a symlinked journal refuses (1.083892ms)
|
||||
✔ the journal: a line with a wrong type refuses with exit 3 and names the field (9.36631ms)
|
||||
✔ the journal: a symlinked directory refuses and says it is a link (0.451727ms)
|
||||
✔ the journal: a dangling directory link, a parent that is a file and a journal that is a directory each refuse with exit 3 (0.537978ms)
|
||||
✔ the journal: an append after the file was swapped for a symlink refuses and writes nothing through it (0.43787ms)
|
||||
✔ the journal: a directory it cannot write or create refuses with exit 3 and names the path (0.503585ms)
|
||||
✔ digest content stays within Discord's 2000 characters (0.31147ms)
|
||||
✔ runLoop never overlaps ticks and stops after the one in flight (110.932405ms)
|
||||
✔ a human command refused with human-required prints the other-tree line and exits 3 (3.742956ms)
|
||||
✔ a --tester command refused with tester-required prints the other-tree line and exits 3 (1.286152ms)
|
||||
✔ other exit-3 refusals print no other-tree line (1.788963ms)
|
||||
✔ the line names no path (0.112178ms)
|
||||
✔ project init/check use declared business repo and never contact the bus (188.529642ms)
|
||||
✔ project commands validate args and refuse undeclared projects and agent init (43.279346ms)
|
||||
✔ project dispatcher reaches the human CLI (121.236216ms)
|
||||
✔ shared copy: npm ci, pushed reachability, readonly/existing copy, webui delegation (706.092889ms)
|
||||
✔ wrapper preserves Q81 lease and marker, rejects foreign/symlink; check uses effective roots (507.9073ms)
|
||||
✔ bus unit copy/pm pins, install refuses all busy states and failed reads, drop-in refusal (479.150721ms)
|
||||
✔ missing package manifest refuses before npm; npm failure removes the unpublished temp copy (406.449401ms)
|
||||
✔ real pinned install loads bus and Console; same-copy mosaic talk passes proof, other trees refuse (4663.790696ms)
|
||||
✔ bus status reads effective copy/pm/drop-ins without writes; check refuses an overridden ExecStart (831.474607ms)
|
||||
✔ drop-ins in either override field and malformed metadata refuse; uninstall also checks --no-reload (330.783865ms)
|
||||
✔ install never shows a template name on systemd 261; template drop-ins still refuse (323.989336ms)
|
||||
✔ unlisted instance drop-in is found in another unit lookup directory; path discovery errors refuse (223.333614ms)
|
||||
✔ inherited mosaic-.service.d override refuses without changing the unit (273.798206ms)
|
||||
✔ inherited service.d override refuses without changing the unit (311.839389ms)
|
||||
✔ inherited drop-in unreadable directory or file refuses before writing (380.038827ms)
|
||||
✔ talk --tester sends a [mos test] message as tester from inside an agent and prints the role's reply (177.324943ms)
|
||||
✔ talk --tester refuses text without the [mos test] prefix before any call (111.649651ms)
|
||||
✔ the read verbs take --tester inside an agent, and the trail shows the tester as the sender (119.377535ms)
|
||||
✔ decide, stop and launches take no --tester (205.88273ms)
|
||||
✔ the tester transport runs tester-cli.mjs, and the tester's refusals exit 3 (0.396064ms)
|
||||
✔ with no stand-in transport, --tester runs tester-cli.mjs on the data root's socket (0.57788ms)
|
||||
✔ talk --tester to a stopped role says nobody is told to launch it (150.550565ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1 REQ-MSG-1 a thread message starts the thread's session, which stops when idle; its history survives the stop and a restart and no other thread sees it (6588.741941ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1 a running thread counts against its model's limit and an idle-stopped one doesn't (1906.245773ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1 a turn longer than the idle time isn't stopped, and the thread idles out after it (4773.324094ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1 a message sent after the idle snapshot keeps the session, which answers it (2886.680209ms)
|
||||
✔ REQ-ROLE-2 REQ-LAUNCH-1 a thread held by a run the launcher didn't start gets no second session (128.605485ms)
|
||||
✔ REQ-LAUNCH-1 a run that ends without taking its thread's message isn't started again for that message (241.669128ms)
|
||||
✔ REQ-THREAD-2 REQ-LAUNCH-1 a thread id that isn't a safe segment, or a thread of a non-thread instance, launches nothing (260.747959ms)
|
||||
✔ REQ-THREAD-1 REQ-LAUNCH-1 the chief can't launch the assistant outside a thread (85.179838ms)
|
||||
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 (471.976237ms)
|
||||
✔ the transport writes {business, verb, args} to the child and reads its JSON (42.823695ms)
|
||||
✔ a bus code on stderr becomes the exit code; garbage and timeouts are outcome problems (2181.124488ms)
|
||||
✔ busExit and refuseInsideAgent (0.492424ms)
|
||||
✔ talk sends a REQUEST, prints and reads only the reply to it, and leaves other messages unread (332.348659ms)
|
||||
✔ talk --wait 0 only sends; no reply within --wait exits 1 and says where it will show (1139.176529ms)
|
||||
✔ a late reply the Console has listed stays unread for mosaic inbox, and the next talk skips it (2307.35447ms)
|
||||
✔ talk says when the role isn't running, whether launch.by was told, and how to start launch.by (1289.691381ms)
|
||||
✔ talk to a role launch.by can't launch says it isn't in the launch block (132.127763ms)
|
||||
✔ talk to a stopped role prints the waiting line once, skips a non-reply and prints the reply (240.377042ms)
|
||||
✔ talk, stop and launches off/on refuse inside an agent run; bad arguments are usage errors (129.64187ms)
|
||||
✔ launches off and on go to the broker and change the business's launch state (118.975429ms)
|
||||
✔ launches list reads sessions.json and marks a stale entry; stop reports it and refuses a non-runner (107.461471ms)
|
||||
ℹ tests 215
|
||||
ℹ suites 0
|
||||
ℹ pass 215
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 20787.262539
|
||||
@@ -0,0 +1,123 @@
|
||||
✔ the Board: held roles with no machine sessions, a claim with no address, the toggle kept across a reload, and Message addressed to the role (6552.409057ms)
|
||||
✔ a redirect answer on a Board read, a bus read, a conversation read, a board POST, a module read and a send signs the page out: one line, nothing stale, no further reads (8481.653749ms)
|
||||
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (5063.217956ms)
|
||||
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
|
||||
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (5287.805963ms)
|
||||
✔ the README says a refused field table names the file or the key at fault, never a path (1.487557ms)
|
||||
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (7696.285468ms)
|
||||
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (364.25131ms)
|
||||
✔ decisions route serves the roles and recent lists from the reader view (509.530753ms)
|
||||
✔ credentials route serves the broker credential status from the reader view (379.944035ms)
|
||||
✔ replies route serves the replies to one message from the reader view (845.245622ms)
|
||||
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (273.614007ms)
|
||||
✔ bus refusals map to statuses and never carry a path or a stack (145.272377ms)
|
||||
✔ humanCall speaks the human transport protocol without blocking the server (1962.944927ms)
|
||||
✔ busReader takes --business, else the live bus host, else refuses (308.115766ms)
|
||||
✔ humanCall kills a transport that runs past its timeout (528.76767ms)
|
||||
✔ serve refuses a --business value that is not a business id (565.635473ms)
|
||||
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (4211.27989ms)
|
||||
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (3675.126155ms)
|
||||
✔ conversation view: a newer session with no readable history keeps the marker (2644.14613ms)
|
||||
✔ conversation view: seats without history say so and offer no reply (2998.426321ms)
|
||||
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (4672.266586ms)
|
||||
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (54143.625734ms)
|
||||
✔ messages HTTP read pages and preserves metadata; bad arguments refuse before a read; other reads unchanged (459.514865ms)
|
||||
✔ Console Messages lists late unsolicited messages on polling with sender class time read state and trail; nav count includes beyond the page; reads never deliver (10594.976417ms)
|
||||
✔ Messages nav count polls on Tasks and Board and clears on a Board refusal; messages 403 refuses local pages (4331.033207ms)
|
||||
✔ copy writes the Console paths at the full id, read-only, and leaves an existing copy alone (3203.83571ms)
|
||||
✔ copy refuses a commit off refactor, an unknown one, a worktree and a bad copies directory (8589.496783ms)
|
||||
✔ copy writes nothing when an archived path is missing at the commit (739.698545ms)
|
||||
✔ a copy that loses the rename race leaves no read-only temp directory behind (1399.366035ms)
|
||||
✔ a copy whose rename fails with no target refuses, writes no copy and leaves no temp directory (1443.986615ms)
|
||||
✔ a copy that meets a target holding files says exists: and moves nothing into it (444.11678ms)
|
||||
✔ a copy that meets an empty target directory replaces it by rename, not by moving into it (375.14829ms)
|
||||
✔ serve runs from a copy: /healthz 200, the config check, roles and RELEASE from the copy, the queue from --checkout (665.203643ms)
|
||||
✔ serve refuses a --checkout that is not an absolute directory path (224.264826ms)
|
||||
✔ consoleReads runs the queue read under queueRoot and reads RELEASE under root (47.327432ms)
|
||||
✔ preview options are all three or none, and each is checked (11.919129ms)
|
||||
✔ the CLI refuses a partial or invalid preview flag set at start (2834.89801ms)
|
||||
✔ the CLI with all three flags serves the preview mode (232.107379ms)
|
||||
✔ a request for the public name needs the header equal to the user id, else 401 and nothing read (21.902851ms)
|
||||
✔ the header name matches without regard to case, and the value compare is exact (4.1968ms)
|
||||
✔ the public name with the header reads the bus views, and the Host and Origin are checked first (42.400818ms)
|
||||
✔ in preview mode every write answers 403 read-only, from the public name and loopback, and reaches nothing (17.471944ms)
|
||||
✔ loopback requests are unchanged in preview mode, and the bus views work with the board down (7.678735ms)
|
||||
✔ a proxy that rewrites Host to the loopback port gets 403 on its first request, whatever the user (24.805898ms)
|
||||
✔ a repeated Host is 400 before any other check, in preview mode and without it (10.29713ms)
|
||||
✔ without the preview flags the public name is refused and writes still reach the board (5.503878ms)
|
||||
✔ redactor: config, dataRoot, any absolute path, Discord ids and the JSON parser quote (2.279642ms)
|
||||
✔ credential state from the date alone, as the bus states it (0.270305ms)
|
||||
✔ queue: rows, one row, ids and methods, notes; no path or id from a row (2068.408945ms)
|
||||
✔ queue: a refused read fails closed with the store's text, redacted (1310.861817ms)
|
||||
✔ queue: a store that fails to load, or a child that dies, gives a fixed message with no path or stack (3848.722755ms)
|
||||
✔ business: names, vars on the allowlist, authority, credential metadata only (18.774655ms)
|
||||
✔ business: missing or invalid file refuses with the module's text, redacted (28.836445ms)
|
||||
✔ business without --business: the live bus host, else no-bus-host; no system config: not-configured (11.524425ms)
|
||||
✔ settings: release, board, loopback address, notifier binding name only (728.930884ms)
|
||||
✔ task fields: the committed table with no reads configured, GET only; a bad table refuses with no path (208.400387ms)
|
||||
✔ bus-status: a refused boot shows reason, file and last good load; a live host or an ok boot clears it (115.015829ms)
|
||||
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (4243.832964ms)
|
||||
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (23022.801528ms)
|
||||
✔ the send box: held roles, the draft and caret across a refresh, each receipt, one POST per Send, and the trail link; the board Reply on a 4xx and a 5xx (6739.378909ms)
|
||||
✔ a sent receipt lists its replies as the page refreshes, oldest first and capped, and marks none delivered or read (13655.158099ms)
|
||||
✔ startServer takes send only as a function and only with the preview mode (6.022255ms)
|
||||
✔ the CLI refuses --send without the preview flags, and without a configured bus (399.224104ms)
|
||||
✔ the CLI with --send and a configured bus sends through the human transport and logs one line (171.780579ms)
|
||||
✔ without --send the route is read-only like every other write, and config says no send (10.436835ms)
|
||||
✔ with --send every other write is still 403 read-only, and nothing reaches the board or bus (8.589808ms)
|
||||
✔ config says send only on the public name with --send on (3.03649ms)
|
||||
✔ a send without the signed-in user is 401 and is neither sent nor logged, loopback included (5.668737ms)
|
||||
✔ each request check refuses before anything is sent, and logs the refusal without the body (18.17362ms)
|
||||
✔ a send passes exactly to, body and in_reply_to, answers the id, and logs it (3.823539ms)
|
||||
✔ a crafted role name cannot forge a log line (3.202576ms)
|
||||
✔ a bus refusal is not sent, with its status; an outcome the bus could not confirm is unknown and never retried (7.892797ms)
|
||||
✔ through the human transport the request is exactly the business, message.send and the keys (180.653985ms)
|
||||
✔ against a real broker: the message is written once as a human send, and its refusals map (985.633929ms)
|
||||
✔ loopback host and board origin fail closed (6.454116ms)
|
||||
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (336.633377ms)
|
||||
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (44.573353ms)
|
||||
✔ unreachable board reports URL; CLI rejects unsupported options (492.078957ms)
|
||||
✔ render prints the unit without the preview flags (9.797762ms)
|
||||
✔ render carries every serve flag, the preview set included (7.339677ms)
|
||||
✔ a partial preview set is refused (22.429815ms)
|
||||
✔ a value the unit cannot carry is refused, for every flag (330.124325ms)
|
||||
✔ the rendered unit names none of the human proof agent markers and sets no agent variable (34.724544ms)
|
||||
✔ install into --dir with --no-reload writes the file whole, then reports unchanged (185.755487ms)
|
||||
✔ install without --no-reload runs daemon-reload and nothing that starts the unit (100.807861ms)
|
||||
✔ uninstall refuses while the unit is running, with or without --no-reload, and removes it once it is not (715.841717ms)
|
||||
✔ status prints the unit state and GET /healthz on the installed port (605.064003ms)
|
||||
✔ usage: an unknown verb or flag, and start or enable, exit 4 (152.87157ms)
|
||||
✔ without --send, render is the template with its placeholders filled, byte for byte (48.524689ms)
|
||||
✔ render --send with the preview set ends ExecStart with --send and changes nothing else (68.240313ms)
|
||||
✔ --send without the whole preview set is refused and writes nothing (175.368903ms)
|
||||
✔ install --send into --dir with --no-reload writes the sending unit, and status says whether it sends (345.109225ms)
|
||||
✔ uninstall and status take no --send (105.03683ms)
|
||||
✔ install refuses while the unit is running, in any state but inactive or failed, and changes nothing (588.318622ms)
|
||||
✔ when the state read fails, install and uninstall refuse with one line and change nothing (170.270036ms)
|
||||
✔ install needs --copy naming a copy that exists, and refuses outside the canonical checkout without --allow-worktree (130.141813ms)
|
||||
✔ install refuses unless the bus unit runs from the same copy, naming both paths, and changes nothing (325.302751ms)
|
||||
✔ render --copy runs the copy and reads the queue in the checkout; without --copy the unit is unchanged (18.604849ms)
|
||||
✔ the uid header takes only an Authentik uid; the username header still takes a username (352.153098ms)
|
||||
✔ a preview value cannot start with - or . (30.817542ms)
|
||||
✔ status names the copy and whether refactor has moved past it, and says when the unit runs from no copy (525.5428ms)
|
||||
✔ Settings form shows every scope and held role; gated save, exact payload, retained draft and no automatic retry (3857.795901ms)
|
||||
2026-10-16T00:43:27.703Z settings user="jason" changed
|
||||
✔ REQ-WEB-1 signed-in same-origin Settings write reaches exactly one human operation (28.756419ms)
|
||||
✔ REQ-WEB-1 Settings writes require enabled send, named Host, identity, exact Origin and same-origin Fetch Metadata (12.907042ms)
|
||||
✔ REQ-WEB-1 Settings validates JSON, size, revision and strict writable keys before broker call (11.661918ms)
|
||||
✔ tokens.css and icons.svg are byte copies of docs/design (1.326589ms)
|
||||
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (2.699686ms)
|
||||
✔ shipped strings are unchanged, and the web keeps its write boundary (3.296736ms)
|
||||
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (7497.722753ms)
|
||||
✔ five states on Board, Inbox, Tasks, Agents and Trail (3215.913554ms)
|
||||
✔ Queue, Business and Settings in their five states, with no move button (5051.221061ms)
|
||||
✔ seeded secrets, Discord ids and paths reach no response and no page; business refusals in the module's words (3267.908769ms)
|
||||
✔ the server log names no config path when the system config refuses (447.701863ms)
|
||||
ℹ tests 113
|
||||
ℹ suites 0
|
||||
ℹ pass 113
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 54633.549276
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,82 @@
|
||||
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/copy-service.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/offline-check.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 183)
|
||||
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
|
||||
OK pinned render runs copy CLI with copy cwd/repo and no checkout executable
|
||||
OK pinned install writes the rendered unit in a temporary unit directory
|
||||
OK pinned install refuses short prerequisite and writes no unit
|
||||
OK pinned install refuses missing prerequisite and writes no unit
|
||||
OK pinned install refuses cli prerequisite and writes no unit
|
||||
OK pinned install refuses pi prerequisite and writes no unit
|
||||
OK status names the copy from fake systemctl effective cwd
|
||||
OK checkout install explicitly recommends --copy
|
||||
OK wrapper check --offline passes local fixture and makes no network call
|
||||
OK wrapper run --offline refuses usage
|
||||
|
||||
discord suite: 78 passed, 0 failed
|
||||
@@ -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: 3419765 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
|
||||
@@ -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
|
||||
@@ -0,0 +1,86 @@
|
||||
OK args: exit 2, target-branch
|
||||
OK args: exit 2, target-branch
|
||||
OK args: exit 4
|
||||
OK args: exit 4
|
||||
OK args: exit 4
|
||||
OK --base next refuses before the config is read (got 2)
|
||||
OK a missing system config exits 3 (got 3)
|
||||
OK nobus: exit 3
|
||||
OK schema-table: exit 2, bus-schema
|
||||
OK schema-meta: exit 2, bus-schema
|
||||
OK openBus opens the database read-only
|
||||
OK other-business: exit 2, decision-not-found
|
||||
OK no-raise: exit 2, decision-not-found
|
||||
OK not-a-merge: exit 2, not-a-merge
|
||||
OK open: exit 2, not-resolved
|
||||
OK withdrawn: exit 2, not-resolved
|
||||
OK by-agent: exit 2, not-human
|
||||
OK via-webui: exit 2, not-human
|
||||
OK no-answer: exit 2, not-human
|
||||
OK answer-role: exit 2, not-human
|
||||
OK answer-run: exit 2, not-human
|
||||
OK answer-choice: exit 2, not-human
|
||||
OK two-answers: exit 2, not-human
|
||||
OK chose-no: exit 2, not-merge-option
|
||||
OK two-refs: exit 2, work-ref
|
||||
OK bad-ref: exit 2, work-ref
|
||||
OK task-ref-disagrees: exit 2, work-ref
|
||||
OK raise-task-disagrees: exit 2, work-ref
|
||||
OK target-main: exit 2, target-branch
|
||||
OK superseded-question: exit 2, superseded
|
||||
OK superseded-task: exit 2, superseded
|
||||
OK superseded-by: exit 2, superseded
|
||||
OK no-verdict: exit 2, no-verdict
|
||||
OK changes-later: exit 2, not-approved
|
||||
OK short-commit: exit 2, not-approved
|
||||
OK wrong-task-body: exit 2, not-approved
|
||||
OK args: exit 2, decision-not-found
|
||||
OK earlier-merge: exit 0
|
||||
OK ref-moved: exit 2, ref-moved
|
||||
OK root-top: exit 2, root-file
|
||||
OK root-newdir: exit 2, root-file
|
||||
OK root-src: exit 2, root-file
|
||||
OK unrelated: exit 2, base-conflict
|
||||
OK empty: exit 2, base-conflict
|
||||
OK an empty reviewed diff says so
|
||||
OK dirty-changed: exit 2, checkout-dirty
|
||||
OK dirty-staged: exit 2, checkout-dirty
|
||||
OK dirty-untracked: exit 2, checkout-dirty
|
||||
OK conflict: exit 2, base-conflict
|
||||
OK a refusal after the worktree is added leaves no worktree or scratch
|
||||
OK cleanup looks for the worktree's Docker network
|
||||
OK dirty-during: exit 2, checkout-dirty
|
||||
OK a reviewed path dirtied during the gate moves no ref
|
||||
OK drift: exit 2, patch-drift
|
||||
OK patch-drift leaves no worktree or scratch
|
||||
OK gate-pkg: exit 2, gate-failed
|
||||
OK gate-failed names the failing step's log, and it exists
|
||||
OK gate-failed leaves no worktree or scratch
|
||||
OK gate-script: exit 2, gate-failed
|
||||
OK a failing scripts/test-*.sh fails the gate
|
||||
OK a failed gate moves no ref
|
||||
OK nomods: exit 4
|
||||
OK a target without node_modules leaves no worktree or scratch
|
||||
OK moved: exit 2, base-moved
|
||||
OK base-moved keeps the base where it moved to
|
||||
OK dry: exit 0
|
||||
OK --dry-run writes no ref
|
||||
OK --dry-run prints the commit with --subject and --attribution
|
||||
OK --dry-run runs the gate
|
||||
OK --dry-run leaves no worktree or scratch
|
||||
OK land: exit 0
|
||||
OK the landing is one commit on the old base
|
||||
OK its diff is the reviewed diff by patch-id
|
||||
OK its tree is the dry run's
|
||||
OK the message has the option's subject, the citations and the attribution last
|
||||
OK it prints the line for the PM
|
||||
OK the checked-out base has the reviewed paths and keeps the unrelated edit
|
||||
OK only refs/heads/refactor exists in the target
|
||||
OK the work ref is unchanged
|
||||
OK the bus database is unchanged
|
||||
OK the gate ran each package suite but queue, and each scripts/test-*.sh
|
||||
OK the landing leaves no worktree or scratch
|
||||
OK the target's node_modules is still there, with its contents
|
||||
OK the worktree's Docker network is removed
|
||||
---
|
||||
land-work selftests: 84 passed, 0 failed
|
||||
@@ -0,0 +1,36 @@
|
||||
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/gate-owner.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 156
|
||||
ℹ pass 156
|
||||
ℹ fail 0
|
||||
OK node --test packages/queue/tests/
|
||||
OK scripts/mosaic queue help
|
||||
skip queue verify and render --check: this checkout (/home/jwoltje/dewey-scratch/r152/wt) is not the queue's canonical root (/mnt/storage/src/mosaic-stack)
|
||||
|
||||
queue suite: 28 passed, 0 failed
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
start 2026-10-16T00:41:24Z
|
||||
B1-always-launchable KILLED rc=1 | a message to a role outside launch.instances says so in its result and in the notice | no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance
|
||||
B2-no-block-false KILLED rc=1 | a business with no launch block tells nobody and says there is no launcher
|
||||
B3-launcher-launchable KILLED rc=1 | no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance
|
||||
B4-not-told-unlaunchable KILLED rc=1 | a message to a role outside launch.instances says so in its result and in the notice
|
||||
B5-launch-text-always KILLED rc=1 | a message to a role outside launch.instances says so in its result and in the notice
|
||||
B6-field-dropped KILLED rc=1 | a business with no launch block tells nobody and says there is no launcher | a message to a role outside launch.instances says so in its result and in the notice | a message to a stopped role sends launch.by one notice, and the result says so | no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance
|
||||
C1-no-launch-block-line KILLED rc=1 | talk to a role launch.by can't launch says it isn't in the launch block
|
||||
C2-restart-after-line KILLED rc=1 | talk to a role launch.by can't launch says it isn't in the launch block
|
||||
restored True
|
||||
end 2026-10-16T00:41:36Z rc=0
|
||||
@@ -0,0 +1,52 @@
|
||||
import subprocess, sys, os, signal
|
||||
# Row 152 (#1646): one mutant per new check. Each applies to its source in the worktree, runs the
|
||||
# owning test file, and the source is restored after every mutant.
|
||||
W=os.path.expanduser('~/dewey-scratch/r152/wt')
|
||||
OUT=os.path.expanduser('~/dewey-scratch/r152/mut')
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
BROKER='packages/bus/src/broker.mjs'
|
||||
CLI='packages/cli/src/cli.mjs'
|
||||
BUS=('packages/bus', 'tests/launch-notice.test.mjs')
|
||||
VERBS=('packages/cli', 'tests/verbs.test.mjs')
|
||||
LAUNCHABLE='const launchable = launch ? launch.instances.includes(to) : null;'
|
||||
TOLD="const told = by !== null && to !== by && sender !== by && sender !== 'tester';"
|
||||
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`;\n'
|
||||
M={
|
||||
# Every target counts as launchable.
|
||||
'B1-always-launchable': (BROKER, *BUS, LAUNCHABLE, 'const launchable = launch ? true : null;'),
|
||||
# No launch block reads as false instead of null.
|
||||
'B2-no-block-false': (BROKER, *BUS, LAUNCHABLE, 'const launchable = launch ? launch.instances.includes(to) : false;'),
|
||||
# launch.by itself counts as launchable.
|
||||
'B3-launcher-launchable': (BROKER, *BUS, LAUNCHABLE, 'const launchable = launch ? launch.instances.includes(to) || to === launch.by : null;'),
|
||||
# launch.by isn't told when the target isn't launchable (the call BUILD.md argues against).
|
||||
'B4-not-told-unlaunchable': (BROKER, *BUS, TOLD, TOLD[:-1] + ' && launchable !== false;'),
|
||||
# The notice keeps row 146's launch text for every target.
|
||||
'B5-launch-text-always': (BROKER, *BUS, ' launchable\n ? `', ' true\n ? `'),
|
||||
# The field is dropped from the result.
|
||||
'B6-field-dropped': (BROKER, *BUS, 'this.#recipient(s.business, by, null) !== null, launchable };', 'this.#recipient(s.business, by, null) !== null };'),
|
||||
# talk drops the launch-block line and prints "has been told".
|
||||
'C1-no-launch-block-line': (CLI, *VERBS, LINE, ''),
|
||||
# talk adds launch.by's restart line after the launch-block line.
|
||||
'C2-restart-after-line': (CLI, *VERBS, LINE, LINE.replace('can\'t launch it\\n`;', 'can\'t launch it\\n` + (w.launcherRunning ? "" : restart(w.launcher, " either"));')),
|
||||
}
|
||||
env=dict(os.environ, TMPDIR=os.path.expanduser('~/dewey-scratch/tmp'))
|
||||
origs={p: open(os.path.join(W,p)).read() for p in (BROKER, CLI)}
|
||||
try:
|
||||
for name,(path,pkg,test,a,b) in M.items():
|
||||
orig=origs[path]
|
||||
assert orig.count(a)==1, name
|
||||
assert a!=b, name
|
||||
open(os.path.join(W,path),'w').write(orig.replace(a,b))
|
||||
p=subprocess.Popen(['node','--test','--test-reporter=spec',test],cwd=os.path.join(W,pkg),env=env,
|
||||
stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True,start_new_session=True)
|
||||
try:
|
||||
out,_=p.communicate(timeout=300)
|
||||
except subprocess.TimeoutExpired:
|
||||
os.killpg(p.pid, signal.SIGKILL); out,_=p.communicate(); out+='\nTIMEOUT\n'
|
||||
fails=sorted({l.strip()[2:].split(' (')[0] for l in out.splitlines() if l.lstrip().startswith('✖') and 'failing tests' not in l})
|
||||
print(name, 'KILLED' if p.returncode!=0 else 'SURVIVED', 'rc=%d'%p.returncode, '| '+' | '.join(fails))
|
||||
open(os.path.join(OUT,f'{name}.log'),'w').write(out)
|
||||
open(os.path.join(W,path),'w').write(orig)
|
||||
finally:
|
||||
for path,orig in origs.items(): open(os.path.join(W,path),'w').write(orig)
|
||||
print('restored', all(open(os.path.join(W,p)).read()==o for p,o in origs.items()))
|
||||
@@ -0,0 +1,76 @@
|
||||
✔ a message to a stopped role sends launch.by one notice, and the result says so (88.661715ms)
|
||||
✖ a message to a role outside launch.instances says so in its result and in the notice (51.142699ms)
|
||||
✔ a message to a running role sends no notice and its result is unchanged (56.07053ms)
|
||||
✔ a re-route at a claim, a release and claim, and a broker restart send no second notice (101.922194ms)
|
||||
✔ a run launched but not yet claimed counts as no holder (51.026354ms)
|
||||
✖ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (45.514785ms)
|
||||
✔ a business with no launch block tells nobody and says there is no launcher (43.784101ms)
|
||||
✔ the notice sender stays internal: no role is named _bus and no caller can send as it or to it (151.114019ms)
|
||||
ℹ tests 8
|
||||
ℹ suites 0
|
||||
ℹ pass 6
|
||||
ℹ fail 2
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 645.823856
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/launch-notice.test.mjs:112:1
|
||||
✖ a message to a role outside launch.instances says so in its result and in the notice (51.142699ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
+ launchable: true,
|
||||
- launchable: false,
|
||||
launcher: 'chief',
|
||||
launcherRunning: false,
|
||||
role: 'coder',
|
||||
told: true
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:115: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 startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { role: 'coder', launcher: 'chief', told: true, launcherRunning: false, launchable: true },
|
||||
expected: { role: 'coder', launcher: 'chief', told: true, launcherRunning: false, launchable: false },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at tests/launch-notice.test.mjs:170:1
|
||||
✖ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (45.514785ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
+ launchable: true,
|
||||
- launchable: false,
|
||||
launcher: 'chief',
|
||||
launcherRunning: false,
|
||||
role: 'chief',
|
||||
told: false
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:173: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: { role: 'chief', launcher: 'chief', told: false, launcherRunning: false, launchable: true },
|
||||
expected: { role: 'chief', launcher: 'chief', told: false, launcherRunning: false, launchable: false },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
✔ a message to a stopped role sends launch.by one notice, and the result says so (85.991542ms)
|
||||
✔ a message to a role outside launch.instances says so in its result and in the notice (64.902256ms)
|
||||
✔ a message to a running role sends no notice and its result is unchanged (56.863323ms)
|
||||
✔ a re-route at a claim, a release and claim, and a broker restart send no second notice (95.780681ms)
|
||||
✔ a run launched but not yet claimed counts as no holder (47.757687ms)
|
||||
✔ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (110.732728ms)
|
||||
✖ a business with no launch block tells nobody and says there is no launcher (44.048009ms)
|
||||
✔ the notice sender stays internal: no role is named _bus and no caller can send as it or to it (149.650889ms)
|
||||
ℹ tests 8
|
||||
ℹ suites 0
|
||||
ℹ pass 7
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 710.43911
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/launch-notice.test.mjs:210:1
|
||||
✖ a business with no launch block tells nobody and says there is no launcher (44.048009ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
+ launchable: false,
|
||||
- launchable: null,
|
||||
launcher: null,
|
||||
launcherRunning: null,
|
||||
role: 'pm',
|
||||
told: false
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:212: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: { role: 'pm', launcher: null, told: false, launcherRunning: null, launchable: false },
|
||||
expected: { role: 'pm', launcher: null, told: false, launcherRunning: null, launchable: null },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
✔ a message to a stopped role sends launch.by one notice, and the result says so (87.215916ms)
|
||||
✔ a message to a role outside launch.instances says so in its result and in the notice (66.273715ms)
|
||||
✔ a message to a running role sends no notice and its result is unchanged (54.285379ms)
|
||||
✔ a re-route at a claim, a release and claim, and a broker restart send no second notice (136.69995ms)
|
||||
✔ a run launched but not yet claimed counts as no holder (72.185667ms)
|
||||
✖ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (45.146228ms)
|
||||
✔ a business with no launch block tells nobody and says there is no launcher (48.487126ms)
|
||||
✔ the notice sender stays internal: no role is named _bus and no caller can send as it or to it (153.024392ms)
|
||||
ℹ tests 8
|
||||
ℹ suites 0
|
||||
ℹ pass 7
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 717.470304
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/launch-notice.test.mjs:170:1
|
||||
✖ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (45.146228ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
+ launchable: true,
|
||||
- launchable: false,
|
||||
launcher: 'chief',
|
||||
launcherRunning: false,
|
||||
role: 'chief',
|
||||
told: false
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:173: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: { role: 'chief', launcher: 'chief', told: false, launcherRunning: false, launchable: true },
|
||||
expected: { role: 'chief', launcher: 'chief', told: false, launcherRunning: false, launchable: false },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
✔ a message to a stopped role sends launch.by one notice, and the result says so (88.032211ms)
|
||||
✖ a message to a role outside launch.instances says so in its result and in the notice (44.597924ms)
|
||||
✔ a message to a running role sends no notice and its result is unchanged (55.061937ms)
|
||||
✔ a re-route at a claim, a release and claim, and a broker restart send no second notice (98.649685ms)
|
||||
✔ a run launched but not yet claimed counts as no holder (46.221566ms)
|
||||
✔ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (105.193165ms)
|
||||
✔ a business with no launch block tells nobody and says there is no launcher (52.058852ms)
|
||||
✔ the notice sender stays internal: no role is named _bus and no caller can send as it or to it (159.32635ms)
|
||||
ℹ tests 8
|
||||
ℹ suites 0
|
||||
ℹ pass 7
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 706.440806
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/launch-notice.test.mjs:112:1
|
||||
✖ a message to a role outside launch.instances says so in its result and in the notice (44.597924ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
launchable: false,
|
||||
launcher: 'chief',
|
||||
launcherRunning: false,
|
||||
role: 'coder',
|
||||
+ told: false
|
||||
- told: true
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:115: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 startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { role: 'coder', launcher: 'chief', told: false, launcherRunning: false, launchable: false },
|
||||
expected: { role: 'coder', launcher: 'chief', told: true, launcherRunning: false, launchable: false },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
✔ a message to a stopped role sends launch.by one notice, and the result says so (95.315312ms)
|
||||
✖ a message to a role outside launch.instances says so in its result and in the notice (44.84616ms)
|
||||
✔ a message to a running role sends no notice and its result is unchanged (54.139426ms)
|
||||
✔ a re-route at a claim, a release and claim, and a broker restart send no second notice (92.878684ms)
|
||||
✔ a run launched but not yet claimed counts as no holder (51.742561ms)
|
||||
✔ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (129.163094ms)
|
||||
✔ a business with no launch block tells nobody and says there is no launcher (48.860858ms)
|
||||
✔ the notice sender stays internal: no role is named _bus and no caller can send as it or to it (155.344221ms)
|
||||
ℹ tests 8
|
||||
ℹ suites 0
|
||||
ℹ pass 7
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 726.828495
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/launch-notice.test.mjs:112:1
|
||||
✖ a message to a role outside launch.instances says so in its result and in the notice (44.84616ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
+ "Message 31ee927c-9807-4770-8cef-9c0ff1924f6e from human to coder waits: coder has no running session. Launch coder within the launch block's limits, or tell human why not with message.send in_reply_to 31ee927c-9807-4770-8cef-9c0ff1924f6e."
|
||||
- "Message 31ee927c-9807-4770-8cef-9c0ff1924f6e from human to coder waits: coder has no running session and isn't in the launch block's instances, so a launch of coder is refused. Tell human why not with message.send in_reply_to 31ee927c-9807-4770-8cef-9c0ff1924f6e."
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:121: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 startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: "Message 31ee927c-9807-4770-8cef-9c0ff1924f6e from human to coder waits: coder has no running session. Launch coder within the launch block's limits, or tell human why not with message.send in_reply_to 31ee927c-9807-4770-8cef-9c0ff1924f6e.",
|
||||
expected: "Message 31ee927c-9807-4770-8cef-9c0ff1924f6e from human to coder waits: coder has no running session and isn't in the launch block's instances, so a launch of coder is refused. Tell human why not with message.send in_reply_to 31ee927c-9807-4770-8cef-9c0ff1924f6e.",
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
✖ a message to a stopped role sends launch.by one notice, and the result says so (47.611491ms)
|
||||
✖ a message to a role outside launch.instances says so in its result and in the notice (47.677677ms)
|
||||
✔ a message to a running role sends no notice and its result is unchanged (60.307952ms)
|
||||
✔ a re-route at a claim, a release and claim, and a broker restart send no second notice (101.047144ms)
|
||||
✔ a run launched but not yet claimed counts as no holder (50.008667ms)
|
||||
✖ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (45.512803ms)
|
||||
✖ a business with no launch block tells nobody and says there is no launcher (47.162127ms)
|
||||
✔ the notice sender stays internal: no role is named _bus and no caller can send as it or to it (162.926512ms)
|
||||
ℹ tests 8
|
||||
ℹ suites 0
|
||||
ℹ pass 4
|
||||
ℹ fail 4
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 619.25303
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/launch-notice.test.mjs:68:1
|
||||
✖ a message to a stopped role sends launch.by one notice, and the result says so (47.611491ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
- launchable: true,
|
||||
launcher: 'chief',
|
||||
launcherRunning: false,
|
||||
role: 'pm',
|
||||
told: true
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:71:10)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.start (node:internal/test_runner/test:1262:17)
|
||||
at startSubtestAfterBootstrap (node:internal/test_runner/harness:387:17) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { role: 'pm', launcher: 'chief', told: true, launcherRunning: false },
|
||||
expected: { role: 'pm', launcher: 'chief', told: true, launcherRunning: false, launchable: true },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at tests/launch-notice.test.mjs:112:1
|
||||
✖ a message to a role outside launch.instances says so in its result and in the notice (47.677677ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
- launchable: false,
|
||||
launcher: 'chief',
|
||||
launcherRunning: false,
|
||||
role: 'coder',
|
||||
told: true
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:115: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 startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: { role: 'coder', launcher: 'chief', told: true, launcherRunning: false },
|
||||
expected: { role: 'coder', launcher: 'chief', told: true, launcherRunning: false, launchable: false },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at tests/launch-notice.test.mjs:170:1
|
||||
✖ no notice for a message to launch.by, from it, from a tester, to the human, or in a thread to a thread instance (45.512803ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
- launchable: false,
|
||||
launcher: 'chief',
|
||||
launcherRunning: false,
|
||||
role: 'chief',
|
||||
told: false
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:173: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: { role: 'chief', launcher: 'chief', told: false, launcherRunning: false },
|
||||
expected: { role: 'chief', launcher: 'chief', told: false, launcherRunning: false, launchable: false },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
|
||||
test at tests/launch-notice.test.mjs:210:1
|
||||
✖ a business with no launch block tells nobody and says there is no launcher (47.162127ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
|
||||
+ actual - expected
|
||||
|
||||
{
|
||||
- launchable: null,
|
||||
launcher: null,
|
||||
launcherRunning: null,
|
||||
role: 'pm',
|
||||
told: false
|
||||
}
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/bus/tests/launch-notice.test.mjs:212: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: { role: 'pm', launcher: null, told: false, launcherRunning: null },
|
||||
expected: { role: 'pm', launcher: null, told: false, launcherRunning: null, launchable: null },
|
||||
operator: 'deepStrictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
✔ talk sends a REQUEST, prints and reads only the reply to it, and leaves other messages unread (134.430331ms)
|
||||
✔ talk --wait 0 only sends; no reply within --wait exits 1 and says where it will show (1065.038298ms)
|
||||
✔ a late reply the Console has listed stays unread for mosaic inbox, and the next talk skips it (2088.824571ms)
|
||||
✔ talk says when the role isn't running, whether launch.by was told, and how to start launch.by (150.583836ms)
|
||||
✖ talk to a role launch.by can't launch says it isn't in the launch block (69.077267ms)
|
||||
✔ talk to a stopped role prints the waiting line once, skips a non-reply and prints the reply (147.944243ms)
|
||||
✔ talk, stop and launches off/on refuse inside an agent run; bad arguments are usage errors (46.772223ms)
|
||||
✔ launches off and on go to the broker and change the business's launch state (61.126923ms)
|
||||
✔ launches list reads sessions.json and marks a stale entry; stop reports it and refuses a non-runner (54.432292ms)
|
||||
ℹ tests 9
|
||||
ℹ suites 0
|
||||
ℹ pass 8
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 3971.031662
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/verbs.test.mjs:123:1
|
||||
✖ talk to a role launch.by can't launch says it isn't in the launch block (69.077267ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
+ "qa isn't running, pm has been told\n" +
|
||||
+ "pm isn't running either. systemctl --user restart mosaic-bus@demo starts it if the unit runs with --pm (scripts/bus-service.sh status demo shows pm: on). The restart stops running sessions.\n"
|
||||
- "qa isn't running and isn't in the launch block, so pm can't launch it\n"
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/cli/tests/verbs.test.mjs:131:10)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: "qa isn't running, pm has been told\npm isn't running either. systemctl --user restart mosaic-bus@demo starts it if the unit runs with --pm (scripts/bus-service.sh status demo shows pm: on). The restart stops running sessions.\n",
|
||||
expected: "qa isn't running and isn't in the launch block, so pm can't launch it\n",
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
✔ talk sends a REQUEST, prints and reads only the reply to it, and leaves other messages unread (155.982818ms)
|
||||
✔ talk --wait 0 only sends; no reply within --wait exits 1 and says where it will show (1070.311838ms)
|
||||
✔ a late reply the Console has listed stays unread for mosaic inbox, and the next talk skips it (2085.148237ms)
|
||||
✔ talk says when the role isn't running, whether launch.by was told, and how to start launch.by (149.032318ms)
|
||||
✖ talk to a role launch.by can't launch says it isn't in the launch block (49.457759ms)
|
||||
✔ talk to a stopped role prints the waiting line once, skips a non-reply and prints the reply (119.826122ms)
|
||||
✔ talk, stop and launches off/on refuse inside an agent run; bad arguments are usage errors (44.336406ms)
|
||||
✔ launches off and on go to the broker and change the business's launch state (52.2718ms)
|
||||
✔ launches list reads sessions.json and marks a stale entry; stop reports it and refuses a non-runner (42.018997ms)
|
||||
ℹ tests 9
|
||||
ℹ suites 0
|
||||
ℹ pass 8
|
||||
ℹ fail 1
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 3860.180816
|
||||
|
||||
✖ failing tests:
|
||||
|
||||
test at tests/verbs.test.mjs:123:1
|
||||
✖ talk to a role launch.by can't launch says it isn't in the launch block (49.457759ms)
|
||||
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
|
||||
+ actual - expected
|
||||
|
||||
+ "qa isn't running and isn't in the launch block, so pm can't launch it\n" +
|
||||
+ "pm isn't running either. systemctl --user restart mosaic-bus@demo starts it if the unit runs with --pm (scripts/bus-service.sh status demo shows pm: on). The restart stops running sessions.\n"
|
||||
- "qa isn't running and isn't in the launch block, so pm can't launch it\n"
|
||||
|
||||
at TestContext.<anonymous> (file:///home/jwoltje/dewey-scratch/r152/wt/packages/cli/tests/verbs.test.mjs:131:10)
|
||||
at async Test.run (node:internal/test_runner/test:1409:7)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7) {
|
||||
generatedMessage: true,
|
||||
code: 'ERR_ASSERTION',
|
||||
actual: "qa isn't running and isn't in the launch block, so pm can't launch it\npm isn't running either. systemctl --user restart mosaic-bus@demo starts it if the unit runs with --pm (scripts/bus-service.sh status demo shows pm: on). The restart stops running sessions.\n",
|
||||
expected: "qa isn't running and isn't in the launch block, so pm can't launch it\n",
|
||||
operator: 'strictEqual',
|
||||
diff: 'simple'
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
a2ae323bc4af65057ca1c31a452b66d31f5118662df5a4a9a7e11d3cb40ad92d ./BUILD.md
|
||||
c29edd841268744dd5974a0f0387da31fcdbaaff385d36c0efdb6ed2f7016299 ./base.txt
|
||||
eedf45be9c46473f841d3e97230ecc58fb8e79bf55aaf960904335cc36d3785c ./build.patch
|
||||
c333f4beffec1d901ca23200365698e42003c8256a609ad662429d15e63747c1 ./candidate-manifest.sha256
|
||||
d83ffb27ea9d4f661b96f14fc281493b2711fd8d806542de6823d7f31b3a6f2b ./gate-run.log
|
||||
6bfbc2a1bdbcb3ab9b4d2e76be3109f9423cfb391f24678411c4c17f4d14bf69 ./gate.sh
|
||||
c6a31883abfab2a83e2a6a620e495e4c58d305d8830142b57d7a9535a7397e0a ./gate/pkg-bus.log
|
||||
3dc8ed7c2b6ee8116ff609df7b71cf8bb64434f57d3bb9d49f313e0412be4c2b ./gate/pkg-business.log
|
||||
29d1ab6978fb4571dfa9e9ae052008018448e145d6e498e6c030f2d7845c6748 ./gate/pkg-cli.log
|
||||
52e2b5283595c819dacdd38fd007efad4adc8b44d0131fbec575fae6011055df ./gate/pkg-webui.log
|
||||
f91fc95a173339137f981e24fbf630acfde957e32c3cd71e28304532083c6a77 ./gate/test-auth.log
|
||||
e1206366f07f3d9029530dcdcb55c0282d3f052adc60fc7fd51642d5d4ec3600 ./gate/test-conductor.log
|
||||
52d211444489ea729dafc3c9745d4474d9dfd50f41055cbad792424197f04073 ./gate/test-config.log
|
||||
87d2e24ce0be7586e31ea1f2c9ce5618b3127515b3c3cd3893f2a0ed899d5822 ./gate/test-discord.log
|
||||
20d1d704f3665cd133d9b3ada0ce52fd993d7fbb055e906d228625741317d6f6 ./gate/test-extension-package.log
|
||||
83dfaa21c4e4ad941088efab3f69e87ebd2f6bd3cc72ede938e21dc06da8a34f ./gate/test-foundation.log
|
||||
8e2254aa3e1bb9b205ab72c68273d447c0328c9f156ccba2a46f3a0476468b58 ./gate/test-land-work.log
|
||||
53294c75cc3fc291f14899143c1b6af2d2c6cf360d78199edbf4056d0d2547dc ./gate/test-queue.log
|
||||
fa832794ee35025fb4559d58d01a270f6bff2eb65e863e9075b797f47fa68545 ./gate/test-release.log
|
||||
ccea37f4ffde1f160dcd1a1864988083a645d974e892065c956b338d0f8c853a ./gate/test-task.log
|
||||
42d9699988f1eb1cdfeb9366bba42dcaf0e5a29c3b208e712d698f6ebf1f8322 ./mutants-run.log
|
||||
2865433053ff4e3a8507899679b87911765959c2a3ba8a4b7e79dd1083721068 ./mutants.py
|
||||
346113382cdd2a8346dae10ebe22cd71e9aeebb2e2a562deb4d32aca684152c6 ./mutants/B1-always-launchable.log
|
||||
a9c4ec9f5bd609b372cb83022a02970ada2a8b17e86b1436ae2227fca38e4b9a ./mutants/B2-no-block-false.log
|
||||
b3c3f8778118cb438b945aa30e276010849f09ea0153984585767c1dbe0d96a8 ./mutants/B3-launcher-launchable.log
|
||||
9c72fa780fdf27c81b255af08382f0e6dfa4f3b3b6b4015583d794cb5ae63038 ./mutants/B4-not-told-unlaunchable.log
|
||||
e34495d47410fd06a28a723e167dcc29c3faaff6886448e3260eb9aeea261922 ./mutants/B5-launch-text-always.log
|
||||
573744115b43f9839fa182dfd606738cac478b011cb1f1d86848e07e014bedc4 ./mutants/B6-field-dropped.log
|
||||
bb37d81f0a08cb3cbed9dec3d32e893e6c9eb9c13a018e07670f59df45b5d40e ./mutants/C1-no-launch-block-line.log
|
||||
b4b7b564090b01c997701d37adc74ecc7fd218a9f793b35d603bf19dce2fdd3d ./mutants/C2-restart-after-line.log
|
||||
82eb9bdbb6c8198ec3c5a9872d47b30f6b28ce51dbf84628ca62d77b215a245c ./repro.sh
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Row 152: apply build.patch to a detached worktree at base.txt and check the candidate manifest.
|
||||
# Usage: repro.sh <canonical checkout> <new worktree path>
|
||||
set -euo pipefail
|
||||
HERE=$(cd "$(dirname "$0")" && pwd)
|
||||
REPO=$1 WT=$2
|
||||
git -C "$REPO" worktree add -q --detach "$WT" "$(cat "$HERE/base.txt")"
|
||||
git -C "$WT" apply "$HERE/build.patch"
|
||||
(cd "$WT" && sha256sum -c --quiet "$HERE/candidate-manifest.sha256") && echo DIGESTS_OK
|
||||
Reference in new issue
Block a user