diff --git a/BUILD-LOG.md b/BUILD-LOG.md index 8bb3abc7..41bf8198 100644 --- a/BUILD-LOG.md +++ b/BUILD-LOG.md @@ -2410,3 +2410,36 @@ first start behind a brake, before any message traffic; replaced by the supervised run as the main process and re-verified: SIGKILL recovered in 16 s with the dead lock cleared, brake held with no restart, released and READY. The Sage seat now runs under the unit; the tmux session is gone. + +## 2026-09-13 — Discord binding reload and per-user channels (#1509, QUEUE rows 19–20) + +Before: the binding was read once at start, so a ceiling, channel or user +change needed brake, STOP removal, reset and start; every listed user could +post in every listed channel. After: `scripts/discord.sh reload ` +validates the file, then sends SIGHUP to the live owner in `run.lock`; the +connector re-reads it and swaps `guildName`, `channels`, `users` and +`limits` in place, reading a channel that is new to the binding over REST +first. `name`, `seat`, `guildId`, `botUserId`, `tokenFile`, `engine` +and `context` are fixed for the life of the process (engine and prompt are +launched once, the token read once); a change there, an invalid file or a +channel outside the guild refuses the reload and keeps the old binding. Each +attempt is one line in `reloads.jsonl`. The unit gained `ExecReload`, so +`systemctl --user reload` does the same. A user entry may carry +`channels`, an allowlist of listed channel ids; outside it the message is +dropped as `channel-not-for-user`, threads counting as their parent. +Allowlist over deny list is a recorded choice: explicit lists are the +connector's policy and a new channel must not widen anyone's reach by +default; the cost is that a channel added later needs adding to Carmen's +list too. Tests: schema for the allowlist, `reloadDiff` per fixed key, the +authorization rows, connector reload (new user, removed channel, lower +ceiling, fixed key refused), CLI exit codes, unit render. Suite 41/41, 101 +node tests. + +Live, 00:03 UTC: unit reinstalled and soft-restarted (the old process had +no SIGHUP handler), READY on the new code. Carmen enrolled by a binding +edit plus `reload`: applied, users +1, no restart. An unknown key was +refused by the CLI with exit 2 and nothing signaled; a valid file with the +seat changed was refused by the process and the binding stayed; the +revert applied with no differences; `systemctl --user reload` applied. +Carmen's own first message is the remaining check. Her id is only in the +binding file. diff --git a/docs/SESSIONS.md b/docs/SESSIONS.md index ef6edbf5..d7349e9b 100644 --- a/docs/SESSIONS.md +++ b/docs/SESSIONS.md @@ -252,3 +252,4 @@ are never rewritten or removed; corrections are new entries. - 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. +- 2026-09-13 UTC — coordinator (Claude) — Discord binding reload and per-user channels (#1509, QUEUE rows 19–20): `reload`/SIGHUP with fixed keys refused, `reloads.jsonl`, user `channels` allowlist; suite 41/41, 101 node tests; Carmen enrolled live by reload at 00:03 UTC, her first message pending; row 18 assigned to darkwing by Jason. diff --git a/docs/plans/2026-09-13_discord-connector-pilot.md b/docs/plans/2026-09-13_discord-connector-pilot.md index 59644597..0bef1b88 100644 --- a/docs/plans/2026-09-13_discord-connector-pilot.md +++ b/docs/plans/2026-09-13_discord-connector-pilot.md @@ -461,6 +461,7 @@ Recorded here because they refine a ruling or fill a gap the rulings left. is added later, Carmen's list needs the id too. Enrollment is a binding edit plus `reload`, which doubles as the live check for iteration 4. Carmen's id lives only in the binding file, never in the repository. +- Live check 2026-09-13 00:03 UTC (iterations 4 and 5): unit reinstalled with `ExecReload` and soft-restarted, READY on the new code. Carmen added to the binding with every listed channel except #sage-admin and applied by `reload` (users +1, no restart). An unknown key was refused by the CLI (exit 2, nothing signaled); a valid file with `seat` changed was refused in the process and the binding stayed; the revert applied with no differences; `systemctl --user reload` applied. Receipt `mvp4-5-reload-carmen-*.json` and a 0600 backup of the binding before the edit in the private evidence dir. Remaining: Carmen's first message in #general (reply, eyes reaction) and one in #sage-admin (silence, `channel-not-for-user` drop line). - Control board row (iteration 3, briefed, not started). Blocked on ownership, not on design: `packages/control-board` is darkwing's (#1503, #1505, brief `2026-09-12_control-board-mvp.md`), and the row cannot be diff --git a/docs/plans/CURRENT.md b/docs/plans/CURRENT.md index 887b6aea..bdcc2e38 100644 --- a/docs/plans/CURRENT.md +++ b/docs/plans/CURRENT.md @@ -366,3 +366,4 @@ git history + Gitea issues. - 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@` 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. +- 2026-09-13 — Discord connector iterations 4 and 5 (#1509, QUEUE rows 19–20): `reload` verb and `systemctl --user reload` apply channels, users, limits and guildName to the running connector, fixed keys refused, attempts journaled in `reloads.jsonl`; per-user channel allowlist; Carmen enrolled live by a reload at 00:03 UTC (all listed rooms except #sage-admin). Suite 41/41, 101 node tests. Commit caaef941 plus records. Row 18 (board row) is darkwing's by Jason's ruling. diff --git a/docs/plans/QUEUE.md b/docs/plans/QUEUE.md index c69ff4d3..a7477fab 100644 --- a/docs/plans/QUEUE.md +++ b/docs/plans/QUEUE.md @@ -43,8 +43,8 @@ Gaps found while working go to `docs/plans/DEFERRED.md`, not here. | 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, operator-verified by Jason 2026-09-13 (all four steps): `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 | | 18 | Control board row for the Discord connector (MVP iteration 3): discovery from binding files, liveness from run.lock, reply refused | darkwing (Jason's ruling 2026-09-13); coordinator answers connector-side questions | #1509 | briefed; assigned to darkwing, not started | a Sage (discord) row on the board shows live, offline and braked correctly, and reply from the board is refused | `2026-09-13_discord-connector-pilot.md` section 11 | -| 19 | Discord connector: binding reload without a restart (`reload` verb, SIGHUP, `systemctl --user reload`); channels, users, limits and guildName apply in place, identity, engine and context stay fixed, an invalid file is refused and the old binding kept (MVP iteration 4) | coordinator | #1509 | in progress | edit the binding, run `scripts/discord.sh reload shared-signals`, the change applies with no restart, a broken edit is refused and journaled | `2026-09-13_discord-connector-pilot.md` section 11 | -| 20 | Discord connector: per-user channel allowlist in the binding and Carmen enrolled (all listed rooms except #sage-admin) (MVP iteration 5) | coordinator | #1509 | briefed, after row 19 | Carmen gets a reply in #general and silence in #sage-admin; Jason unchanged | `2026-09-13_discord-connector-pilot.md` section 11 | +| 19 | Discord connector: binding reload without a restart (`reload` verb, SIGHUP, `systemctl --user reload`); channels, users, limits and guildName apply in place, identity, engine and context stay fixed, an invalid file is refused and the old binding kept (MVP iteration 4) | coordinator | #1509 | done: caaef941; live 00:03 UTC: reload applied Carmen's entry with no restart, unknown key refused by the CLI (exit 2), fixed key refused in the process with the binding kept, `systemctl --user reload` applied; suite 41/41 (101 node tests); receipt `mvp4-5-reload-carmen-*.json` | edit the binding, run `scripts/discord.sh reload shared-signals`, the change applies with no restart, a broken edit is refused and journaled | `2026-09-13_discord-connector-pilot.md` section 11 | +| 20 | Discord connector: per-user channel allowlist in the binding and Carmen enrolled (all listed rooms except #sage-admin) (MVP iteration 5) | coordinator | #1509 | done: caaef941 (`users[].channels` allowlist, `channel-not-for-user` drop); Carmen enrolled live by reload 00:03 UTC; her first message is the remaining check | Carmen gets a reply in #general and silence in #sage-admin; Jason unchanged | `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 @@ -91,3 +91,4 @@ Gate F or when blocked." - 2026-09-13 — coordinator: row 18 assigned to darkwing by Jason ("darkwing should build the board row"). Coordinator no longer holds a Discord row in progress. No other row changed. - 2026-09-13 — coordinator: row 17 operator check passed (Jason: all tests successfully verified, 21:29 UTC). No other row changed. - 2026-09-13 — coordinator: rows 19 (binding reload) and 20 (per-user channels, Carmen) added on Jason's "proceed in order"; row 19 in progress. No other row changed. +- 2026-09-13 — coordinator: rows 19–20 done (caaef941, live reload 00:03 UTC, Carmen enrolled); Carmen's first message pending as the operator check. No other row changed.