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:
@@ -94,7 +94,9 @@ export function message(overrides = {}) {
|
||||
}
|
||||
|
||||
// Fake REST: scripted outcomes for createMessage, records every call.
|
||||
export function fakeRest({ outcomes = [] } = {}) {
|
||||
// With snowflakes, message ids are 18-digit like Discord's, for code that
|
||||
// validates them (the approvals ledger keys).
|
||||
export function fakeRest({ outcomes = [], snowflakes = false } = {}) {
|
||||
const calls = [];
|
||||
let n = 0;
|
||||
return {
|
||||
@@ -113,7 +115,8 @@ export function fakeRest({ outcomes = [] } = {}) {
|
||||
async createMessage(channelId, body) {
|
||||
calls.push({ channelId, ...body });
|
||||
const o = outcomes.length > 0 ? outcomes.shift() : { ok: true };
|
||||
if (o.ok) return { messageId: o.messageId || `m${++n}`, status: 200 };
|
||||
n += 1;
|
||||
if (o.ok) return { messageId: o.messageId || (snowflakes ? `5000000000000000${String(n).padStart(2, "0")}` : `m${n}`), status: 200 };
|
||||
throw new RestOutcome(o.kind, o.message || `fake ${o.kind}`);
|
||||
},
|
||||
async typing(channelId) {
|
||||
|
||||
Reference in New Issue
Block a user