feat(broker): record daemon idempotency fields on message_queue
Additive plumbing for v0.9.0 daemon spec §4.2/§4.4. Adds two nullable
columns to mesh.message_queue — client_message_id (caller-supplied) and
request_fingerprint (canonical sha256 of the send shape) — and threads
them through the broker:
- handleSend reads them off the wire envelope when present
- queueMessage persists them on the row
- drainForMember projects them onto the push so receiving daemons
can dedupe their local inbox by client_message_id
Columns stay nullable so legacy traffic (launch CLI, dashboard chat)
continues to flow uninterrupted. Sprint 7 (broker hardening) will add
the partial unique index and the client_message_dedupe atomic-accept
table once we're ready to enforce dedupe broker-side.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -359,6 +359,14 @@ export const messageQueue = meshSchema.table("message_queue", {
|
||||
createdAt: timestamp().defaultNow().notNull(),
|
||||
deliveredAt: timestamp(),
|
||||
expiresAt: timestamp(),
|
||||
// v0.9.0 daemon: caller-supplied idempotency id (spec §4.2). Nullable
|
||||
// for legacy traffic. Sprint 7+ promotes it to a partial-unique index
|
||||
// and adds the mesh.client_message_dedupe table for atomic accept.
|
||||
clientMessageId: text("client_message_id"),
|
||||
// v0.9.0 daemon: 32-byte sha256 of the canonical request shape (spec
|
||||
// §4.4), hex-encoded. Nullable for legacy traffic. Brokers that want
|
||||
// to enforce idempotency on retries will read this column.
|
||||
requestFingerprint: text("request_fingerprint"),
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -1658,10 +1666,10 @@ export type InsertMeshNotification = typeof meshNotification.$inferInsert;
|
||||
* ──────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
export const apiKeyCapabilityEnum = meshSchema.enum("api_key_capability", [
|
||||
"send", // POST /messages
|
||||
"read", // GET /messages, /peers, /state
|
||||
"send", // POST /messages
|
||||
"read", // GET /messages, /peers, /state
|
||||
"state_write", // POST /state
|
||||
"admin", // issue/revoke other keys, delete topics, etc.
|
||||
"admin", // issue/revoke other keys, delete topics, etc.
|
||||
]);
|
||||
|
||||
export const meshApiKey = meshSchema.table(
|
||||
@@ -1679,7 +1687,7 @@ export const meshApiKey = meshSchema.table(
|
||||
secretPrefix: text().notNull(),
|
||||
/** Granted capabilities. Empty = no permissions; key is a stub. */
|
||||
capabilities: jsonb()
|
||||
.$type<Array<"send" | "read" | "state_write" | "admin">>()
|
||||
.$type<("send" | "read" | "state_write" | "admin")[]>()
|
||||
.notNull()
|
||||
.default([]),
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user