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 <[email protected]>
This commit is contained in:
2026-10-14 11:13:43 -05:00
co-authored by Claude Opus 5.5
parent 5b86abe47d
commit d7e1d5ed5d
@@ -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
`[email protected]` 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/[email protected]` 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/<sha>`), 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, `<repo>/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/[email protected]`
- `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-<row>/`
`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
`<node> <copy>/packages/discord/src/cli.mjs run %i --supervised --repo
<copy>`. 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 <binding>` prints the tree the unit
runs. It reads `WorkingDirectory` from `systemctl --user show`, so
drop-ins count, and prints `copy: <id>` or `checkout: <path>`.
3. `discord.sh check <binding> --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 <copy>` 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
`[email protected]`. 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 <sha>` (Sage).
2. `discord.sh check shared-signals --offline` from the copy.
3. Rollback copy of the installed unit.
4. `discord-service.sh install --copy <sha>`.
5. Restart on Mos's go.
Until then, every packages/discord landing is flagged in its
before-notice.