feat(discord): systemd user service with a supervised run; brakes exit 3 and are never retried (#1509)
QUEUE row 17, MVP iteration 2. scripts/discord-service.sh renders and installs mosaic-discord@<binding> from packages/discord/systemd/. The unit's main process is `run --supervised`, which applies the new recover policy first: a lock whose owner is gone is cleared and only the STOP written for that is removed; an operator STOP or a held binding refuses with exit 3, which RestartPreventExitStatus never retries. `recover` is also a CLI verb. First cut used ExecStartPre and looped live, since systemd honours the never-retry status only from the main process; replaced and re-verified before any message traffic. Suite 40/40, 95 node tests. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
@@ -251,3 +251,4 @@ are never rewritten or removed; corrections are new entries.
|
||||
- 2026-09-13 UTC — coordinator (Claude) — Discord connector pilot closed (#1509, QUEUE row 14): Jason ruled Gate H passed, replies read as Sage. DISCORD-USER.md wording corrected (unlisted senders are dropped silently, not refused with a reply). Records committed and pushed on Jason's authorization; connector left running for MVP iteration.
|
||||
- 2026-09-13 UTC — coordinator (Claude) — Discord read receipt (#1509, QUEUE row 15): eyes reaction on every admitted message at admission, best effort, outcome in the turn record; REST `react` plus connector and REST tests. `scripts/test-discord.sh` 28/28 (90 node tests). Committed; connector restarted to pick it up. Push on Jason's say-so.
|
||||
- 2026-09-13 UTC — coordinator (Claude) — Discord read receipt live check (#1509, QUEUE row 15): reaction confirmed on a live message at 19:21 UTC, turn record receipt ok true, private evidence receipt written, row 15 done. Committed; push on Jason's say-so.
|
||||
- 2026-09-13 UTC — coordinator (Claude) — Discord service unit (#1509, QUEUE row 17): `run --supervised` and `recover`, exit 3 for brakes, `scripts/discord-service.sh`, systemd user unit; suite 40/40 (95 node tests); Sage seat migrated from tmux to `mosaic-discord@shared-signals`, kill and brake checks passed live. Committed; push on Jason's say-so.
|
||||
|
||||
+13
-4
@@ -151,9 +151,11 @@ usage. Details and the record's fields: `packages/seat/README.md`.
|
||||
|
||||
```bash
|
||||
scripts/discord.sh check <binding>
|
||||
scripts/discord.sh run <binding>
|
||||
scripts/discord.sh run <binding> [--supervised]
|
||||
scripts/discord.sh stop <binding>
|
||||
scripts/discord.sh unlock <binding>
|
||||
scripts/discord.sh recover <binding>
|
||||
scripts/discord-service.sh render | install [--dir DIR] [--no-reload] | uninstall [--dir DIR] [--no-reload] | status <binding>
|
||||
```
|
||||
|
||||
One seat's conversation reachable from listed channels of one Discord
|
||||
@@ -167,12 +169,19 @@ reconciled. `stop` writes `STOP` and signals the running process. `unlock`
|
||||
writes `STOP` and removes a `run.lock` left by a dead process; it refuses
|
||||
while the owner is alive with an unverifiable identity or its record cannot be
|
||||
parsed. `run` refuses a stale lock rather than reclaiming it, and releases a
|
||||
claim that meets `STOP`. Records
|
||||
claim that meets `STOP`. `recover` is the supervised pre-start, and
|
||||
`run --supervised` does it first in the same process: it refuses (exit 3)
|
||||
while `STOP` is present or the binding is held, clears a lock whose owner
|
||||
is gone and removes only the `STOP` it wrote for that.
|
||||
`scripts/discord-service.sh install` renders and writes the systemd user
|
||||
unit `[email protected]` (one instance per binding, restart on
|
||||
failure, exit 3 never retried, SIGTERM on `systemctl --user stop`). Records
|
||||
under `<dataRoot>/discord/<binding>/`: `inbox.jsonl`, `outbox.jsonl`,
|
||||
`drops.jsonl`, `admissions.jsonl`, `notices.jsonl`, write-once `turns/<id>.json`. Suite:
|
||||
`scripts/test-discord.sh`.
|
||||
Exit codes: 0 ok, 1 operation failed, 2 invalid data or configuration, 4
|
||||
usage. Details: `packages/discord/README.md`.
|
||||
Exit codes: 0 ok, 1 operation failed, 2 invalid data or configuration, 3
|
||||
refused by a brake (a supervisor must not retry), 4 usage. Details:
|
||||
`packages/discord/README.md`.
|
||||
|
||||
## Tools (host-side)
|
||||
|
||||
|
||||
@@ -421,3 +421,17 @@ Recorded here because they refine a ruling or fill a gap the rulings left.
|
||||
is logged and recorded in the turn record as `receipt.ok: false` and never
|
||||
fails the turn. Needs the Add Reactions permission on the bot role.
|
||||
- Live check 2026-09-13 19:21 UTC: reaction seen by Jason ("test is successful") and recorded in the turn record. Iteration 1 closed.
|
||||
- Service unit (iteration 2, Jason: "proceed as suggested", 2026-09-13).
|
||||
`scripts/discord-service.sh` renders and installs a systemd user unit,
|
||||
`mosaic-discord@<binding>`, from a template in `packages/discord/systemd/`.
|
||||
The new `recover` policy runs first inside `run --supervised`, the unit's
|
||||
main process: it clears a lock whose owner is gone and removes only the
|
||||
STOP it wrote for that; every operator STOP and every held binding
|
||||
refuses with the new exit code 3, which the unit never retries. First
|
||||
cut used an `ExecStartPre`; systemd only honours the never-retry status
|
||||
from the main process, so that looped, and the live check caught it. `systemctl --user stop` is the soft stop (SIGTERM, no STOP,
|
||||
restartable); `scripts/discord.sh stop` stays the brake. This ends the
|
||||
hand-removal of STOP after every rerun that step 3 of the pilot showed.
|
||||
Not done: a binding reload without a restart (a ceiling or channel change
|
||||
still needs stop and start). Next: the control board row.
|
||||
- Live check 2026-09-13 19:35 to 19:40 UTC: Sage seat migrated to the unit; SIGKILL recovered in 16 s with the dead lock cleared; `discord.sh stop` held (start exits 3, no restart); released and READY. Iteration 2 closed.
|
||||
|
||||
@@ -365,3 +365,4 @@ git history + Gitea issues.
|
||||
- 2026-09-03 — M19 correction: auth ownership moved to the data root (#48, owner direction — the stack never writes to default harness config locations; ROADMAP standing decision); auth.sh config-driven, accounts at <dataRoot>/auth, 0600 enforced; test-auth 13 → 15
|
||||
- 2026-09-03 — harness/provider/auth registry specification drafted (#49): agent.json harness declaration, central provider/account/settings registries, runtime seat selection, mechanical per-harness materialization, centralized OAuth refresh, Ollama endpoints, CLI contract; implementation blocked pending ten-gate review
|
||||
- 2026-09-13 — Discord connector pilot for the Sage seat (#1509; QUEUE rows 14–15; brief `2026-09-13_discord-connector-pilot.md`): nine review rounds with rev-code-02, live pilot steps 1–8 with private receipts, Gate H passed (Jason: the replies read as Sage). Commits 786e379c, 788515dc (pushed). MVP iteration 1, eyes reaction as a read receipt, committed 93d6b624 (local); live check pending. Connector stays up in tmux `discord-sage`; binding and token live outside the repo.
|
||||
- 2026-09-13 — Discord connector iteration 2 (#1509, QUEUE row 17): systemd user service `mosaic-discord@<binding>` with a supervised run that clears a dead lock and never retries a brake (exit 3). Sage seat now runs under systemd, not tmux. Next: control board row.
|
||||
|
||||
@@ -41,6 +41,7 @@ Gaps found while working go to `docs/plans/DEFERRED.md`, not here.
|
||||
| 13 | Ledger "queue" section: issue/row/seat drift printed with the weekly number | darkwing; filbert reviews | #1508 | required; after row 9 | first run Monday 2026-09-21, zero violations or every one moved same day | `2026-09-13_queue-as-data.md`, Piece E |
|
||||
| 14 | Discord connector pilot: Sage answers in Shared Signals (chat only, no tools, no repo writes) | coordinator; Filbert or orch-01 seat reviews | #1509 | done: rev-code-02 APPROVE 26170 (round 9), committed 786e379c; pilot steps 1-8 done with private receipts, Gate H passed (Jason, 2026-09-13: replies read as Sage); connector left running for MVP iteration | H: offline suite green, eight-step live pilot with private receipts, then Jason says the reply reads as Sage | `2026-09-13_discord-connector-pilot.md` |
|
||||
| 15 | Discord connector: eyes reaction on every admitted message as a read receipt (MVP iteration 1) | coordinator | #1509 | done: committed 93d6b624, live check passed 19:21 UTC (turn record receipt ok, Jason: test is successful), receipt `mvp1-read-receipt-20260913T192158Z.json` in the private evidence dir; `rest.react` best effort, reaction placed at admission before the engine runs, outcome in the turn record, no reaction on drops or refusals; `scripts/test-discord.sh` 28/28 (90 node tests) | Jason sees the reaction on a live message | `2026-09-13_discord-connector-pilot.md` section 11 |
|
||||
| 17 | Discord connector: systemd user service with a supervised pre-start (`recover`, exit 3 never retried) (MVP iteration 2) | coordinator | #1509 | done: `scripts/test-discord.sh` 40/40 (95 node tests); Sage seat migrated 19:35 UTC, SIGKILL recovered in 16 s with the dead lock cleared, brake held (exit 3, no restart), released and READY; receipt `mvp2-service-unit-*.json` in the private evidence dir. First cut (ExecStartPre) looped and was replaced by `run --supervised` before any traffic | the Sage connector runs under `mosaic-discord@shared-signals`, survives a kill with a clean restart, and stays down behind `discord.sh stop` | `2026-09-13_discord-connector-pilot.md` section 11 |
|
||||
|
||||
Start message for row 6, sent from the board to darkwing:
|
||||
"Read docs/plans/QUEUE.md, then the plan page section "Piece 5: darkwing on
|
||||
@@ -79,3 +80,6 @@ Gate F or when blocked."
|
||||
- 2026-09-13 — coordinator: row 15 added and done (Discord read receipt, Jason's request after the pilot); committed after suites green. No other row changed.
|
||||
- 2026-09-13 — coordinator: row 15 moved to in verification; committed 93d6b624, connector running the new code, waiting for Jason's live message to show the reaction. No other row changed.
|
||||
- 2026-09-13 — coordinator: row 15 done; live reaction confirmed by Jason and by the turn record. No other row changed.
|
||||
- 2026-09-13 — coordinator: rows 14–15 pushed on Jason's authorization (788515dc..dc5902aa to origin/refactor). No other row changed.
|
||||
- 2026-09-13 — coordinator: row 17 added, in verification (Discord service unit, iteration 2 on Jason's "proceed as suggested"). No other row changed.
|
||||
- 2026-09-13 — coordinator: row 17 done; the Sage connector runs under systemd, kill and brake checks passed live. No other row changed.
|
||||
|
||||
Reference in New Issue
Block a user