Files
stack/agents/dewey/work/queue-83/build.md
T
jason.woltjeandClaude Opus 5.5 e1bf582a1a dewey: row 83 round 1 packet, unit script takes --send (#1576)
build.patch against d13b9300 (brief blob f8d14d70, rev 630), candidate
manifest, identity and mutant harnesses with results, gate summary.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-11 22:59:05 -05:00

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

  • render and install take --send, a flag with no value. It is accepted only with all three preview flags. Otherwise serve_flags refuses before anything is written: exit 1, empty stdout, and on stderr webui-service: --send needs the preview mode (--public-host, --auth-header and --allow-user), serve's own wording (cli.mjs:37). install renders before mkdir, 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).
  • uninstall and status take no --send: it sets SERVE_SET like the other serve flags, so both exit 4 (tested with a stand-in systemctl).
  • status prints one new line when a unit is installed: send: on (--send; human messages to roles) or send: 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.
  • USAGE and the header comment name [--send] inside the preview set. README's service paragraph and TOOLS.md's "Console service" section say the script takes --send only 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=2 in the template). README's "Message a role" --send paragraph gets one sentence pointing at scripts/webui-service.sh install with --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 --send check runs before the all-three check. --send with one or two preview flags therefore gets the --send message, 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 --send still gets "all three or none" (base test unchanged).
  • Status detection is anchored on the allowed user. My first version matched ^ExecStart=.* --send$. The mutant status-send-anywhere survived it, and that showed a real gap: --allow-user accepts the value --send (its character set allows -, and serve's USER pattern 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 --send right 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 --send and 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 --send on 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 --send case, the refusal and the append in serve_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 (--send first, last, in the middle of the preview set, with --port and --business). Each equals filled(flags + ' --send'), and against the same render without --send exactly one line differs, the ExecStart, by --send.
  • --send without the whole preview set is refused and writes nothing: --send alone, with --port, with --business, with each one of the three preview flags, and with each two of the three. Each render gives exit 1, empty stdout and serve's message. Each install into a fresh --dir gives the same, and the directory is never created. An install of --send with 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:, the serve: line ending --send, the file equal to filled(...), mode 0644, no temp file; status send: on; reinstall unchanged:; install without --send writes the read-only unit and status says send: off (read-only); the odd allowed user --send case above; no send: line without a unit. The only systemctl calls are status's reads. Status's /healthz goes 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) and status --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 adds render --send yes ...PREVIEW (--send takes 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 --send or -x. That isn't new here, and changing it would change no---send renders, 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.in lines 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-reload or a stand-in systemctl.