rocko: row 77 (#1571) packet, round 2; BUILD-LOG and SESSIONS appends

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-12 15:04:42 -05:00
co-authored by Claude Opus 5.5
parent 3268d5034d
commit bb909a6bf2
48 changed files with 2830 additions and 0 deletions
+6
View File
@@ -4418,3 +4418,9 @@ After (6c42344d): Darkwing's round 1, 12 files +519 -12. `packages/tasks/fields.
Before (9438880e): a message Jason sent from the Console got a Sent receipt and nothing else; the reply reached him only through `mosaic talk`, and the broker had no read that returned replies without consuming them.
After (c9a5650e): Dewey's round 2, 13 files +455 -30, a rebase on 1e5f5958 after row 61 with round 1's two follow-ups folded in (the cli README's talk entry, a rewrapped `bus.mjs` comment). The broker gains a `replies` read verb for human and reader sessions: `{id}` returns that business's messages whose `in_reply_to` is the id, oldest first, at most 50, writes no `deliveries` row, and refuses `message-not-found` for an unknown id. The Console serves it through `BUS_VERBS` with an id check and the Sent receipt shows the replies; the cli's talk timeout message now says the reply may still come. Approved by Darkwing (27783 round 1, 27821 round 2) on manifest 3ce7527f, no drift. Sage's gate on 9438880e plus the patch, 19:25:18Z to 19:30:39Z: tasks 74, webui 84, bus 102, cli 115, control-board 124, the nine `scripts/test-*.sh` 0 failed (test-task 98). `queue review verify-commit 81 c9a5650e` matched 13 paths. Row 81 done at rev 704 (5849de76), pushed, #1575 closed with comment 27825. The broker verb is live at the next bus restart, which ends the PM session (Mos's pm.conf drop-in relaunches it); the view at the next Console restart, bus first so the view doesn't get unknown-verb. Mos had the decision-109 before-notice; the Console still runs MainPID 2089167 from 19:05:38Z, /healthz 200.
### 2026-10-12 — Rocko, row 77 (#1571) candidate, round 2: the bus-on-copy refusal, row 61's paths, read-only directories
Before: round 1 (candidate 4927de66) got changes from Darkwing (27801) and Filbert (27818). A Console on a copy would fail every bus call with `human-required`, because the bus accepts a human proof only from its own `human-cli.mjs` and the bus runs from the checkout. The copy left out row 61's `packages/tasks/src` and `fields.json`, so serve from a copy failed at load, and with `src` alone `/api/task-fields` answered 503. Copy directories stayed writable, so `sed -i` could replace a 0444 file. Filbert left three mutants alive.
After (candidate, uncommitted, base 04db738a, packet `agents/rocko/work/queue-77/r2/`, candidate manifest sha256 045f0ac8): `install --copy ID` refuses unless every `ExecStart` path of the bus unit (`mosaic-bus@ID` with `--business`, else every loaded `mosaic-bus@` unit), read from `systemctl --user show` so drop-ins count, lies inside that copy. It also refuses when the unit isn't loaded, none is loaded, `ExecStart` has no path, or systemctl fails. `COPY_PATHS` gains `packages/tasks/src` and `packages/tasks/fields.json`, and the serve test GETs `/api/task-fields` from the copy and expects 200. Every copy directory is 0555, and the temp trap runs `chmod -R u+w` before `rm -rf`. TOOLS.md and the README give the removal command, the rollback floor (ids at or after row 77's landing; Filbert N2, docs only), the unpinned queue view (N3), and that the update step can't be used until a later row puts the bus on the copy. Filbert's three survivors are killed by a `.refactor` refusal, the directory-mode check, and the README in the copy. The pinned-copy fixture repository sets `gc.auto 0`: a detached gc was deleting loose objects while the cleanup chmod walked them. Mutants 34/34 killed. Byte check: 8 of 8 renders the same. Gate at 04db738a: the nine `scripts/test-*.sh` 0 failed (test-task 98); webui 98/1 with a `bus.test.mjs` humanCall timeout at load 27 (the file and `bus.mjs` aren't in this diff), rerun 99/0, and `bus.test.mjs` alone 5/5. Moves: in-progress rev 745, in-review round 2 rev 746, request rocko-77-review-2 failed rev 747 (no credential; Sage sends as jarvis). The live unit and the live bus are untouched.
+226
View File
@@ -0,0 +1,226 @@
# Row 77 (P19 #225): the Console runs a pinned copy, candidate packet, round 2
Author: Rocko. Reviewers: Darkwing (comment 27801) and Filbert (comment
27818), both "changes" on round 1 candidate `4927de66`. Gate: Sage.
Base: `04db738a` (`base.txt`), current `refactor`, which includes row 61
(`6c42344d`) and row 81 (`c9a5650e`). Row 81 touched
`packages/webui/README.md`; the round 2 change applied to it cleanly with
a 3-way apply. At freeze `refactor` is at `a3f6e9e6`: no commit after
the base touches this row's paths, `packages/tasks` or `packages/bus`,
and `build.patch` passes `git apply --check` on the checkout. The packet
is uncommitted. I made no commits, pushes or
Gitea calls, read no token, and started, stopped or installed no unit.
Tests use `--dir`, a stand-in `systemctl` and fixture copies only.
The round 1 packet is unchanged one level up (`../`). This directory
holds round 2 only; `build.patch` is the whole candidate against the base,
not a delta on round 1.
## Files (`files.txt`, `candidate-manifest.sha256`)
Round 1's eight files, with these round 2 changes:
| File | Round 2 change |
|---|---|
| `scripts/webui-service.sh` | `bus_on_copy`, called by `install`; `packages/tasks/src` and `packages/tasks/fields.json` in `COPY_PATHS`; directories read-only; the temp trap restores write before removing |
| `packages/webui/tests/service.test.mjs` | the stand-in answers the bus `list-units` and `show` calls; the bus-on-copy test |
| `packages/webui/tests/pinned-copy.test.mjs` | directory modes, `sed -i` and a new file refused, the rename-race cleanup test, `GET /api/task-fields` from the copy, a `.refactor` refusal, the README in the copy, `gc.auto 0` in the fixture repository |
| `docs/TOOLS.md`, `packages/webui/README.md` | the bus wording, the install refusal, read-only directories and removal, the rollback floor, the unpinned queue view, the update step not yet usable |
| `agents/rocko/work/queue-77/r2/mutants.py` | 34 mutants (round 1's 18 plus 16) |
| `agents/rocko/work/queue-77/byte-check.sh` | unchanged from round 1 |
Round 1's `agents/rocko/work/queue-77/mutants.py` is superseded by
`r2/mutants.py` and isn't in this candidate.
## Findings
### Darkwing F1, Filbert F1: a Console on a copy fails every human proof
The bus accepts a human proof only when `argv[1]` is its own
`human-cli.mjs` (`human.mjs:70`, `runtime.mjs:68`). A Console on a copy
spawns the copy's `human-cli.mjs`, so with the bus on the checkout every
bus call fails `human-required`.
Fix: `install --copy ID` refuses unless the bus unit runs from the same
copy (`bus_on_copy`, Sage approved the design). It reads the effective
`ExecStart` with `systemctl --user show UNIT -p LoadState -p ExecStart`,
because the live bus has a `pm.conf` drop-in and the unit file alone
isn't the effective value.
- With `--business ID` the unit is `[email protected]`. Without it,
every loaded `mosaic-bus@*.service` from `list-units --all` is checked.
- Every `path=` in `ExecStart` must lie under `<copy>/`. A path that only
shares the copy's prefix (`<copy>x/...`) refuses.
- It refuses when the unit isn't loaded (`not-found`), when no bus unit
is loaded, when `ExecStart` has no path, and when `list-units` or `show`
fails. Each refusal is one line and changes nothing.
- The check runs after `render` and before the running-state read, so
nothing is written on a refusal.
The bus runs from the checkout today, and `copy` doesn't include
`scripts/mosaic` (the bus entry point). So `install --copy` refuses on
the live system until a later row puts the bus on the copy. TOOLS.md and
the README say the update step can't be used yet and why. I didn't add
the bus paths to the copy: moving the bus is the later row (Sage: "Don't
move the bus yourself"), and row 85 (#1579, one-copy stack) is that
row.
TOOLS.md's "the bus child come from the copy" now says the bus child is
the human transport and that the bus checks its path.
Tests (`service.test.mjs`, "install refuses unless the bus unit runs from
the same copy"):
- refused: the bus on the checkout, with and without `--business`; the
prefix-only path; two units, one off the copy; `not-found`; no units
loaded; no `ExecStart` path; `list-units` failing; `show` failing
- accepted: the bus on the same copy, with and without `--business`
The exact-calls assertion in the existing install test now lists the bus
calls too.
### Darkwing F2, Filbert F2: row 61's task field table
`reads.mjs` imports `packages/tasks/src/fields.mjs`, which reads
`packages/tasks/fields.json` at request time. Both are in `COPY_PATHS`.
The comment says why and says the test serves from a copy: a missing
import fails it at load, and a missing file read at request time
(`fields.json`, `RELEASE`, `roles/`) fails the route that reads it, which
the test also GETs (Filbert's wording point).
The serve test GETs `/api/task-fields` from the copy and expects 200 with
a body equal to `packages/tasks/fields.json`. Without that GET, the
"copy misses fields table" mutant survived; with it, it dies.
### Darkwing 3, Filbert N1: read-only directories
`copy` now makes every directory 0555 (the top one included) as well as
every file `a-w`, so a writer that replaces by rename (`sed -i`, git,
editors) fails too. Because a read-only temp directory can't be removed,
the trap runs `chmod -R u+w` before `rm -rf`. TOOLS.md and the README give
the removal command: `chmod -R u+w DIR && rm -rf DIR`.
Tests (`pinned-copy.test.mjs`): every directory is 0555; `sed -i` on a
copied file fails and leaves it unchanged; writing a new file throws
`EACCES`. A new test makes `mv` lose the rename race (a stand-in `mv` that
creates the target and fails): `copy` reports `exists:`, and the copies
directory holds only that one entry, so no read-only temp directory
is left behind.
### Filbert N2: rollback floor (docs)
A copy from before row 77 holds a `cli.mjs` that refuses `--checkout`
("unknown option"), so a unit pointing at it exits 2 at start. I took the
docs-only option Filbert offered: TOOLS.md and the README say rollback
reaches only ids at or after row 77's landing. I didn't add a refusal to
`install`: a grep of the copy's `cli.mjs` would be a second source of
truth for the flag set. Before the next row lands, the update step can't
be used anyway (F1).
### Filbert N3: the queue view isn't pinned (docs)
By design (the brief), the queue read runs from the checkout. The README's
update-step paragraph and TOOLS.md say so: a landing on the queue read
shows at once.
### Filbert's three surviving mutants
| Survivor | Now |
|---|---|
| the commit's leading-character check deleted | killed: `.refactor` refusal case, expects exit 1 and "commit must be a commit id or branch name: .refactor" (mutant "commit may start with a dot") |
| `chmod 0755 "$COPY_TMP"` deleted, top directory 0700 | that line is gone; the directory-mode check covers the top directory (mutants "copy dirs stay writable", "copy subdirs stay writable") |
| `packages/webui/README.md` dropped from `COPY_PATHS` | killed: the copy test checks the README exists and is read-only (mutant "copy misses README") |
## Test flakes seen while building, and one fix
- Round 2's first full run after the mutants had one failure whose name I
didn't capture. To find it I ran the suite five more times with TAP
output. That turned up three failures:
- `bus-browser.test.mjs` "S5 pages in a browser": a 27 s condition
timeout.
- `bus.test.mjs` "humanCall kills a transport that runs past its
timeout": the pid file was missing.
Both are timing failures in files this row doesn't change, seen under a
load average of 20-30.
- The third was this row's own: the cleanup of the new pinned-copy
`tmp` helper (`chmod -R u+w`) failed with ENOENT under the fixture
repository's `.git/objects`. The fixture commits thousands of loose
objects, which starts a detached `git gc --auto`, and gc deletes
objects while chmod walks. I set `gc.auto 0` in the fixture
repository rather than making the cleanup ignore errors.
After that, six consecutive full runs at the earlier base `08941d8b`
were 97 pass, 0 fail (row 81 adds two tests at `04db738a`).
## Mutants (`mutants.py`, `out/mutants.txt`)
`python3 mutants.py <tree>` applies each mutant alone to the candidate
tree and runs `service.test.mjs` and `pinned-copy.test.mjs`. 34 mutants,
all killed. The 16 new ones:
- install skips the bus check
- bus path prefix only
- `not-found` accepted
- `show` failure ignored
- `list-units` failure ignored
- no loaded bus accepted
- no `ExecStart` path accepted
- only the first bus unit checked
- `--business` ignored for the bus
- copy misses tasks src
- copy misses the fields table
- copy misses README
- commit may start with a dot
- copy dirs stay writable, copy subdirs stay writable (`-maxdepth 0`), and
the trap leaves a read-only temp directory
The run in `out/mutants.txt` is on the candidate at `04db738a`.
## Byte check (`out/byte-check.txt`, `../byte-check.sh`)
Round 1's script, base `04db738a` against the candidate: `render`
without `--copy` gives the same unit and exit code for all 8 flag sets,
and the template body is unchanged.
## Gate (`out/gate/`, `out/gate.sh`, `out/after-gate.sh`)
Sequential, in the scratch worktree at `04db738a` with the candidate and
`node_modules` linked, full output kept per suite, load average 17-27:
| Suite | Result |
|---|---|
| webui node (`packages/webui/tests/*.test.mjs`) | 98 pass, 1 fail (below); rerun 99 pass, 0 fail |
| test-auth | 15 passed, 0 failed |
| test-conductor | 17 passed, 0 failed |
| test-config | 24 passed, 0 failed |
| test-discord | 66 passed, 0 failed |
| test-extension-package | 18 passed, 0 failed |
| test-foundation | 44 passed, 0 failed |
| test-queue | 27 passed, 0 failed (the canonical-root checks skip in a worktree, as always) |
| test-release | 14 passed, 0 failed |
| test-task | 98 passed, 0 failed |
The gate's one webui failure: `bus.test.mjs` "humanCall speaks the human
transport protocol without blocking the server" got `outcome-unknown`
where it expects `invalid-response`. That call has a 1500 ms timeout
around spawning a node child, and the load average was 27. Neither
`bus.test.mjs` nor `packages/webui/src/bus.mjs` is in this row's diff.
After the gate, `out/after-gate.sh` ran the whole webui suite again (99
pass, 0 fail) and `bus.test.mjs` alone five times (all pass). The only
failure marker in `out/gate/` is that one, in `node-webui.txt`.
`rocko-r77_default` was removed after the Docker suites.
The TOOLS.md update-step paragraph was reflowed during the gate
(whitespace only, prose); no suite reads `docs/TOOLS.md`. The mutants and
the rerun ran after the reflow.
## For the reviewers
- The live unit and the live bus are untouched. The live Console can't
take this change through `install --copy` until a later row moves the
bus; until then it stays on its current unit.
- The design decision with the most weight: an install refusal rather
than a Console that spawns the checkout's `human-cli.mjs`. The latter
would keep proofs working but put an unpinned file in the pinned
Console's trust path.
+1
View File
@@ -0,0 +1 @@
04db738a351e25f6ae92e3c679cffa57887f9368
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,10 @@
28c4708c062b752832576eb42aa1f1c9cede16f940d6d8929a4f47957c2f2b4d agents/rocko/work/queue-77/byte-check.sh
85f722a82873b52d2c02f8573eb9c63b025514f239551bff214e44b8303b00c0 agents/rocko/work/queue-77/r2/mutants.py
683aa2c5ee05404c08c35f13113c80a8029fe7881bab8dd8083ba3c87c261815 docs/TOOLS.md
063e1d6c492f32d80d71e669f537622d2e920d7dbfb37f3cfaafeb59d753ea0c packages/webui/README.md
fdd202e6faa08f3b6e1784b805c6e4db5464126b8d7ed54f471cc38a524597e6 packages/webui/src/cli.mjs
b41a2670df325112efe9292667131edee2b6ac307e3bfc9e5b03d531171ea06d packages/webui/src/reads.mjs
7a449ef91310ab6b0185ab97f1720e0790adbd9a8d1d83c3c716e36da976acb5 packages/webui/systemd/mosaic-webui.service.in
9f336ae0e51814bc19fcd5a039ca95dc92912663c6a46eaf63e1933d6c84e863 packages/webui/tests/pinned-copy.test.mjs
3fd286a744e7e4827b2f15da9bcae1484228ba077c4823ac84bfad9026e42470 packages/webui/tests/service.test.mjs
03350df28932e61c16a3ba87db4ccd2d3cff8e74a88fb08f5828a462639aa185 scripts/webui-service.sh
+10
View File
@@ -0,0 +1,10 @@
agents/rocko/work/queue-77/byte-check.sh
agents/rocko/work/queue-77/r2/mutants.py
docs/TOOLS.md
packages/webui/README.md
packages/webui/src/cli.mjs
packages/webui/src/reads.mjs
packages/webui/systemd/mosaic-webui.service.in
packages/webui/tests/pinned-copy.test.mjs
packages/webui/tests/service.test.mjs
scripts/webui-service.sh
+53
View File
@@ -0,0 +1,53 @@
# Row 77 mutants (rounds 1 and 2): each edit applied alone to <tree>, the service and pinned-copy
# tests run, the file restored. Usage: python3 mutants.py <tree>
import subprocess, shutil, sys
W=sys.argv[1] # the tree with the candidate applied
S='scripts/webui-service.sh'
M=[
('failed counts as running', S, '&& $3 != "failed" {', '{'),
('reloading not running', S, '$3 != "failed" {', '$3 != "failed" && $3 != "reloading" {'),
('list-units failure ignored', S, '2>/dev/null)" || die "refusing: systemctl --user list-units', '2>/dev/null)" || true; : "refusing: systemctl --user list-units'),
('install skips state read', S, ' state="$(running)" || exit 1\n [ -z "$state" ] || die "refusing: $UNIT_NAME is running', ' state=""\n [ -z "$state" ] || die "refusing: $UNIT_NAME is running'),
('uninstall skips state read with --no-reload', S, '[ -z "$state" ] || die "refusing: $UNIT_NAME is still running', '[ -z "$state" ] || [ "$RELOAD" = 0 ] || die "refusing: $UNIT_NAME is still running'),
('uid header case-sensitive', S, '"${AUTH_HEADER,,}" = x-authentik-uid', '"$AUTH_HEADER" = X-authentik-uid'),
('uid allows upper hex', S, '^[0-9a-f]{64}$ ]]; then', '^[0-9a-fA-F]{64}$ ]]; then'),
('allowed user may start with -', S, 'case "$ALLOW_USER" in [A-Za-z0-9]*) ;;', 'case "$ALLOW_USER" in *) ;;'),
('no --checkout in unit', S, 'flags="--checkout $REPO $flags"', 'flags="$flags"'),
('canonical always passes', S, '[ -d "$REPO/.git" ] || [ "$ALLOW_WORKTREE" = 1 ] ||', 'true ||'),
('install without --copy', S, '[ -n "$COPY_ID" ] || die "install needs --copy ID', 'true || die "install needs --copy ID'),
('missing copy accepted', S, '[ -f "$COPIES/$COPY_ID/packages/webui/src/cli.mjs" ] ||', 'true ||'),
('status drift wrong', S, 'if [ "$head" = "$copy" ]; then', 'if true; then'),
('copy misses seat', S, ' packages/seat/src\n', ''),
('copy misses README', S, ' packages/webui/README.md\n', ''),
('commit may start with a dot', S, 'case "$commit" in [A-Za-z0-9]*) ;;', 'case "$commit" in [.A-Za-z0-9]*) ;;'),
('copy misses tasks src', S, ' packages/tasks/src\n', ''),
('copy misses fields table', S, ' packages/tasks/fields.json\n', ''),
('copy stays writable', S, '-type f -exec chmod a-w', '-type f -exec true'),
('copy dirs stay writable', S, '-type d -exec chmod 0555', '-type d -exec true'),
('copy subdirs stay writable', S, '-type d -exec chmod 0555 {} +', '-maxdepth 0 -type d -exec chmod 0555 {} +'),
('trap leaves read-only temp', S, "trap 'chmod -R u+w \"$COPY_TMP\" 2>/dev/null; rm -rf", "trap 'rm -rf"),
('copy off-branch accepted', S, 'merge-base --is-ancestor "$id" refs/heads/refactor ||', 'true ||'),
('queue reads root', 'packages/webui/src/reads.mjs', 'root: queueRoot', 'root'),
('--checkout relative ok', 'packages/webui/src/cli.mjs', 'isAbsolute(', '!!('),
('install skips bus check', S, ' unit="$(render)" || exit 1\n bus_on_copy', ' unit="$(render)" || exit 1\n : bus_on_copy'),
('bus path prefix only', S, 'in "$copy"/*) ;;', 'in "$copy"*) ;;'),
('bus not-found accepted', S, '[ "$load" = loaded ] ||', 'true ||'),
('bus show failure ignored', S, '-p LoadState -p ExecStart 2>/dev/null)" || die', '-p LoadState -p ExecStart 2>/dev/null)" || true; : die'),
('bus list failure ignored', S, "'mosaic-bus@*.service' 2>/dev/null)\" || die", "'mosaic-bus@*.service' 2>/dev/null)\" || true; : die"),
('no loaded bus accepted', S, '[ -n "$units" ] || die', 'true || die'),
('no ExecStart path accepted', S, '[ -n "$paths" ] || die', 'true || die'),
('only first bus unit checked', S, ' for unit in $units; do', ' for unit in ${units%%[[:space:]]*}; do'),
('--business ignored for bus', S, ' if [ -n "$BUSINESS" ]; then\n units=', ' if false; then\n units='),
]
res=[]
for name,f,a,b in M:
p=f'{W}/{f}'; s=open(p).read()
if s.count(a)<1: res.append(f'NOMATCH {name}'); continue
shutil.copy(p,p+'.bak'); open(p,'w').write(s.replace(a,b))
try:
r=subprocess.run(['node','--test','tests/service.test.mjs','tests/pinned-copy.test.mjs'],cwd=f'{W}/packages/webui',capture_output=True,text=True,timeout=300)
fails=[l for l in r.stdout.splitlines() if l.startswith('✖') and 'failing tests' not in l]
res.append(f"{'KILLED' if r.returncode else 'SURVIVED'} {name}: {len(set(fails))} failing")
finally:
shutil.move(p+'.bak',p)
print('\n'.join(res))
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
# Row 77 round 2, after the gate: the webui suite again, bus.test.mjs alone
# five times (the gate's one failure), the mutants on the rebased candidate,
# and the byte check against the base. Sequential, output kept.
W=/mnt/storage/scratch/rocko-r77
O=/mnt/storage/scratch/rocko-r77-r2/gate
P=/mnt/storage/scratch/rocko-r77-r2/pkt
cd "$W" || exit 1
node --test 'packages/webui/tests/*.test.mjs' > "$O/node-webui-rerun.txt" 2>&1; echo "node-webui rerun exit $?" | tee -a "$O/after.txt"
grep -E '^ℹ (pass|fail)' "$O/node-webui-rerun.txt" | tee -a "$O/after.txt"
for i in 1 2 3 4 5; do
node --test packages/webui/tests/bus.test.mjs > "$O/bus-test-$i.txt" 2>&1; echo "bus.test.mjs run $i exit $?" | tee -a "$O/after.txt"
done
uptime | tee -a "$O/after.txt"
python3 "$P/mutants.py" "$W" > "$P/mutants.txt" 2>&1; echo "mutants: $(grep -c '^KILLED' "$P/mutants.txt") killed, $(grep -c '^SURVIVED' "$P/mutants.txt") survived" | tee -a "$O/after.txt"
bash /mnt/storage/src/mosaic-stack/agents/rocko/work/queue-77/byte-check.sh "$W" "$(cat "$P/base.txt")" "$P/byte-check" > "$P/byte-check.txt" 2>&1; echo "byte-check exit $?" | tee -a "$O/after.txt"
@@ -0,0 +1,10 @@
template body: same
1 exit 0/0 same: render
2 exit 0/0 same: render --port 7444
3 exit 0/0 same: render --business mosaic --board http://127.0.0.1:7331
4 exit 0/0 same: render --public-host console.example.com --auth-header X-authentik-uid --allow-user 6f1c0e2a9b8d7c4e5f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e
5 exit 0/0 same: render --public-host console.example.com --auth-header X-authentik-uid --allow-user 6f1c0e2a9b8d7c4e5f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e --send
6 exit 0/0 same: render --public-host console.example.com --auth-header X-authentik-username --allow-user jason
7 exit 1/1 same: render --port 0
8 exit 0/0 same: render --business a.b
8 of 8 same
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7444
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --business mosaic --board http://127.0.0.1:7331
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --public-host console.example.com --auth-header X-authentik-uid --allow-user 6f1c0e2a9b8d7c4e5f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --public-host console.example.com --auth-header X-authentik-uid --allow-user 6f1c0e2a9b8d7c4e5f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e --send
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --public-host console.example.com --auth-header X-authentik-username --allow-user jason
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1 @@
webui-service: port must be 1..65535: 0
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --business a.b
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7444
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --business mosaic --board http://127.0.0.1:7331
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --public-host console.example.com --auth-header X-authentik-uid --allow-user 6f1c0e2a9b8d7c4e5f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --public-host console.example.com --auth-header X-authentik-uid --allow-user 6f1c0e2a9b8d7c4e5f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e --send
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --public-host console.example.com --auth-header X-authentik-username --allow-user jason
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
@@ -0,0 +1 @@
webui-service: port must be 1..65535: 0
@@ -0,0 +1,20 @@
[Unit]
Description=Mosaic Console
Documentation=file:///mnt/storage/scratch/rocko-r77/packages/webui/README.md
StartLimitIntervalSec=600
StartLimitBurst=5
[Service]
Type=simple
WorkingDirectory=/mnt/storage/scratch/rocko-r77
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/bin/node /mnt/storage/scratch/rocko-r77/packages/webui/src/cli.mjs serve --port 7332 --business a.b
Restart=on-failure
RestartSec=15
RestartPreventExitStatus=2
KillSignal=SIGTERM
TimeoutStopSec=30
NoNewPrivileges=yes
[Install]
WantedBy=default.target
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# Row 77 gate: webui node suite, then every scripts/test-*.sh, sequentially, full output kept.
W=/mnt/storage/scratch/rocko-r77
O=/mnt/storage/scratch/rocko-r77-r2/gate
mkdir -p "$O"
cd "$W" || exit 1
node --test 'packages/webui/tests/*.test.mjs' > "$O/node-webui.txt" 2>&1; echo "node-webui exit $?" | tee -a "$O/summary.txt"
grep -E '^ℹ (pass|fail)' "$O/node-webui.txt" | tee -a "$O/summary.txt"
for s in scripts/test-*.sh; do
n=$(basename "$s" .sh)
bash "$s" > "$O/$n.txt" 2>&1; echo "$n exit $?" | tee -a "$O/summary.txt"
tail -3 "$O/$n.txt" | sed "s/^/ $n: /" | tee -a "$O/summary.txt"
done
grep -l -E '✖|^not ok' "$O"/*.txt | sed 's/^/failure markers in: /' | tee -a "$O/summary.txt"
@@ -0,0 +1,11 @@
node-webui rerun exit 0
ℹ pass 99
ℹ fail 0
bus.test.mjs run 1 exit 0
bus.test.mjs run 2 exit 0
bus.test.mjs run 3 exit 0
bus.test.mjs run 4 exit 0
bus.test.mjs run 5 exit 0
14:52:03 up 36 days, 16:26, 6 users, load average: 17.19, 15.86, 17.62
mutants: 34 killed, 0 survived
byte-check exit 0
@@ -0,0 +1,18 @@
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (161.249345ms)
✔ decisions route serves the roles and recent lists from the reader view (53.662611ms)
✔ credentials route serves the broker credential status from the reader view (18.226566ms)
✔ replies route serves the replies to one message from the reader view (42.604654ms)
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (72.24404ms)
✔ bus refusals map to statuses and never carry a path or a stack (30.764775ms)
✔ humanCall speaks the human transport protocol without blocking the server (1764.61973ms)
✔ busReader takes --business, else the live bus host, else refuses (258.396508ms)
✔ humanCall kills a transport that runs past its timeout (530.540486ms)
✔ serve refuses a --business value that is not a business id (391.31184ms)
ℹ tests 10
ℹ suites 0
ℹ pass 10
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 3590.111513
@@ -0,0 +1,18 @@
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (94.426818ms)
✔ decisions route serves the roles and recent lists from the reader view (49.074979ms)
✔ credentials route serves the broker credential status from the reader view (12.568848ms)
✔ replies route serves the replies to one message from the reader view (37.691656ms)
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (65.872606ms)
✔ bus refusals map to statuses and never carry a path or a stack (30.962879ms)
✔ humanCall speaks the human transport protocol without blocking the server (1762.475645ms)
✔ busReader takes --business, else the live bus host, else refuses (317.111924ms)
✔ humanCall kills a transport that runs past its timeout (529.670013ms)
✔ serve refuses a --business value that is not a business id (301.086504ms)
ℹ tests 10
ℹ suites 0
ℹ pass 10
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 3383.957406
@@ -0,0 +1,18 @@
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (86.799967ms)
✔ decisions route serves the roles and recent lists from the reader view (34.778475ms)
✔ credentials route serves the broker credential status from the reader view (10.3248ms)
✔ replies route serves the replies to one message from the reader view (38.894225ms)
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (78.307086ms)
✔ bus refusals map to statuses and never carry a path or a stack (51.771651ms)
✔ humanCall speaks the human transport protocol without blocking the server (1774.138607ms)
✔ busReader takes --business, else the live bus host, else refuses (263.177027ms)
✔ humanCall kills a transport that runs past its timeout (559.303281ms)
✔ serve refuses a --business value that is not a business id (810.128012ms)
ℹ tests 10
ℹ suites 0
ℹ pass 10
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 3853.216345
@@ -0,0 +1,18 @@
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (147.576748ms)
✔ decisions route serves the roles and recent lists from the reader view (71.24427ms)
✔ credentials route serves the broker credential status from the reader view (24.686191ms)
✔ replies route serves the replies to one message from the reader view (65.144473ms)
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (96.434519ms)
✔ bus refusals map to statuses and never carry a path or a stack (35.40309ms)
✔ humanCall speaks the human transport protocol without blocking the server (1857.011131ms)
✔ busReader takes --business, else the live bus host, else refuses (500.647909ms)
✔ humanCall kills a transport that runs past its timeout (531.323287ms)
✔ serve refuses a --business value that is not a business id (467.071352ms)
ℹ tests 10
ℹ suites 0
ℹ pass 10
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 3983.488051
@@ -0,0 +1,18 @@
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (131.308066ms)
✔ decisions route serves the roles and recent lists from the reader view (73.717113ms)
✔ credentials route serves the broker credential status from the reader view (26.525262ms)
✔ replies route serves the replies to one message from the reader view (43.755167ms)
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (87.245157ms)
✔ bus refusals map to statuses and never carry a path or a stack (31.51965ms)
✔ humanCall speaks the human transport protocol without blocking the server (1789.459657ms)
✔ busReader takes --business, else the live bus host, else refuses (358.189276ms)
✔ humanCall kills a transport that runs past its timeout (532.381089ms)
✔ serve refuses a --business value that is not a business id (545.94619ms)
ℹ tests 10
ℹ suites 0
ℹ pass 10
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 3812.185455
@@ -0,0 +1,108 @@
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (7922.129029ms)
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (10589.292103ms)
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (13846.049306ms)
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (272.984809ms)
✔ decisions route serves the roles and recent lists from the reader view (284.339931ms)
✔ credentials route serves the broker credential status from the reader view (54.853255ms)
✔ replies route serves the replies to one message from the reader view (208.806256ms)
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (480.022848ms)
✔ bus refusals map to statuses and never carry a path or a stack (320.875093ms)
✔ humanCall speaks the human transport protocol without blocking the server (4504.413901ms)
✔ busReader takes --business, else the live bus host, else refuses (1086.858268ms)
✔ humanCall kills a transport that runs past its timeout (538.572787ms)
✔ serve refuses a --business value that is not a business id (1014.827467ms)
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (7634.87859ms)
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (4494.326139ms)
✔ conversation view: a newer session with no readable history keeps the marker (2208.366445ms)
✔ conversation view: seats without history say so and offer no reply (1468.715575ms)
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (6641.979629ms)
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (58409.064883ms)
✔ copy writes the Console paths at the full id, read-only, and leaves an existing copy alone (3123.713189ms)
✔ copy refuses a commit off refactor, an unknown one, a worktree and a bad copies directory (4399.658862ms)
✔ copy writes nothing when an archived path is missing at the commit (1455.180147ms)
✔ a copy that loses the rename race leaves no read-only temp directory behind (1344.95328ms)
✔ serve runs from a copy: /healthz 200, the config check, roles and RELEASE from the copy, the queue from --checkout (2876.584159ms)
✔ serve refuses a --checkout that is not an absolute directory path (738.777325ms)
✔ consoleReads runs the queue read under queueRoot and reads RELEASE under root (100.933236ms)
✔ preview options are all three or none, and each is checked (71.416393ms)
✔ the CLI refuses a partial or invalid preview flag set at start (5925.258645ms)
✔ the CLI with all three flags serves the preview mode (1120.846329ms)
✔ a request for the public name needs the header equal to the user id, else 401 and nothing read (83.167076ms)
✔ the header name matches without regard to case, and the value compare is exact (48.60573ms)
✔ the public name with the header reads the bus views, and the Host and Origin are checked first (180.376949ms)
✔ in preview mode every write answers 403 read-only, from the public name and loopback, and reaches nothing (58.779701ms)
✔ loopback requests are unchanged in preview mode, and the bus views work with the board down (10.558133ms)
✔ a proxy that rewrites Host to the loopback port gets 403 on its first request, whatever the user (46.371305ms)
✔ a repeated Host is 400 before any other check, in preview mode and without it (38.70273ms)
✔ without the preview flags the public name is refused and writes still reach the board (25.624988ms)
✔ redactor: config, dataRoot, any absolute path, Discord ids and the JSON parser quote (2.618182ms)
✔ credential state from the date alone, as the bus states it (0.390239ms)
✔ queue: rows, one row, ids and methods, notes; no path or id from a row (4828.447275ms)
✔ queue: a refused read fails closed with the store's text, redacted (2195.360083ms)
✔ queue: a store that fails to load, or a child that dies, gives a fixed message with no path or stack (3945.207078ms)
✔ business: names, vars on the allowlist, authority, credential metadata only (23.99685ms)
✔ business: missing or invalid file refuses with the module's text, redacted (24.215847ms)
✔ business without --business: the live bus host, else no-bus-host; no system config: not-configured (71.843937ms)
✔ settings: release, board, loopback address, notifier binding name only (1035.907629ms)
✔ task fields: the committed table with no reads configured, GET only; a bad table refuses with no path (72.91973ms)
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (7058.779135ms)
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (25687.574783ms)
✔ 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 (9571.866523ms)
✔ a sent receipt lists its replies as the page refreshes, oldest first and capped, and marks none delivered or read (13447.203331ms)
✔ startServer takes send only as a function and only with the preview mode (38.494842ms)
✔ the CLI refuses --send without the preview flags, and without a configured bus (3189.296308ms)
✔ the CLI with --send and a configured bus sends through the human transport and logs one line (2077.584188ms)
✔ without --send the route is read-only like every other write, and config says no send (89.8573ms)
✔ with --send every other write is still 403 read-only, and nothing reaches the board or bus (105.842042ms)
✔ config says send only on the public name with --send on (31.210357ms)
✔ a send without the signed-in user is 401 and is neither sent nor logged, loopback included (35.525904ms)
✔ each request check refuses before anything is sent, and logs the refusal without the body (250.517286ms)
✔ a send passes exactly to, body and in_reply_to, answers the id, and logs it (13.355596ms)
✔ a crafted role name cannot forge a log line (7.595144ms)
✔ a bus refusal is not sent, with its status; an outcome the bus could not confirm is unknown and never retried (34.977451ms)
✔ through the human transport the request is exactly the business, message.send and the keys (699.379015ms)
✔ against a real broker: the message is written once as a human send, and its refusals map (282.651102ms)
✔ loopback host and board origin fail closed (26.574479ms)
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (692.385365ms)
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (157.697756ms)
✔ unreachable board reports URL; CLI rejects unsupported options (5188.488208ms)
✔ render prints the unit without the preview flags (177.83225ms)
✔ render carries every serve flag, the preview set included (75.348573ms)
✔ a partial preview set is refused (225.778763ms)
✔ a value the unit cannot carry is refused, for every flag (4118.666824ms)
✔ the rendered unit names none of the human proof agent markers and sets no agent variable (343.383428ms)
✔ install into --dir with --no-reload writes the file whole, then reports unchanged (508.407268ms)
✔ install without --no-reload runs daemon-reload and nothing that starts the unit (251.227001ms)
✔ uninstall refuses while the unit is running, with or without --no-reload, and removes it once it is not (1193.671278ms)
✔ status prints the unit state and GET /healthz on the installed port (406.049224ms)
✔ usage: an unknown verb or flag, and start or enable, exit 4 (116.166834ms)
✔ without --send, render is the template with its placeholders filled, byte for byte (122.991269ms)
✔ render --send with the preview set ends ExecStart with --send and changes nothing else (164.049609ms)
✔ --send without the whole preview set is refused and writes nothing (258.177359ms)
✔ install --send into --dir with --no-reload writes the sending unit, and status says whether it sends (1067.692317ms)
✔ uninstall and status take no --send (98.845504ms)
✔ install refuses while the unit is running, in any state but inactive or failed, and changes nothing (799.309273ms)
✔ when the state read fails, install and uninstall refuse with one line and change nothing (122.206697ms)
✔ install needs --copy naming a copy that exists, and refuses outside the canonical checkout without --allow-worktree (109.620424ms)
✔ install refuses unless the bus unit runs from the same copy, naming both paths, and changes nothing (614.213943ms)
✔ render --copy runs the copy and reads the queue in the checkout; without --copy the unit is unchanged (32.644275ms)
✔ the uid header takes only an Authentik uid; the username header still takes a username (616.204805ms)
✔ a preview value cannot start with - or . (68.907765ms)
✔ status names the copy and whether refactor has moved past it, and says when the unit runs from no copy (347.958796ms)
✔ tokens.css and icons.svg are byte copies of docs/design (22.800193ms)
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (3.63211ms)
✔ shipped strings are unchanged, and the web keeps its write boundary (4.060874ms)
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (11089.882591ms)
✔ five states on Board, Inbox, Tasks, Agents and Trail (2958.939696ms)
✔ Queue, Business and Settings in their five states, with no move button (7588.987121ms)
✔ seeded secrets, Discord ids and paths reach no response and no page; business refusals in the module's words (2711.388576ms)
✔ the server log names no config path when the system config refuses (473.55308ms)
ℹ tests 99
ℹ suites 0
ℹ pass 99
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 59395.123456
@@ -0,0 +1,129 @@
✔ browser edge states: loading, empty, malformed, stale, hostile/long values, in-flight reply and appearance fallback (13353.062302ms)
Rendered contrast: {"failures":[],"count":330,"lowest":4.504658476260286}
✔ served Console browser: real board fixtures, keyboard, drafts, receipts, themes, 320px and failures (17505.077679ms)
✔ S5 pages in a browser: real broker rows, inert text, Copy, routes, failures, layout and no writes (21181.360792ms)
✔ bus routes serve the four reads from the reader view, unescaped JSON for the page to escape (514.383962ms)
✔ decisions route serves the roles and recent lists from the reader view (266.757958ms)
✔ credentials route serves the broker credential status from the reader view (58.699559ms)
✔ replies route serves the replies to one message from the reader view (247.282253ms)
✔ bus routes are GET-only, have no write verb, and keep the same-origin checks (675.981643ms)
✔ bus refusals map to statuses and never carry a path or a stack (235.703397ms)
✖ humanCall speaks the human transport protocol without blocking the server (3361.135662ms)
✔ busReader takes --business, else the live bus host, else refuses (2944.918922ms)
✔ humanCall kills a transport that runs past its timeout (779.122407ms)
✔ serve refuses a --business value that is not a business id (2753.024234ms)
✔ conversation view: full history, collapsed tools, hidden thinking, inert hostile content, malformed and reconcile markers (12928.611006ms)
✔ conversation view: a fork keeps the open branch, says so, and opens the new one on request (5813.12294ms)
✔ conversation view: a newer session with no readable history keeps the marker (3096.668897ms)
✔ conversation view: seats without history say so and offer no reply (2649.397758ms)
✔ Discord row through real board/WebUI: independent brake/liveness, no Reply, literal content (11186.080048ms)
✔ return flow through the conversation view: send, tool call, delayed result, peer message, exact long answers, relaunch (53058.506895ms)
✔ copy writes the Console paths at the full id, read-only, and leaves an existing copy alone (3644.410381ms)
✔ copy refuses a commit off refactor, an unknown one, a worktree and a bad copies directory (9728.174492ms)
✔ copy writes nothing when an archived path is missing at the commit (3970.533696ms)
✔ a copy that loses the rename race leaves no read-only temp directory behind (1362.906942ms)
✔ serve runs from a copy: /healthz 200, the config check, roles and RELEASE from the copy, the queue from --checkout (3048.775691ms)
✔ serve refuses a --checkout that is not an absolute directory path (999.704484ms)
✔ consoleReads runs the queue read under queueRoot and reads RELEASE under root (587.347684ms)
✔ preview options are all three or none, and each is checked (17.22235ms)
✔ the CLI refuses a partial or invalid preview flag set at start (8329.855ms)
✔ the CLI with all three flags serves the preview mode (2086.394744ms)
✔ a request for the public name needs the header equal to the user id, else 401 and nothing read (276.985812ms)
✔ the header name matches without regard to case, and the value compare is exact (196.690926ms)
✔ the public name with the header reads the bus views, and the Host and Origin are checked first (243.570901ms)
✔ in preview mode every write answers 403 read-only, from the public name and loopback, and reaches nothing (729.074769ms)
✔ loopback requests are unchanged in preview mode, and the bus views work with the board down (11.857127ms)
✔ a proxy that rewrites Host to the loopback port gets 403 on its first request, whatever the user (130.317131ms)
✔ a repeated Host is 400 before any other check, in preview mode and without it (35.076658ms)
✔ without the preview flags the public name is refused and writes still reach the board (118.636348ms)
✔ redactor: config, dataRoot, any absolute path, Discord ids and the JSON parser quote (3.571251ms)
✔ credential state from the date alone, as the bus states it (0.458354ms)
✔ queue: rows, one row, ids and methods, notes; no path or id from a row (6200.374865ms)
✔ queue: a refused read fails closed with the store's text, redacted (4773.698702ms)
✔ queue: a store that fails to load, or a child that dies, gives a fixed message with no path or stack (7089.238058ms)
✔ business: names, vars on the allowlist, authority, credential metadata only (53.019466ms)
✔ business: missing or invalid file refuses with the module's text, redacted (43.157373ms)
✔ business without --business: the live bus host, else no-bus-host; no system config: not-configured (55.083594ms)
✔ settings: release, board, loopback address, notifier binding name only (692.232526ms)
✔ task fields: the committed table with no reads configured, GET only; a bad table refuses with no path (265.343821ms)
✔ both presentations replace old activity with relaunch notice, label retained history, then resume after new activity (13140.177462ms)
✔ reported return flow and relative Age: reply sent from the inspector, then the new answer appears there without manual refresh (30875.11132ms)
✔ 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 (17686.470718ms)
✔ a sent receipt lists its replies as the page refreshes, oldest first and capped, and marks none delivered or read (14649.112647ms)
✔ startServer takes send only as a function and only with the preview mode (83.297459ms)
✔ the CLI refuses --send without the preview flags, and without a configured bus (6801.340148ms)
✔ the CLI with --send and a configured bus sends through the human transport and logs one line (2992.652988ms)
✔ without --send the route is read-only like every other write, and config says no send (151.048723ms)
✔ with --send every other write is still 403 read-only, and nothing reaches the board or bus (101.145607ms)
✔ config says send only on the public name with --send on (23.158872ms)
✔ a send without the signed-in user is 401 and is neither sent nor logged, loopback included (137.394777ms)
✔ each request check refuses before anything is sent, and logs the refusal without the body (233.684497ms)
✔ a send passes exactly to, body and in_reply_to, answers the id, and logs it (66.595528ms)
✔ a crafted role name cannot forge a log line (50.322395ms)
✔ a bus refusal is not sent, with its status; an outcome the bus could not confirm is unknown and never retried (59.646091ms)
✔ through the human transport the request is exactly the business, message.send and the keys (1184.981285ms)
✔ against a real broker: the message is written once as a human send, and its refusals map (942.91515ms)
✔ loopback host and board origin fail closed (32.398348ms)
✔ real board fixture passes through WebUI; assets and isolated seen/reply work (612.495128ms)
✔ proxy preserves exact request bytes, status and receipt, rejects forms and malformed JSON, never follows redirect (375.783908ms)
✔ unreachable board reports URL; CLI rejects unsupported options (6974.571769ms)
✔ render prints the unit without the preview flags (527.087753ms)
✔ render carries every serve flag, the preview set included (314.620671ms)
✔ a partial preview set is refused (1017.24355ms)
✔ a value the unit cannot carry is refused, for every flag (5937.492565ms)
✔ the rendered unit names none of the human proof agent markers and sets no agent variable (307.249806ms)
✔ install into --dir with --no-reload writes the file whole, then reports unchanged (957.169485ms)
✔ install without --no-reload runs daemon-reload and nothing that starts the unit (451.676692ms)
✔ uninstall refuses while the unit is running, with or without --no-reload, and removes it once it is not (1694.11373ms)
✔ status prints the unit state and GET /healthz on the installed port (927.078831ms)
✔ usage: an unknown verb or flag, and start or enable, exit 4 (593.176179ms)
✔ without --send, render is the template with its placeholders filled, byte for byte (626.057374ms)
✔ render --send with the preview set ends ExecStart with --send and changes nothing else (634.790175ms)
✔ --send without the whole preview set is refused and writes nothing (1047.147522ms)
✔ install --send into --dir with --no-reload writes the sending unit, and status says whether it sends (1416.030944ms)
✔ uninstall and status take no --send (292.176366ms)
✔ install refuses while the unit is running, in any state but inactive or failed, and changes nothing (3165.689542ms)
✔ when the state read fails, install and uninstall refuse with one line and change nothing (1008.734269ms)
✔ install needs --copy naming a copy that exists, and refuses outside the canonical checkout without --allow-worktree (646.89939ms)
✔ install refuses unless the bus unit runs from the same copy, naming both paths, and changes nothing (1106.818942ms)
✔ render --copy runs the copy and reads the queue in the checkout; without --copy the unit is unchanged (69.968863ms)
✔ the uid header takes only an Authentik uid; the username header still takes a username (1280.511271ms)
✔ a preview value cannot start with - or . (89.433601ms)
✔ status names the copy and whether refactor has moved past it, and says when the unit runs from no copy (475.249886ms)
✔ tokens.css and icons.svg are byte copies of docs/design (3.3454ms)
✔ JetBrains Mono files match the digests in their sources file, with the OFL text (26.377882ms)
✔ shipped strings are unchanged, and the web keeps its write boundary (9.230331ms)
✔ shell in a browser: System default, seeded states, 400px, focus and the Ctrl+K palette (14604.156031ms)
✔ five states on Board, Inbox, Tasks, Agents and Trail (6696.544258ms)
✔ Queue, Business and Settings in their five states, with no move button (11775.027569ms)
✔ seeded secrets, Discord ids and paths reach no response and no page; business refusals in the module's words (5054.620031ms)
✔ the server log names no config path when the system config refuses (1573.285308ms)
ℹ tests 99
ℹ suites 0
ℹ pass 98
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 54658.862666
✖ failing tests:
test at packages/webui/tests/bus.test.mjs:266:1
✖ humanCall speaks the human transport protocol without blocking the server (3361.135662ms)
AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ actual - expected
+ 'outcome-unknown'
- 'invalid-response'
at TestContext.<anonymous> (file:///mnt/storage/scratch/rocko-r77/packages/webui/tests/bus.test.mjs:273: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: 'outcome-unknown',
expected: 'invalid-response',
operator: 'strictEqual',
diff: 'simple'
}
@@ -0,0 +1,40 @@
node-webui exit 1
ℹ pass 98
ℹ fail 1
test-auth exit 0
test-auth: OK auth.sh without valid config refuses
test-auth:
test-auth: selftest: 15 passed, 0 failed
test-conductor exit 0
test-conductor: OK invalid policy exits 2 (exit 2)
test-conductor:
test-conductor: selftest: 17 passed, 0 failed
test-config exit 0
test-config: OK failed validation modified nothing
test-config:
test-config: selftest: 24 passed, 0 failed
test-discord exit 0
test-discord: OK service install with USER unset finishes and names the account for lingering
test-discord:
test-discord: discord suite: 66 passed, 0 failed
test-extension-package exit 0
test-extension-package: OK nested second entrypoint fails closed
test-extension-package:
test-extension-package: extension package selftest: 18 passed, 0 failed
test-foundation exit 0
test-foundation: OK no field of the non-bundle file is echoed
test-foundation:
test-foundation: selftest: 44 passed, 0 failed
test-queue exit 0
test-queue: skip queue verify and render --check: this checkout (/mnt/storage/scratch/rocko-r77) is not the queue's canonical root (/mnt/storage/src/mosaic-stack)
test-queue:
test-queue: queue suite: 27 passed, 0 failed
test-release exit 0
test-release: OK rollback without previous refuses (exit 1)
test-release:
test-release: selftest: 14 passed, 0 failed
test-task exit 0
test-task: OK no agent identity on headless run
test-task:
test-task: selftest: 98 passed, 0 failed
failure markers in: /mnt/storage/scratch/rocko-r77-r2/gate/node-webui.txt
@@ -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,70 @@
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/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/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 178)
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
discord suite: 66 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: 3599819 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,35 @@
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/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 150
ℹ pass 150
ℹ fail 0
OK node --test packages/queue/tests/
OK scripts/mosaic queue help
skip queue verify and render --check: this checkout (/mnt/storage/scratch/rocko-r77) is not the queue's canonical root (/mnt/storage/src/mosaic-stack)
queue suite: 27 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,34 @@
KILLED failed counts as running: 2 failing
KILLED reloading not running: 2 failing
KILLED list-units failure ignored: 2 failing
KILLED install skips state read: 3 failing
KILLED uninstall skips state read with --no-reload: 1 failing
KILLED uid header case-sensitive: 1 failing
KILLED uid allows upper hex: 1 failing
KILLED allowed user may start with -: 2 failing
KILLED no --checkout in unit: 4 failing
KILLED canonical always passes: 2 failing
KILLED install without --copy: 1 failing
KILLED missing copy accepted: 2 failing
KILLED status drift wrong: 1 failing
KILLED copy misses seat: 1 failing
KILLED copy misses README: 1 failing
KILLED commit may start with a dot: 1 failing
KILLED copy misses tasks src: 1 failing
KILLED copy misses fields table: 2 failing
KILLED copy stays writable: 1 failing
KILLED copy dirs stay writable: 1 failing
KILLED copy subdirs stay writable: 1 failing
KILLED trap leaves read-only temp: 1 failing
KILLED copy off-branch accepted: 5 failing
KILLED queue reads root: 2 failing
KILLED --checkout relative ok: 1 failing
KILLED install skips bus check: 2 failing
KILLED bus path prefix only: 1 failing
KILLED bus not-found accepted: 1 failing
KILLED bus show failure ignored: 1 failing
KILLED bus list failure ignored: 1 failing
KILLED no loaded bus accepted: 1 failing
KILLED no ExecStart path accepted: 1 failing
KILLED only first bus unit checked: 1 failing
KILLED --business ignored for bus: 1 failing
@@ -0,0 +1,45 @@
125da8fe5a1d1dc2f4c75215fc560e503b4e6bc720e04bda84f4e5e65e49c032 ./base.txt
46e71d49a77f8c579121734237c6163a90bee10c20671b1efb0df754bb6629ff ./BUILD.md
8f983bf4edcd5e245d46685e2d322b536b7b56cce843092cec011840c595b321 ./build.patch
045f0ac8333709fbe7badbed7ca45f29f0d11c0d2aaee952fb1a5b77727c55ad ./candidate-manifest.sha256
adaee0d7d46742fe5b1eb17d04b75128f80ae5bc9544a3bc4b1de3ce632bb1d7 ./files.txt
85f722a82873b52d2c02f8573eb9c63b025514f239551bff214e44b8303b00c0 ./mutants.py
b1bb6d5ce6672bb0410098cc7e591f857f19d6788945806bd0953101719ec4f7 ./out/after-gate.sh
7236b1386f47d3e88f44c1baeb3cdc3ba4e0d72df6cf57b3ecd7adf24f56dfb4 ./out/byte-check/base-1.txt
619a486a2828f6eab280f8df4dd82735464c02a5aded055137374f6f3c17f9b0 ./out/byte-check/base-2.txt
64d6be0adfe28df72a3b79ede380561ddf18a93afccacc27ed8314d05ce18c7d ./out/byte-check/base-3.txt
3d5a4aac2243cc40acb90f8917372cedc222e354ea09bce939856568735da229 ./out/byte-check/base-4.txt
ffbfc5ee5865a1fd4705f1ae32b1e802c7b68789955a5e3b381fa242781ea63d ./out/byte-check/base-5.txt
ce08c820abdee674b08f09768e6fc56b8a17cfe082829d8c26daa1e456ec1a6f ./out/byte-check/base-6.txt
d38e7cfe67f8045602923579a9087779cc05cb433490ea606132be49ac53a897 ./out/byte-check/base-7.txt
af9d8b17ad1c42d0c881ff9a72673044b0ebc52eb78cf453ee76614b2cc0be72 ./out/byte-check/base-8.txt
7236b1386f47d3e88f44c1baeb3cdc3ba4e0d72df6cf57b3ecd7adf24f56dfb4 ./out/byte-check/cand-1.txt
619a486a2828f6eab280f8df4dd82735464c02a5aded055137374f6f3c17f9b0 ./out/byte-check/cand-2.txt
64d6be0adfe28df72a3b79ede380561ddf18a93afccacc27ed8314d05ce18c7d ./out/byte-check/cand-3.txt
3d5a4aac2243cc40acb90f8917372cedc222e354ea09bce939856568735da229 ./out/byte-check/cand-4.txt
ffbfc5ee5865a1fd4705f1ae32b1e802c7b68789955a5e3b381fa242781ea63d ./out/byte-check/cand-5.txt
ce08c820abdee674b08f09768e6fc56b8a17cfe082829d8c26daa1e456ec1a6f ./out/byte-check/cand-6.txt
d38e7cfe67f8045602923579a9087779cc05cb433490ea606132be49ac53a897 ./out/byte-check/cand-7.txt
af9d8b17ad1c42d0c881ff9a72673044b0ebc52eb78cf453ee76614b2cc0be72 ./out/byte-check/cand-8.txt
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 ./out/byte-check/template-body.diff
c8865434415cf50faef608ff185e4390ef068b1239c1bdfa8195f7b7ce98f872 ./out/byte-check.txt
87385410957c4fdb782d10d20d0165d24d01ae24a5b56035273907c5e033cf9a ./out/gate/after.txt
abbee45800283182f193e780bbc6ee2f666f0305effb2318aac386461b09f87e ./out/gate/bus-test-1.txt
2399761fe44a30b3cc017b84caa9f703969414f8e77fff193c0be6ac2148bde2 ./out/gate/bus-test-2.txt
84e3879d5b4a219589aede605f905b4a9daf8fa710e9f62e13ab54de5aeb0bb9 ./out/gate/bus-test-3.txt
83a2c8ecad58df5112b1565d8fd8024e8cff230722068defb4777a593b574b78 ./out/gate/bus-test-4.txt
6f705a0619571629cfb7df5b8974ae79ee143e85f0507ad8938f50c3a9f6b746 ./out/gate/bus-test-5.txt
b21fed7b714090f83978b18c30a5aa6a12f08fda55ff53a9bc2275cc67e39bca ./out/gate/node-webui-rerun.txt
02e7914e7621f2d31faf015611d3b0c64686720b89a0b7b1cb9a22db2ecd9139 ./out/gate/node-webui.txt
12167bcacf7e8d5172c2a5a3e2d33050923a2d6a6aee05e68b216be839d54ee5 ./out/gate.sh
6da159300c4c5d834cc9abf729edabe661f15e692ceabd7c079fb2270e27c872 ./out/gate/summary.txt
f91fc95a173339137f981e24fbf630acfde957e32c3cd71e28304532083c6a77 ./out/gate/test-auth.txt
e1206366f07f3d9029530dcdcb55c0282d3f052adc60fc7fd51642d5d4ec3600 ./out/gate/test-conductor.txt
52d211444489ea729dafc3c9745d4474d9dfd50f41055cbad792424197f04073 ./out/gate/test-config.txt
7d5016ded1994048642f8b9ae845e52e8af4a069ba05c056c8f580a4589bacbe ./out/gate/test-discord.txt
c61a2dafbbdfcde691e656b9d0ba9b62ab8179002fa7fc0f4686900c76124913 ./out/gate/test-extension-package.txt
83dfaa21c4e4ad941088efab3f69e87ebd2f6bd3cc72ede938e21dc06da8a34f ./out/gate/test-foundation.txt
0cd57fe625b02fdc477f1aea2c54a9cabcc8af10eb2b53fd6dbbb1eab3b5c3fd ./out/gate/test-queue.txt
fa832794ee35025fb4559d58d01a270f6bff2eb65e863e9075b797f47fa68545 ./out/gate/test-release.txt
ccea37f4ffde1f160dcd1a1864988083a645d974e892065c956b338d0f8c853a ./out/gate/test-task.txt
212135b87a3a39748e8bba8fa528701098343dfacb2630b56e81ec9542471b7c ./out/mutants.txt
+1
View File
@@ -780,3 +780,4 @@ are never rewritten or removed; corrections are new entries.
2026-10-12T19:58:50Z | dewey | row 63 (#1556) round 1 review for darkwing | changes, test-only: comment 27847, rev 740 (in sage's af01465c), packet agents/dewey/work/queue-63-review/r1 (7a3e85a3). Candidate ec28d736 tasks 80, harness 59, business 60, bus 95 rc=0; code right, 5 of 10 of my mutants survive on the child re-read, final-read and fallback paths and on located's loop; proof-tests.mjs kills all five. All five build choices agreed. Filbert approved (27846) with the same gap as non-blocking N1.
2026-10-12T19:56:44Z | dewey | correction to my 19:58:50Z row 63 review line | that stamp was typed, not read from the clock; the line was written at about 19:57Z (date -u read 19:56:30Z just before it). Content unchanged.
2026-10-12T19:57:52Z | sage | Q125 (Mos sage-0104 to 0107): Jason's PM test faults to rows | rows 93-95 briefed (#1587-1589, docs/plans/2026-10-12_pm-test-fixes.md), 89/90/92 briefs extended for faults 9, 10 and the session credential, decision 118; Console cause found (works as built, Board is the machine scan, pre-row-81 build, no PM-started messages, cross-origin 302 during sign-in loss); answered Mos (bus restart ends PM runs), order 92,89,95,94,90,91,93 then redeploy; Input needed to Jason via Mos: row 92 credential choice; pushed 5849de76..40067b32. Correction: 6aebcef3 also swept darkwing revs 719-720, its message names only 711-718
2026-10-12T20:03Z | rocko | row 77 (#1571) candidate round 2 | packet agents/rocko/work/queue-77/r2/ (candidate manifest 045f0ac8, base 04db738a); in-review→in-progress rev 745, in-progress→in-review round 2 rev 746, request rocko-77-review-2 failed rev 747 (no credential; Sage sends as jarvis); gate 9 scripts green, webui 98/1 load flake in bus.test (not in diff) then 99/0; 34/34 mutants killed; live unit untouched