Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,3 @@ Use the `sent` skill for shared Sent terminology and routing.
| `scripts/analyze_mdr_funnel.py` | Validation script | Reads an MDR export (CSV or JSON), groups channel × direction outcomes, separates delivery transitions from engagement, and retains malformed/unknown rows. Run from the skill root: `python scripts/analyze_mdr_funnel.py path/to/mdr.csv` (use `--threshold N`, `--show-errors`, or `--format json`). Exit `0` means no observed transition breach, `2` means bad input/no usable cohort, and `3` means an observed breach. JSON uses `null` where a denominator is unavailable; text uses `N/A`. |
| `scripts/fixtures/good.json` | Fixture | Synthetic healthy-funnel MDR export. |
| `scripts/fixtures/bad.json` | Fixture | Synthetic MDR export with deliberate >50% SENT→DELIVERED drop. |

## Unverified claims to confirm or remove

- Any fixed cohort-size threshold such as “1,000 messages minimum” is an analyst heuristic, not a documented Sent API rule.
- External provider identifiers such as carrier message IDs, WhatsApp `wamid`, and RCS message IDs are not in the v3 docs as join keys; use Sent `message_id` and treat provider IDs as escalation-only context.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@
Supporting reference for `messaging-performance-analyzer`. "MDR" is the human term for Sent's per-message status stream; the v3 surfaces are `GET /v3/messages/{id}` and `GET /v3/messages/{id}/activities`. The codes below are Sent's own normalized catalog as documented at docs.sent.dm — not raw provider codes.

Authoritative upstream sources (for the downstream provider codes that may appear in `error.details` after Sent normalization):

- WhatsApp: [Cloud API Error Codes](https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes)
- SMS: TCR + carrier-specific reject reasons (T-Mobile, AT&T, Verizon each publish their own list)
- RCS: [RBM API errors](https://developers.google.com/business-communications/rcs-business-messaging/reference/rest)

## Table of contents

- [Message status lifecycle](#message-status-lifecycle)
- [Synchronous errors](#synchronous-errors-http-response-body)
- [Send-time per-message errors](#send-time-per-message-errors)
- [Webhook payload shape](#webhook-payload-shape)
- [Webhook event lifecycle](#webhook-event-lifecycle)
- [Provider-level codes](#provider-level-codes-referential-not-sent-normalized)
- [Counting rules](#counting-rules)
- [Source notes](#source-notes)

## Message status lifecycle

Sent normalizes channels into a shared delivery state machine. The latest status per `message_id` determines its current outcome, while an activity history supplies the evidence for transition counts. Do not backfill earlier stages from a latest-only record.
Expand Down Expand Up @@ -214,3 +226,10 @@ Carriers don't share an enum; the categories you actually need to triage on:
- **Stop SMS at `DELIVERED`.** Calculate `READ` engagement only for WhatsApp and RCS.
- **Separate channel fan-out.** `POST /v3/messages` with `"channel": ["sms","whatsapp","rcs"]` creates one message per channel; each has its own `message_id` and its own lifecycle. Don't double-count at the recipient level unless the user explicitly asks for recipient-level rollup.
- **Honor a minimum cohort size** before drawing conclusions about small rate shifts. A working heuristic is ≥1,000 messages per cohort; below that, noise dominates. This is an analyst rule of thumb, not a Sent API rule.

## Source notes

- Sent lifecycle, error-envelope, template, message-activity, and webhook claims were last checked on 2026-08-09 against the [Sent v3 OpenAPI](https://api.sent.dm/swagger/v3/swagger.json), [message status guide](https://docs.sent.dm/llms/start/guides/message-status-tracking.txt), and [webhook event reference](https://docs.sent.dm/llms/start/webhooks/event-types.txt).
- Provider-code tables are referential aids sourced from the linked provider documentation; they are not Sent-normalized enums. SMS carriers do not publish one shared reject enum.
- The 1,000-message cohort threshold is an analyst heuristic, not a documented Sent API requirement.
- Provider identifiers such as carrier message IDs, WhatsApp `wamid`, and RCS message IDs are not documented Sent v3 join keys. Use Sent `message_id` and treat provider IDs as escalation context.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Supporting reference for `messaging-performance-analyzer`. The SKILL.md tells yo

For the full catalog of codes referenced below, see `references/mdr-status-codes.md`.

## Table of contents

- [Symptom-driven diagnosis](#symptom-driven-diagnosis)
- [Cross-skill handoff matrix](#cross-skill-handoff-matrix)
- [When to escalate to Sent support](#when-to-escalate-to-sent-support)
- [Diagnostic loop](#diagnostic-loop)
- [Source notes](#source-notes)

## Symptom-driven diagnosis

Every entry follows the same pattern: **observable symptom -> where the failure code lives -> what to check first -> handoff if rooted elsewhere.**
Expand Down Expand Up @@ -137,3 +145,9 @@ Repeat until the symptom is explained or scoped:
7. If the symptom is missing customer-side data: prove webhook health via `is_active`, `consecutive_failures`, and `/v3/webhooks/{id}/events` before blaming delivery.
8. Hand off via the matrix above, or escalate to Sent support with the required evidence.
9. Quantify the diagnosis — never "looks better now" without a recomputed funnel.

## Source notes

- This playbook is operational guidance synthesized from the [Sent v3 OpenAPI](https://api.sent.dm/swagger/v3/swagger.json), [message status guide](https://docs.sent.dm/llms/start/guides/message-status-tracking.txt), [webhook event reference](https://docs.sent.dm/llms/start/webhooks/event-types.txt), and [channel-routing reference](https://docs.sent.dm/llms/reference/channel-routing.txt), last checked on 2026-08-09.
- Dominance thresholds, cohort-size guidance, comparison windows, and escalation timing are analyst heuristics unless a cited Sent source states otherwise.
- Re-check the repository documentation source catalog before relying on exact endpoints, enums, or limits after its `last_verified` date.
5 changes: 0 additions & 5 deletions packages/sent/skills/messaging-performance-analyzer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,3 @@ Use the `sent` skill for shared Sent terminology and routing.
| `scripts/analyze_mdr_funnel.py` | Validation script | Reads an MDR export (CSV or JSON), groups channel × direction outcomes, separates delivery transitions from engagement, and retains malformed/unknown rows. Run from the skill root: `python scripts/analyze_mdr_funnel.py path/to/mdr.csv` (use `--threshold N`, `--show-errors`, or `--format json`). Exit `0` means no observed transition breach, `2` means bad input/no usable cohort, and `3` means an observed breach. JSON uses `null` where a denominator is unavailable; text uses `N/A`. |
| `scripts/fixtures/good.json` | Fixture | Synthetic healthy-funnel MDR export. |
| `scripts/fixtures/bad.json` | Fixture | Synthetic MDR export with deliberate >50% SENT→DELIVERED drop. |

## Unverified claims to confirm or remove

- Any fixed cohort-size threshold such as “1,000 messages minimum” is an analyst heuristic, not a documented Sent API rule.
- External provider identifiers such as carrier message IDs, WhatsApp `wamid`, and RCS message IDs are not in the v3 docs as join keys; use Sent `message_id` and treat provider IDs as escalation-only context.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@
Supporting reference for `messaging-performance-analyzer`. "MDR" is the human term for Sent's per-message status stream; the v3 surfaces are `GET /v3/messages/{id}` and `GET /v3/messages/{id}/activities`. The codes below are Sent's own normalized catalog as documented at docs.sent.dm — not raw provider codes.

Authoritative upstream sources (for the downstream provider codes that may appear in `error.details` after Sent normalization):

- WhatsApp: [Cloud API Error Codes](https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes)
- SMS: TCR + carrier-specific reject reasons (T-Mobile, AT&T, Verizon each publish their own list)
- RCS: [RBM API errors](https://developers.google.com/business-communications/rcs-business-messaging/reference/rest)

## Table of contents

- [Message status lifecycle](#message-status-lifecycle)
- [Synchronous errors](#synchronous-errors-http-response-body)
- [Send-time per-message errors](#send-time-per-message-errors)
- [Webhook payload shape](#webhook-payload-shape)
- [Webhook event lifecycle](#webhook-event-lifecycle)
- [Provider-level codes](#provider-level-codes-referential-not-sent-normalized)
- [Counting rules](#counting-rules)
- [Source notes](#source-notes)

## Message status lifecycle

Sent normalizes channels into a shared delivery state machine. The latest status per `message_id` determines its current outcome, while an activity history supplies the evidence for transition counts. Do not backfill earlier stages from a latest-only record.
Expand Down Expand Up @@ -214,3 +226,10 @@ Carriers don't share an enum; the categories you actually need to triage on:
- **Stop SMS at `DELIVERED`.** Calculate `READ` engagement only for WhatsApp and RCS.
- **Separate channel fan-out.** `POST /v3/messages` with `"channel": ["sms","whatsapp","rcs"]` creates one message per channel; each has its own `message_id` and its own lifecycle. Don't double-count at the recipient level unless the user explicitly asks for recipient-level rollup.
- **Honor a minimum cohort size** before drawing conclusions about small rate shifts. A working heuristic is ≥1,000 messages per cohort; below that, noise dominates. This is an analyst rule of thumb, not a Sent API rule.

## Source notes

- Sent lifecycle, error-envelope, template, message-activity, and webhook claims were last checked on 2026-08-09 against the [Sent v3 OpenAPI](https://api.sent.dm/swagger/v3/swagger.json), [message status guide](https://docs.sent.dm/llms/start/guides/message-status-tracking.txt), and [webhook event reference](https://docs.sent.dm/llms/start/webhooks/event-types.txt).
- Provider-code tables are referential aids sourced from the linked provider documentation; they are not Sent-normalized enums. SMS carriers do not publish one shared reject enum.
- The 1,000-message cohort threshold is an analyst heuristic, not a documented Sent API requirement.
- Provider identifiers such as carrier message IDs, WhatsApp `wamid`, and RCS message IDs are not documented Sent v3 join keys. Use Sent `message_id` and treat provider IDs as escalation context.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Supporting reference for `messaging-performance-analyzer`. The SKILL.md tells yo

For the full catalog of codes referenced below, see `references/mdr-status-codes.md`.

## Table of contents

- [Symptom-driven diagnosis](#symptom-driven-diagnosis)
- [Cross-skill handoff matrix](#cross-skill-handoff-matrix)
- [When to escalate to Sent support](#when-to-escalate-to-sent-support)
- [Diagnostic loop](#diagnostic-loop)
- [Source notes](#source-notes)

## Symptom-driven diagnosis

Every entry follows the same pattern: **observable symptom -> where the failure code lives -> what to check first -> handoff if rooted elsewhere.**
Expand Down Expand Up @@ -137,3 +145,9 @@ Repeat until the symptom is explained or scoped:
7. If the symptom is missing customer-side data: prove webhook health via `is_active`, `consecutive_failures`, and `/v3/webhooks/{id}/events` before blaming delivery.
8. Hand off via the matrix above, or escalate to Sent support with the required evidence.
9. Quantify the diagnosis — never "looks better now" without a recomputed funnel.

## Source notes

- This playbook is operational guidance synthesized from the [Sent v3 OpenAPI](https://api.sent.dm/swagger/v3/swagger.json), [message status guide](https://docs.sent.dm/llms/start/guides/message-status-tracking.txt), [webhook event reference](https://docs.sent.dm/llms/start/webhooks/event-types.txt), and [channel-routing reference](https://docs.sent.dm/llms/reference/channel-routing.txt), last checked on 2026-08-09.
- Dominance thresholds, cohort-size guidance, comparison windows, and escalation timing are analyst heuristics unless a cited Sent source states otherwise.
- Re-check the repository documentation source catalog before relying on exact endpoints, enums, or limits after its `last_verified` date.
5 changes: 0 additions & 5 deletions plugins/sent/skills/messaging-performance-analyzer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,3 @@ Use the `sent` skill for shared Sent terminology and routing.
| `scripts/analyze_mdr_funnel.py` | Validation script | Reads an MDR export (CSV or JSON), groups channel × direction outcomes, separates delivery transitions from engagement, and retains malformed/unknown rows. Run from the skill root: `python scripts/analyze_mdr_funnel.py path/to/mdr.csv` (use `--threshold N`, `--show-errors`, or `--format json`). Exit `0` means no observed transition breach, `2` means bad input/no usable cohort, and `3` means an observed breach. JSON uses `null` where a denominator is unavailable; text uses `N/A`. |
| `scripts/fixtures/good.json` | Fixture | Synthetic healthy-funnel MDR export. |
| `scripts/fixtures/bad.json` | Fixture | Synthetic MDR export with deliberate >50% SENT→DELIVERED drop. |

## Unverified claims to confirm or remove

- Any fixed cohort-size threshold such as “1,000 messages minimum” is an analyst heuristic, not a documented Sent API rule.
- External provider identifiers such as carrier message IDs, WhatsApp `wamid`, and RCS message IDs are not in the v3 docs as join keys; use Sent `message_id` and treat provider IDs as escalation-only context.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@
Supporting reference for `messaging-performance-analyzer`. "MDR" is the human term for Sent's per-message status stream; the v3 surfaces are `GET /v3/messages/{id}` and `GET /v3/messages/{id}/activities`. The codes below are Sent's own normalized catalog as documented at docs.sent.dm — not raw provider codes.

Authoritative upstream sources (for the downstream provider codes that may appear in `error.details` after Sent normalization):

- WhatsApp: [Cloud API Error Codes](https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes)
- SMS: TCR + carrier-specific reject reasons (T-Mobile, AT&T, Verizon each publish their own list)
- RCS: [RBM API errors](https://developers.google.com/business-communications/rcs-business-messaging/reference/rest)

## Table of contents

- [Message status lifecycle](#message-status-lifecycle)
- [Synchronous errors](#synchronous-errors-http-response-body)
- [Send-time per-message errors](#send-time-per-message-errors)
- [Webhook payload shape](#webhook-payload-shape)
- [Webhook event lifecycle](#webhook-event-lifecycle)
- [Provider-level codes](#provider-level-codes-referential-not-sent-normalized)
- [Counting rules](#counting-rules)
- [Source notes](#source-notes)

## Message status lifecycle

Sent normalizes channels into a shared delivery state machine. The latest status per `message_id` determines its current outcome, while an activity history supplies the evidence for transition counts. Do not backfill earlier stages from a latest-only record.
Expand Down Expand Up @@ -214,3 +226,10 @@ Carriers don't share an enum; the categories you actually need to triage on:
- **Stop SMS at `DELIVERED`.** Calculate `READ` engagement only for WhatsApp and RCS.
- **Separate channel fan-out.** `POST /v3/messages` with `"channel": ["sms","whatsapp","rcs"]` creates one message per channel; each has its own `message_id` and its own lifecycle. Don't double-count at the recipient level unless the user explicitly asks for recipient-level rollup.
- **Honor a minimum cohort size** before drawing conclusions about small rate shifts. A working heuristic is ≥1,000 messages per cohort; below that, noise dominates. This is an analyst rule of thumb, not a Sent API rule.

## Source notes

- Sent lifecycle, error-envelope, template, message-activity, and webhook claims were last checked on 2026-08-09 against the [Sent v3 OpenAPI](https://api.sent.dm/swagger/v3/swagger.json), [message status guide](https://docs.sent.dm/llms/start/guides/message-status-tracking.txt), and [webhook event reference](https://docs.sent.dm/llms/start/webhooks/event-types.txt).
- Provider-code tables are referential aids sourced from the linked provider documentation; they are not Sent-normalized enums. SMS carriers do not publish one shared reject enum.
- The 1,000-message cohort threshold is an analyst heuristic, not a documented Sent API requirement.
- Provider identifiers such as carrier message IDs, WhatsApp `wamid`, and RCS message IDs are not documented Sent v3 join keys. Use Sent `message_id` and treat provider IDs as escalation context.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ Supporting reference for `messaging-performance-analyzer`. The SKILL.md tells yo

For the full catalog of codes referenced below, see `references/mdr-status-codes.md`.

## Table of contents

- [Symptom-driven diagnosis](#symptom-driven-diagnosis)
- [Cross-skill handoff matrix](#cross-skill-handoff-matrix)
- [When to escalate to Sent support](#when-to-escalate-to-sent-support)
- [Diagnostic loop](#diagnostic-loop)
- [Source notes](#source-notes)

## Symptom-driven diagnosis

Every entry follows the same pattern: **observable symptom -> where the failure code lives -> what to check first -> handoff if rooted elsewhere.**
Expand Down Expand Up @@ -137,3 +145,9 @@ Repeat until the symptom is explained or scoped:
7. If the symptom is missing customer-side data: prove webhook health via `is_active`, `consecutive_failures`, and `/v3/webhooks/{id}/events` before blaming delivery.
8. Hand off via the matrix above, or escalate to Sent support with the required evidence.
9. Quantify the diagnosis — never "looks better now" without a recomputed funnel.

## Source notes

- This playbook is operational guidance synthesized from the [Sent v3 OpenAPI](https://api.sent.dm/swagger/v3/swagger.json), [message status guide](https://docs.sent.dm/llms/start/guides/message-status-tracking.txt), [webhook event reference](https://docs.sent.dm/llms/start/webhooks/event-types.txt), and [channel-routing reference](https://docs.sent.dm/llms/reference/channel-routing.txt), last checked on 2026-08-09.
- Dominance thresholds, cohort-size guidance, comparison windows, and escalation timing are analyst heuristics unless a cited Sent source states otherwise.
- Re-check the repository documentation source catalog before relying on exact endpoints, enums, or limits after its `last_verified` date.
Loading