feat(discord): SetSpark record client for the Discord Sage, fixed verbs against setspark-api, connector-verified approvals (#1509)

Row 25, parts 2a and 2b, against the shared-signals contract a5425a2.

Model side: eight fixed verbs in the pi extension (record_list, record_get,
record_create, record_update, resolve_id, open_approval_request,
get_approval_request, create_document), each one HTTP call with arguments
checked before any request. Writes carry an idempotency key
<principal>:<message id>:<call index> and an audit context. The seat key is
read from a 0600 file on every call and never cached, printed or journaled.

Connector side: append-only approval ledger, Approve button and exact
"approve" reply resolved by the connector against the required approvers,
confirmation message posted as button evidence, bind and add_approval through
the service under connector keys, retry of unknown entries on start.

Evidence: node tests 162 pass, scripts/test-discord.sh 63/63. Review by
rev-code-02, round 1 approved (#1509 comment 26467, tree 7872d8c5).

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
2026-09-22 12:59:39 -05:00
co-authored by Claude Fable 5.1
parent 1949ed8d31
commit 43d7574d6a
24 changed files with 2178 additions and 32 deletions
+5
View File
@@ -48,6 +48,7 @@ Gaps found while working go to `docs/plans/DEFERRED.md`, not here.
| 21 | Discord connector: read-only tools for the Discord Sage through a Mosaic pi extension confined to declared roots (MVP iteration 6) | coordinator; reviewer per Q12 | #1509 | approved: rev-code-02 round 2 verdict 26276 (tree 43f0329b); committed locally; live check in #sage-admin with Jason next; Jason ruled R1–R7 2026-09-14 (roots docs/ and agents/sage/, Carmen included) | Sage answers a question from a file under a declared root with the reads in the turn record; a read outside the roots is refused and recorded | `2026-09-14_discord-readonly-tools.md` |
| 23 | Discord connector: writes confined to the `shared-signals` root plus web fetch and search for the Discord Sage (MVP iteration 7) | coordinator; reviewer per Q12 | #1509 | in review: parts 1 and 2 (writes, web fetch and search) built 2026-09-16, suite 52/52, node 128; round 3 pinned for rev-code-02 on #1509 comment 26361 (supersedes rounds 1–2; adds the engine held-prompt fix); part 3 done live 2026-09-17 (SearXNG container on loopback, binding web key, restart; first live turn searched, fetched and wrote vault/Businesses/naming.md); Jason ruled D1–D4 2026-09-16 (SearXNG, Jason and Carmen write, any https host, rev-code-02) | Sage writes a naming shortlist into the repository from #ideas with the write and web calls in the turn record; a write outside the root is refused | `2026-09-16_discord-write-and-web-tools.md` |
| 24 | Discord connector: git verbs (status, commit, pull ff-only, push) for the Discord Sage on the `shared-signals` root, seat identity through the existing credential helper (MVP iteration 8) | coordinator; reviewer per Q12 | #1509 | done 2026-09-18: built (src/git.mjs, bin/git-credential.mjs, extension params, envelope requester, context paragraph, vault protocol via reserve_id and per-write locks); suite 58/58, node 143; rev-code-02 APPROVED round 1 (#1509 comment 26375, tree 82ab962f); D5 mechanism changed: the fleet helper declines github.com, so the package ships its own credential helper reading the 0600 seat token file; binding change and live check next | Sage commits and pushes a decision file from #ideas; GitHub shows Sage as author with a Requested-by trailer; no token in any record | `2026-09-16_discord-git-tools.md` |
| 25 | Discord connector: SetSpark record client for the Discord Sage, fixed verbs against setspark-api, connector-verified approvals (MVP iteration 9) | coordinator; reviewer per Q12 | #1509 | in progress 2026-09-20: Jason's go relayed by the SetSpark coordinator (plan v3.2, shared-signals 55b2515); part 2a built (config, key read per call, HTTP core, approval ledger, Approve button and `approve` reply resolution, bind and approval submission with restart retry); part 2b built against shared-signals a5425a2 (eight model verbs, connector client, button evidence by confirmation message); node 162 pass, suite 63 passed; rev-code-02 APPROVED round 1 (#1509 comment 26467, tree 7872d8c5); binding change and live check next | Sage creates one work item from #sage-admin and the API shows it with revision 1; a proposal is approved by the Approve button and the audit row carries Sage's key id and Jason's Discord id separately; rev-code-02 approves on #1509 | `2026-09-20_discord-setspark-client.md` |
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
@@ -104,3 +105,7 @@ Gate F or when blocked."
- 2026-09-16 — coordinator: row 23 part 3 live (SearXNG container mosaic-searxng on 127.0.0.1:8888, binding web key, restart); Jason's first web turn worked end to end but exposed a live defect: a second message during a turn was sent as a pi follow-up and lost the first answer. Engine now holds it until pi settles. Suite 52/52, node 129; round 3 pinned as #1509 comment 26361; service restarted with the fix. Row 24 rulings D5–D7 recorded.
- 2026-09-17 — coordinator: shared-signals-05 briefed the new id registry and file lock protocol (jetrich/shared-signals 8f0d946); folded into the row 24 brief section 6 (validate before commit, reserve_id tool, per-write clone lock, explicit-path staging). No row changed.
- 2026-09-18 — coordinator: row 23 pushed on Jason's word ("push as well"): refactor 90cb31f5..1685deb4, seven commits, identity jarvis. Row 24 built and under test: four git verbs plus reserve_id, package credential helper (the fleet helper cannot serve github.com), requester in the envelope, explicit-path staging; suite 58/58, node 143; review requested from rev-code-02 on #1509.
- 2026-09-20 — coordinator: SetSpark plan v3 reviewed (Phase 2 rules, Phase 3 verbs); all eight objections from the v2 review adopted; answered "phase 3 ok" with two non-blocking notes. Write target is setspark-api at api.setspark.io; row 25 brief waits on the accepted plan.
- 2026-09-20 — coordinator: plan v3.1 committed on shared-signals main (361380c). Approval flow for row 25: open_approval_request on proposal post; the connector resolves the Approve button or an exact "approve" reply, checks the required-approver list, and submits request id, author id and message id. REF-045 conflict cleared by the REF-047 renumber (9287d49); row 24 live check unblocked. Phase 3 code waits on Jason's go.
- 2026-09-20 — coordinator: Jason's go for phase 3 relayed (plan v3.2, shared-signals 55b2515). Row 25 part 2a built: setspark.mjs (config, key read per call, HTTP core, refusal rendering), approvals.mjs (ledger, reply and button resolution), connector posts the request message with the button, binds it, submits approvals, retries unknown ones on start. Tests 157 node, suite 62. Part 2b waits on stack/api/openapi.json. Contract needs (open without a message, bind, add_approval with request id, author id, message id) sent to the coordinator and adopted, with bound_message_id added on add_approval and a request_stale code; openapi.json being regenerated.
- 2026-09-20 — coordinator: contract committed (shared-signals a5425a2). Row 25 part 2b built: eight model verbs (record_list, record_get, record_create, record_update, resolve_id, open_approval_request, get_approval_request, create_document; get_counters left out), the connector's api client (bind, add_approval with kind button or reply, get), the envelope's author and message ids read by the extension for the write keys. Coordinator's ruling on button evidence: the connector posts a confirmation line and submits its url and text as source_url and statement; a reply is its own evidence. Node 162, suite 63. Next: rev-code-02 review on #1509, then a local commit.