build.patch againstd13b9300(brief blobf8d14d70, rev 630), candidate manifest, identity and mutant harnesses with results, gate summary. Co-Authored-By: Claude Opus 5.5 <[email protected]>
11 KiB
Row 83 (#1576): Console service, the unit script takes --send, round 1
Owner: Dewey. Reviewers: Darkwing and Filbert, then Sage's gate. Brief:
docs/plans/2026-10-12_console-service-send.md § "The unit script takes
--send", blob f8d14d70 (re-pinned at rev 630 for lead decision 102; first
pinned as 739bea66 at rev 627, briefed at rev 628). Lead decision 101
gives the reason. Base d13b9300. None of the candidate's paths, nor the
template, changed between d13b9300 and refactor HEAD (a1c5c8fc) when
the packet was built.
build.patch is git diff --cached --binary d13b9300 -- the four paths
below. Apply it with git apply --index to a detached worktree of the base;
candidate-manifest.sha256 then checks 4/4 OK (checked on a fresh
worktree).
What ships
renderandinstalltake--send, a flag with no value. It is accepted only with all three preview flags. Otherwiseserve_flagsrefuses before anything is written: exit 1, empty stdout, and on stderrwebui-service: --send needs the preview mode (--public-host, --auth-header and --allow-user), serve's own wording (cli.mjs:37).installrenders beforemkdir, so a refusal creates no directory and leaves an installed unit alone (tested).- With
--send, ExecStart ends... --allow-user ID --send. Nothing else in the unit changes (tested line by line against the same render without--send). - Without
--send, every render is the template with its four placeholders filled, byte for byte (new test), and the base and candidate scripts give the same stdout, stderr, status and installed files on every argument list the base tests use (identity.txt). uninstallandstatustake no--send: it sets SERVE_SET like the other serve flags, so both exit 4 (tested with a stand-in systemctl).statusprints one new line when a unit is installed:send: on (--send; human messages to roles)orsend: off (read-only). The brief allowed this "if small"; it is five lines plus a comment. With no unit installed there is no send line.USAGEand the header comment name[--send]inside the preview set. README's service paragraph and TOOLS.md's "Console service" section say the script takes--sendonly with the preview set (exit 1, nothing written), that ExecStart then ends with--send, and that the Console needs the system config at start (--send needs the bus configured, exit 2, which the unit doesn't restart:RestartPreventExitStatus=2in the template). README's "Message a role"--sendparagraph gets one sentence pointing atscripts/webui-service.sh installwith--send.- The start wording (lead decision 102). The script's header comment, its
install message, TOOLS.md's "Console service" and README's service
paragraph now say Jason starts and restarts the Console, and so may Mos
under decision 102, which accepts that sends from a Console Mos started
enter the trail as Jason (
human-cli). Any other agent starting it, even through systemd, still works around the human proof (decisions 62 and 94). The script still has no start, stop or restart verb. A test checks the install message's wording.
The template (packages/webui/systemd/mosaic-webui.service.in) is
unchanged. install prints no new line; its serve: line already shows
the ExecStart, --send included. The install message's opening sentence
changed wording only (decision 102).
Decisions and tradeoffs
- Refusal order. The
--sendcheck runs before the all-three check.--sendwith one or two preview flags therefore gets the--sendmessage, not "all three or none". The brief asks for a message naming the preview flags the way serve refuses, and serve checks the preview set first. Both messages name the three flags. A partial preview set without--sendstill gets "all three or none" (base test unchanged). - Status detection is anchored on the allowed user. My first version
matched
^ExecStart=.* --send$. The mutantstatus-send-anywheresurvived it, and that showed a real gap:--allow-useraccepts the value--send(its character set allows-, and serve'sUSERpattern accepts it), so a read-only unit's ExecStart can end--allow-user --send. The check is now^ExecStart=.* --allow-user [^ ][^ ]* --send$. render always puts--sendright after the allowed user, so a sending unit ends with both the allowed user and--send. A test installs both cases, read-only--allow-user --sendand sending--allow-user --send --send, and checks status for each. - No config or bus check in the script (out of scope per the brief).
A unit installed with
--sendon a host without the system config installs fine and exits 2 at start; the docs say so.
Files
scripts/webui-service.sh:SEND=0, the--sendcase, the refusal and the append inserve_flags, the status line, USAGE and header.packages/webui/tests/service.test.mjs: 5 new tests, 2 widened.packages/webui/README.md: the service paragraph, one sentence in "Message a role".docs/TOOLS.md: the "Console service" FLAGS comment and prose.
Tests
packages/webui/tests/service.test.mjs, 15 tests (10 base, 5 new). The
helper filled(flags) is the template with @REPO@, @PATH@, @NODE@
and @FLAGS@ replaced, computed in the test the way the base script does
it.
- without --send, render is the template with its placeholders filled, byte for byte: five flag combinations, from none to every flag.
- render --send with the preview set ends ExecStart with --send and
changes nothing else: four argument orders (
--sendfirst, last, in the middle of the preview set, with--portand--business). Each equalsfilled(flags + ' --send'), and against the same render without--sendexactly one line differs, the ExecStart, by--send. - --send without the whole preview set is refused and writes nothing:
--sendalone, with--port, with--business, with each one of the three preview flags, and with each two of the three. Eachrendergives exit 1, empty stdout and serve's message. Eachinstallinto a fresh--dirgives the same, and the directory is never created. An install of--sendwith two preview flags over an installed unit leaves it byte for byte, with no temp file and no systemctl call. - install --send into --dir with --no-reload writes the sending unit, and
status says whether it sends:
written:, theserve:line ending--send, the file equal tofilled(...), mode 0644, no temp file; statussend: on; reinstallunchanged:; install without--sendwrites the read-only unit and status sayssend: off (read-only); the odd allowed user--sendcase above; nosend:line without a unit. The only systemctl calls are status's reads. Status's/healthzgoes to a loopback port that was just closed, so it reaches no real Console. - uninstall and status take no --send: exit 4 for
uninstall --send(with and without--no-reload) andstatus --send, against a stand-in systemctl that records no call; the unit stays installed. - Widened: the agent-marker test also renders
[...PREVIEW, '--send']; the usage test addsrender --send yes ...PREVIEW(--sendtakes no value); the install test checks the decision 102 start wording in the install message.
Why the uninstall and status cases sit in their own test: in the usage
loop they run with the real /usr/bin/systemctl on PATH. A mutant where
--send doesn't set SERVE_SET would let uninstall --send reach a real
systemctl --user daemon-reload. With the stand-in, no mutant can.
Byte identity (identity.mjs, identity.txt)
One scratch worktree of d13b9300 holds the base script as
scripts/webui-service-base.sh and the candidate as
scripts/webui-service.sh, so REPO and the template are the same for
both. Each script runs the same 86 argument lists from a clean scratch:
every render the base tests make (the value and port refusals included),
the usage list, --help, and an install, reinstall, refused install,
install over, status, uninstall, uninstall and status sequence, all with
--no-reload and a stand-in systemctl.
Result: 69 identical, 17 expected differences, 0 unexpected. The 17 are
the usage text on 12 exit-4 cases plus --help (the FLAGS line names
[--send]), three installs whose message differs only in the decision 102
start wording (the base message's opening lines replaced by the
candidate's, then everything else identical, installed unit included),
and one status with a unit installed (the added send: off (read-only)
line, nothing else). A self-check: with the append made
unconditional, the same run reports 13 unexpected differences.
Mutants (mutants.py, mutants.txt)
15 single-site mutants of scripts/webui-service.sh, each run against the
base tests (d13b9300's service.test.mjs), the candidate tests and
identity.mjs. Baselines: all three pass on the unmutated candidate.
Rerun on the decision 102 candidate, 2026-10-12T03:53Z; same results as
the first run.
| mutant | base tests | candidate tests |
|---|---|---|
| send-no-preview-check | survived | killed |
| send-needs-any-preview | survived | killed |
| send-message-reworded | survived | killed |
| send-no-append | survived | killed |
| send-append-always | killed | killed |
| send-append-before-preview | survived | killed |
| send-default-on | killed | killed |
| send-no-serve-set | survived | killed |
| send-takes-value | survived | killed |
| send-flag-unknown | survived | killed |
| status-send-always-off | survived | killed |
| status-send-always-on | survived | killed |
| status-no-send-line | survived | killed |
| status-send-anywhere | survived | killed |
| status-send-suffix-only | survived | killed |
The candidate tests kill 15 of 15. The two the brief names,
send-no-preview-check and send-no-append, survive the base tests.
send-append-always and send-default-on are killed by the base tests
too, as a change to every render should be.
Gate (my run on the candidate)
On the staged candidate in a worktree of d13b9300, run sequentially,
2026-10-12T03:54:20Z to 03:58:42Z (gate-summary.txt):
packages/webui,node --test 'tests/*.test.mjs': 81 tests, 81 pass, rc=0.scripts/test-auth.sh,test-conductor.sh,test-config.sh,test-discord.sh,test-extension-package.sh,test-foundation.sh,test-queue.sh,test-release.sh,test-task.sh: all rc=0.
For reviewers
- Allowed user starting with
-. The base script and serve both accept an allowed user like--sendor-x. That isn't new here, and changing it would change no---sendrenders, which the brief rules out. The only effect on this row was status detection, now anchored. If it should be refused, that's a follow-up for the script and serve together. - The template's comment still says Jason starts it.
mosaic-webui.service.inlines 6-9 say Jason starts it from a personal shell and that an agent starting it works around the human proof. The template isn't in this row's files and is rendered into every unit, so changing it would break the byte identity the brief asks for. Bringing it in line with decision 102 is a follow-up (a template change plus the render tests that pin it). - Nothing here starts, enables or restarts a unit, and no test reaches the
real systemd: every install and uninstall uses
--no-reloador a stand-in systemctl.