From 2333741267a11cf0680c820bfc1fd955e354fad1 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 21 Jun 2026 21:07:01 +0000 Subject: [PATCH] fix(sdk): stop advertising operator-only blockedReason on Message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The customer-facing API (messages.list/get + the live tail) never returns the detailed abuse-scan trigger — it is operator-only and senderkit-app #211 made that explicit and permanent. Drop the optional `Message.blockedReason` field and the MCP status-description reference to it. A `blocked` message still surfaces a generic "blocked" entry on its timeline. The `Message` index signature keeps `.blockedReason` readable as `unknown`, so this is non-breaking. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01AegJQ2qjCaw8iJjaAFni2k --- .changeset/quiet-message-block-reason.md | 10 ++++++++++ packages/sdk/src/mcp-schemas.ts | 3 ++- packages/sdk/src/types.ts | 6 +++--- 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 .changeset/quiet-message-block-reason.md diff --git a/.changeset/quiet-message-block-reason.md b/.changeset/quiet-message-block-reason.md new file mode 100644 index 0000000..dd49c8e --- /dev/null +++ b/.changeset/quiet-message-block-reason.md @@ -0,0 +1,10 @@ +--- +"@senderkit/sdk": patch +--- + +Stop advertising `Message.blockedReason` on the message read type and in the +MCP status description. The customer-facing API (`messages.list` / `messages.get`, +plus the live tail) never returns the detailed abuse-scan trigger — it is +operator-only — so the optional field was always absent on the wire. A `blocked` +message still surfaces a generic "blocked" entry on its `timeline`. The `Message` +type keeps its `[key: string]: unknown` index signature, so this is non-breaking. diff --git a/packages/sdk/src/mcp-schemas.ts b/packages/sdk/src/mcp-schemas.ts index 0dec5e3..3d4adee 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; a generic "blocked" entry is recorded on the message timeline. The + * detailed detection trigger is operator-only and not returned by the API. */ export const MESSAGE_STATUSES = [ "scheduled", diff --git a/packages/sdk/src/types.ts b/packages/sdk/src/types.ts index a3345e7..bcf50e1 100644 --- a/packages/sdk/src/types.ts +++ b/packages/sdk/src/types.ts @@ -195,15 +195,15 @@ 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; a generic "blocked" entry appears on + * the message `timeline`. The detailed detection breakdown is operator-only + * and is never returned by the customer-facing API. */ 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; }