feat(discord): binding reload without a restart, and a per-user channel allowlist (#1509)

`reload` validates the binding file and sends SIGHUP to the live owner;
the running connector re-reads it and swaps guildName, channels, users
and limits in place. name, seat, guildId, botUserId, tokenFile, engine
and context are fixed for the life of the process; a change there, an
invalid file or a channel outside the guild refuses the reload and keeps
the old binding. Every attempt is one line in reloads.jsonl. The service
unit maps `systemctl --user reload` to the same signal.

A user entry may carry `channels`, an allowlist of listed channel ids;
absent means every listed channel. Outside the list the message is
dropped as channel-not-for-user; threads count as their parent.

Suite 41/41, 101 node tests. QUEUE rows 19 and 20 opened.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
2026-09-13 18:59:31 -05:00
co-authored by Claude Fable 5.1
parent d9745a4510
commit caaef941e6
16 changed files with 326 additions and 21 deletions
+8 -2
View File
@@ -155,6 +155,7 @@ scripts/discord.sh run <binding> [--supervised]
scripts/discord.sh stop <binding>
scripts/discord.sh unlock <binding>
scripts/discord.sh recover <binding>
scripts/discord.sh reload <binding>
scripts/discord-service.sh render | install [--dir DIR] [--no-reload] | uninstall [--dir DIR] [--no-reload] | status <binding>
```
@@ -172,10 +173,15 @@ parsed. `run` refuses a stale lock rather than reclaiming it, and releases a
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.
is gone and removes only the `STOP` it wrote for that. `reload` validates
the binding file and sends SIGHUP to the running connector, which applies
`guildName`, `channels`, `users` and `limits` in place and refuses anything
else, keeping the old binding; attempts are journaled in `reloads.jsonl`. A
user entry may carry `channels`, an allowlist of listed channel ids.
`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
failure, exit 3 never retried, SIGTERM on `systemctl --user stop`, SIGHUP on
`systemctl --user reload`). 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`.