From d7e1d5ed5d52e4a271585df8b605f0b012e9f6dd Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Wed, 14 Oct 2026 11:13:43 -0500 Subject: [PATCH] docs: brief for the Discord connector on a pinned copy (#1608) Mos asked on 2026-10-14 for the connector unit to follow row 85's rule. install --copy, status names the copy, check --offline, tests and docs. The live repoint waits for Mos's go after the SetSpark freeze lifts. Co-Authored-By: Claude Opus 5.5 --- docs/plans/2026-10-14_discord-pinned-copy.md | 138 +++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 docs/plans/2026-10-14_discord-pinned-copy.md diff --git a/docs/plans/2026-10-14_discord-pinned-copy.md b/docs/plans/2026-10-14_discord-pinned-copy.md new file mode 100644 index 000000000..855203306 --- /dev/null +++ b/docs/plans/2026-10-14_discord-pinned-copy.md @@ -0,0 +1,138 @@ +# Discord connector on a pinned copy (2026-10-14) + +Filed by Sage at Mos's request of 2026-10-14 (reply to sage-0162: "yes, +pin it, under the same rule as row 85"). Gitea #1608. + +## Discord connector unit runs from a pinned copy + +### Problem + +`mosaic-discord@shared-signals.service` runs the connector straight from +the checkout. On 2026-10-14 that was pid 5841, up since 2026-10-13 08:40:34 +CDT, running `node /mnt/storage/src/mosaic-stack/packages/discord/src/cli.mjs +run shared-signals --supervised --repo /mnt/storage/src/mosaic-stack`. +`packages/discord/systemd/mosaic-discord@.service.in` sets +`WorkingDirectory=@REPO@` and `ExecStart=@REPO@/scripts/discord.sh run %i +--supervised`, and `scripts/discord.sh` passes `--repo` as its own +checkout. + +The unit has `Restart=on-failure`. Any landing that touches +`packages/discord` therefore goes live at the connector's next crash +restart, with nobody's go. The bus, the Console and the `mosaic` CLI have +run from read-only copies since row 85 (`scripts/stack-copy.sh`, +`~/.local/share/mosaic-stack/copies/`), and a landing reaches them only +through a re-pin under Mos's go. This row gives the connector the same rule. + +`--repo` decides three things in the connector, all in +`packages/discord/src/cli.mjs` `prepare` and `run`: + +- the binding's `context.files`, which must resolve inside it + (`resolveContextFiles` in `binding.mjs`); +- the engine binary, `/node_modules/.bin/pi`; +- the engine's working directory. + +The tools extension and the git credential helper already resolve from the +module's own path (`engine-pi.mjs:48`, `git.mjs:61`). A copy already has +`packages/discord/src`, `bin`, `extension`, and `node_modules` with `pi` +(stack-copy `COPY_PATHS`). It has no `scripts/discord.sh` and no +`packages/discord/systemd/`. + +### Owner and reviewer + +- Owner: rocko, after row 108. Row 108 also edits `docs/TOOLS.md`. +- Reviewer: filbert (decision 130, not a sandbox row). + +### Files owned + +- `scripts/discord-service.sh` +- `packages/discord/systemd/mosaic-discord@.service.in` +- `packages/discord/src/cli.mjs`, the `check` path and option parsing only +- `scripts/test-discord.sh`, the service and `check --offline` cases +- `packages/discord/tests/`, a new or changed test for `check --offline` +- `packages/discord/README.md`, the "Service unit" section and the `check` + usage +- `docs/TOOLS.md`, the Discord service paragraph only +- `agents/rocko/work/queue-/` + +`scripts/stack-copy.sh` is not in this row. Its `COPY_PATHS` already carry +what the connector needs, and its `check` stays bus, Console and CLI only: +the connector moves on its own go, so a shared check would fail every time +the two pins differ. + +### What ships + +1. `scripts/discord-service.sh install --copy ID [--dir DIR] [--no-reload]`: + - ID must be a full 40-character commit id. The copy must exist under + `~/.local/share/mosaic-stack/copies/` (or `--copies DIR`, same as + stack-copy), and it must hold `packages/discord/src/cli.mjs` and + `node_modules/.bin/pi`. Any miss refuses with exit 1, and no unit is + written. + - The rendered unit sets `WorkingDirectory` to the copy and runs + ` /packages/discord/src/cli.mjs run %i --supervised --repo + `. Nothing in `ExecStart` or `WorkingDirectory` points into the + checkout. + - `Documentation` may name the checkout's README. It's a link, not code. + - Every other line stays as it is: Restart, RestartPreventExitStatus=3, + the stop signal and timeout, `NoNewPrivileges`, `PATH`. + - Without `--copy`, `render` and `install` behave as today. The install + output then says the unit runs the checkout and names `--copy`. +2. `scripts/discord-service.sh status ` prints the tree the unit + runs. It reads `WorkingDirectory` from `systemctl --user show`, so + drop-ins count, and prints `copy: ` or `checkout: `. +3. `discord.sh check --offline` (and `cli.mjs check --offline`) + runs everything up to and including the token-file mode check: binding, + context files against `--repo`, tool roots, `pi`, journal and STOP. It + makes no REST or gateway call, says so in its last line, and exits 0 + only if all of those pass. Without `--offline`, `check` is unchanged. + `--offline` with `run` is a usage error (exit 4). +4. README "Service unit": the `--copy` install, how a re-pin works (new + copy, `check --offline` from the copy, install, restart), and the + rollback (keep the old unit file, copy it back, `daemon-reload`). It + also says the binding's `context.files` resolve against the copy, so a + file that isn't in the copy refuses at start. TOOLS.md gets the same in + one paragraph. +5. Tests, offline. Use `--dir` on a temp directory and `--no-reload`, and a + fake copy directory, as `test-discord.sh` does today: + - `--copy` renders `ExecStart` and `WorkingDirectory` inside the copy, + with `--repo ` and no checkout path in either. + - A short id, a missing copy, a copy without `cli.mjs`, and a copy + without `pi` each refuse, and no unit file appears. + - Without `--copy` the render is byte-identical to today's. + - `status` prints the copy id from a stubbed `systemctl show`. + - `check --offline` on a fixture binding and a 0600 token file exits 0 + with no network. It refuses on a 0644 token file and on a context + file missing under `--repo`. `run --offline` exits 4. + - Mutants, each recorded in the packet: an `ExecStart` that keeps + `@REPO@`; dropping the `pi` existence check; `--offline` still calling + `getMe`. Each must fail a test. +6. Suites: discord package suite, `scripts/test-discord.sh`, and every + other `scripts/test-*.sh` on the packet gate. + +### Out of scope + +- Installing, enabling, repointing or restarting + `mosaic-discord@shared-signals.service`. That's Mos's step, on Mos's go. + It waits until the SetSpark freeze lifts and stays off the shared + mosaic-stack step 3. +- Running `check` without `--offline` against the live bot. +- `scripts/stack-copy.sh`, including `check` and `COPY_PATHS`. +- The binding file, the token, and SetSpark keys. No seat reads them for + this row. Tests use fixtures only. +- The bus notifier's own use of `packages/discord`, which already runs from + the bus copy. + +### Gate + +Filbert approves on #1608 naming the candidate manifest. Sage reruns the +full gate at the landing target. Mos gets notices before and after the +landing, and the before-notice says it touches `packages/discord`. The +live step is Mos's, after the SetSpark freeze lifts: + +1. `stack-copy.sh copy ` (Sage). +2. `discord.sh check shared-signals --offline` from the copy. +3. Rollback copy of the installed unit. +4. `discord-service.sh install --copy `. +5. Restart on Mos's go. + +Until then, every packages/discord landing is flagged in its +before-notice.