From b987c3be5b29f76d93bae783ceb8b94f0953076f Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 25 Jun 2026 21:07:35 +0000 Subject: [PATCH] fix(sdk): blocked reason is operator-only, not an API-returned field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit senderkit-app's message read endpoints (GET /api/v1/messages and GET /api/v1/messages/:id) project a lean column set that never includes the detailed abuse `blockedReason` — the anti-phishing/spam signal breakdown is deliberately operator-only so a sender can't learn how detection works. App #211 locks this in (test-guarded across list, get, and the SSE tail). A prior release documented an optional `Message.blockedReason` field as if the API returned it; it never did. Correct the SDK surface to match reality: - types.ts: remove the `Message.blockedReason` field and reword the `status` doc. The `[key: string]: unknown` index signature is unchanged, so this is not a runtime change for callers. - mcp-schemas.ts: drop the MESSAGE_STATUSES comment claiming the trigger is on the message's `blockedReason`. The `blocked` lifecycle status itself is unaffected — still a real returned `status` value, still in MESSAGE_STATUSES and the messages_list status filter. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01GL2Utmx3RszZ1uUQyLEzwu --- .changeset/blocked-reason-not-returned.md | 20 ++++++++++++++++++++ packages/sdk/src/mcp-schemas.ts | 3 ++- packages/sdk/src/types.ts | 5 ++--- 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 .changeset/blocked-reason-not-returned.md diff --git a/.changeset/blocked-reason-not-returned.md b/.changeset/blocked-reason-not-returned.md new file mode 100644 index 0000000..74f801b --- /dev/null +++ b/.changeset/blocked-reason-not-returned.md @@ -0,0 +1,20 @@ +--- +"@senderkit/sdk": patch +"@senderkit/cli": patch +--- + +Correct the `blocked` message documentation: the detailed block reason is operator-only and is not returned by the API. + +A prior release documented an optional `Message.blockedReason` field, but the +app's message read endpoints (`GET /api/v1/messages` and +`GET /api/v1/messages/:id`) never project that column — the detailed +anti-phishing/abuse signal breakdown is deliberately operator-only (senderkit-app +#211), so a sender can't learn how detection works. The field was therefore never +populated on any SDK/MCP/CLI response. + +- **`Message`** — remove the `blockedReason` field (it was never returned) and + reword the `status` doc accordingly. The `[key: string]: unknown` index + signature is unchanged, so this is not a runtime change for any caller. +- The `blocked` lifecycle status is unaffected: it is still a real, returned + `status` value and remains in `MESSAGE_STATUSES` and the + `senderkit_messages_list.status` filter. diff --git a/packages/sdk/src/mcp-schemas.ts b/packages/sdk/src/mcp-schemas.ts index 0dec5e3..7bab4dc 100644 --- a/packages/sdk/src/mcp-schemas.ts +++ b/packages/sdk/src/mcp-schemas.ts @@ -122,7 +122,8 @@ const emailEnvelope = { * The ten message lifecycle statuses (mirrors the app's `messageStatusEnum`). * Bounces normalize to `failed` with the reason on the message timeline. * `blocked` is a terminal state set when the outbound abuse scanner halts a - * send (the human-readable trigger is on the message's `blockedReason`). + * send. The detailed block reason is operator-only and is not returned by the + * message read endpoints. */ export const MESSAGE_STATUSES = [ "scheduled", diff --git a/packages/sdk/src/types.ts b/packages/sdk/src/types.ts index a3345e7..0e4ae0f 100644 --- a/packages/sdk/src/types.ts +++ b/packages/sdk/src/types.ts @@ -195,15 +195,14 @@ export interface Message { publicId: string; /** * Lifecycle status (one of `MESSAGE_STATUSES`). A `blocked` message was - * halted by the outbound abuse scanner; `blockedReason` carries the trigger. + * halted by the outbound abuse scanner. The detailed block reason is + * operator-only and is not returned by the message read endpoints. */ status: string; channel: Channel; templateSlug: string | null; recipient: string; createdAt: string; - /** Human-readable reason a `blocked` message was halted. Absent otherwise. */ - blockedReason?: string | null; [key: string]: unknown; }