Files
coordination-engine/spec/SmsAdapterSpecification.md

1700 lines
64 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
I used current provider documentation and industry guidance to ground the SMS model. Twilios outbound status model includes states such as queued/sending/sent/delivered/undelivered/failed, and notes that `sent` may remain without final delivery status in some cases. ([help.twilio.com][1]) Vonages SMS DLRs include `accepted`, `delivered`, `buffered`, `expired`, `failed`, `rejected`, and `unknown`; Vonage also notes DLRs are returned when received from downstream carriers. ([developer.vonage.com][2]) Sinchs SMS delivery reports use statuses such as queued, dispatched, delivered and error codes, while Bird/MessageBird distinguish delivered from not delivered and provide reason codes such as unknown subscriber. ([developers.sinch.com][3]) SMS content length, encoding, and concatenation matter because GSM-7, UCS-2, and multi-segment messages affect cost, delivery behavior, and diagnostics. ([Twilio][4]) For compliance-sensitive SMS, opt-in/opt-out, STOP/HELP handling, and sender registration are first-class channel concerns; Twilio documents Advanced Opt-Out and A2P 10DLC registration, while CTIA guidance emphasizes documenting consent and respecting opt-out. ([Twilio][5])
# SmsAdapterSpecification.md
## 1. Document Status
**Document:** SmsAdapterSpecification.md
**Project:** sms-connect
**Target Integration:** coordination-engine
**Adapter Contract:** AdapterInterfaceSpecification.md v1.0
**Status:** Draft v1.0
**Primary Scope:** SMS protocol and provider integration as a coordination-engine adapter
## 2. Purpose
This document specifies how `sms-connect` models SMS as a communication protocol and how it integrates with `coordination-engine`.
`sms-connect` is a channel adapter for short-message communication. It provides SMS-specific sending, delivery receipt ingestion, status normalization, phone endpoint quality handling, opt-out/suppression handling, inbound reply processing, evidence classification, and provider abstraction.
SMS is often stronger than email for endpoint-level delivery evidence because carriers and providers may return delivery receipts indicating that a message reached the receiving network or handset. However, SMS still does not normally prove human awareness, comprehension, identity-bound interaction, payload access, or final coordination success.
The key design objective is to make SMS useful as a notification, reminder, escalation, and lightweight interaction channel without overclaiming what SMS can prove.
## 3. Core Principle
SMS is a medium-strength notification channel with better endpoint-delivery evidence than email in many cases, but it is still not a reliable proof channel for human awareness or result completion.
The adapter MUST distinguish:
```text
provider acceptance
carrier or downstream network acceptance
delivery receipt
temporary delivery uncertainty
permanent delivery failure
recipient reply
opt-out or suppression
link interaction
identity-bound interaction from another system
coordination result evidence
```
In the coordination model, SMS delivery receipts can support stronger notification evidence than email MX acceptance, but SMS events alone usually remain insufficient for high-assurance scenarios unless the intended result explicitly accepts SMS delivery or SMS reply as sufficient.
## 4. Architectural Role
### 4.1 Standalone Role
As a standalone component, `sms-connect` provides:
* provider-neutral SMS sending
* transactional SMS dispatch
* provider and carrier delivery receipt ingestion
* message status normalization
* phone number endpoint diagnostics
* SMS segmentation and encoding diagnostics
* inbound SMS reply handling
* opt-in, opt-out, HELP, START, and STOP keyword handling
* suppression management
* sender identity and campaign metadata tracking
* SMS message timelines
* delivery failure classification
* channel health and compliance diagnostics
* normalized SMS evidence stream
### 4.2 coordination-engine Adapter Role
As a `coordination-engine` adapter, `sms-connect` provides:
#### Actions
* `notification.send`
* `notification.send_reminder`
* `notification.schedule`
* `notification.cancel` where technically possible before dispatch
* `recipient.suppress`
* `recipient.unsuppress`
* `recipient.opt_in_record`
* `recipient.opt_out_record`
* `notification.register_tracking_context`
#### Signals
* `notification.attempt.accepted_by_adapter`
* `notification.attempt.rejected_by_adapter`
* `notification.attempt.accepted_by_provider`
* `notification.attempt.rejected_by_provider`
* `notification.attempt.queued`
* `notification.attempt.scheduled`
* `notification.attempt.delayed`
* `notification.endpoint.accepted`
* `notification.endpoint.deferred`
* `notification.endpoint.rejected_temporary`
* `notification.endpoint.rejected_permanent`
* `notification.endpoint.unreachable`
* `notification.endpoint.unknown`
* `notification.channel.suppression_added`
* `notification.channel.suppression_removed`
* `notification.channel.complaint_received`
* `notification.channel.unsubscribe_received`
* `notification.channel.reputation_warning`
* `interaction.reply_received`
* `interaction.acknowledgement_recorded`
* `interaction.unverified_actor_interaction`
* `interaction.authenticated_actor_interaction` only when paired with trusted identity evidence
* `system.provider.degraded`
* `system.provider.unavailable`
## 5. Relationship to coordination-engine
`sms-connect` does not own:
* `CoordinationCase`
* intended result evaluation
* participant-level success
* case-level success
* legal notification interpretation
* portal access
* payload retrieval
* payment settlement
* signature completion
* multi-channel escalation policy
* final closure decisions
`sms-connect` owns:
* SMS send requests
* SMS provider abstraction
* provider and carrier identifiers
* SMS delivery receipt ingestion
* SMS status classification
* SMS-native message timeline
* phone endpoint diagnostics
* SMS reply classification
* opt-out and suppression handling
* SMS evidence mapping
* SMS-specific uncertainty classification
The boundary rule is:
> sms-connect reports what happened in the SMS channel and what that may indicate. coordination-engine decides what that means for the coordination case.
## 6. SMS as Notification, Lightweight Payload, and Response Channel
Within `coordination-engine`, SMS is primarily a **notification and reminder channel**.
SMS may also carry lightweight inline payloads or action prompts, such as:
* one-time codes
* short status alerts
* short links
* payment links
* confirmation prompts
* reply keywords
* appointment reminders
* urgent escalation notices
However, for most coordination scenarios, SMS should point participants toward an action surface such as:
* portal page
* mobile app screen
* payment page
* signature flow
* upload form
* approval screen
* support flow
The actual payload access or result-relevant action is usually observed by another adapter.
Example:
```text
sms-connect:
notification.endpoint.accepted
interaction.reply_received
portal-connect:
identity.actor_authenticated
delivery.payload.downloaded
coordination-engine:
participant result satisfied
```
SMS delivery to handset or network is stronger than provider acceptance but still does not prove that the intended human read, understood, or acted on the message.
## 7. SMS Message Lifecycle Model
`sms-connect` models an SMS notification as a lifecycle with observable phases.
```text
message.created
message.rendered
message.render_failed
message.segmentation_analyzed
message.consent_checked
message.suppression_checked
message.send_requested
message.accepted_by_adapter
message.rejected_by_adapter
message.accepted_by_provider
message.rejected_by_provider
message.queued
message.scheduled
message.dispatched
message.accepted_by_carrier
message.buffered
message.deferred
message.delivered
message.undelivered
message.failed
message.rejected
message.expired
message.unknown
message.inbound_reply_received
message.opt_out_received
message.opt_in_received
message.help_received
message.link_clicked
message.suppression_added
message.channel_warning
```
The lifecycle is not strictly linear. Events may arrive late, out of order, duplicated, partially aggregated, or missing.
## 8. SMS Message vs Attempt vs Segment vs Recipient
The adapter MUST distinguish at least four layers.
### 8.1 SmsMessage
The logical SMS message created by a client or coordination case.
```yaml
SmsMessage:
sms_message_id: string
coordination_case_id: string?
participant_id: string?
purpose: string?
message_body_ref: string?
template_ref: string?
tracking_context: TrackingContext
created_at: timestamp
```
### 8.2 SmsAttempt
One send attempt through one provider/configuration.
```yaml
SmsAttempt:
sms_attempt_id: string
sms_message_id: string
provider_name: string
provider_account_ref: string?
sender_endpoint: SmsEndpoint
recipient_endpoint: SmsEndpoint
provider_message_id: string?
adapter_operation_id: string?
sender_identity_ref: string?
campaign_ref: string?
state: SmsAttemptState
created_at: timestamp
updated_at: timestamp
```
### 8.3 SmsSegment
A logical SMS may be split into multiple billable/deliverable segments.
```yaml
SmsSegment:
sms_segment_id: string
sms_attempt_id: string
segment_index: integer
segment_count: integer
encoding: gsm7 | ucs2 | binary | unknown
provider_segment_id: string?
carrier_segment_id: string?
state: SmsSegmentState
delivered_at: timestamp?
failed_at: timestamp?
```
Segmentation matters for cost, deliverability diagnostics, and partial-failure interpretation. For coordination evidence, a multi-segment message should normally be considered delivered only when the provider or carrier reports the message as delivered or enough segment-level evidence exists according to provider semantics.
### 8.4 SmsEndpoint
The target or sender endpoint.
```yaml
SmsEndpoint:
endpoint_id: string?
endpoint_type: phone_number | short_code | long_code | toll_free | alphanumeric_sender_id | sender_pool | unknown
phone_number_e164: string?
sender_id: string?
display_name: string?
country_code: string?
verification_state: unknown | syntax_validated | verified | suspected_invalid | invalid
consent_state: unknown | opted_in | opted_out | consent_not_required | consent_required | disputed
suppression_state: active | suppressed | opt_out_suppressed | bounce_suppressed | provider_suppressed | manual_suppressed | unknown
metadata: object?
```
Per-recipient modeling is required. The preferred coordination mode is one logical notification attempt per participant endpoint.
## 9. SMS Attempt States
The adapter SHOULD support these attempt states:
```text
created
rendered
render_failed
consent_blocked
suppressed
send_requested
accepted_by_adapter
rejected_by_adapter
accepted_by_provider
rejected_by_provider
queued
scheduled
dispatched
accepted_by_carrier
buffered
deferred
delivered
undelivered
failed
rejected
expired
unknown
reply_received
opt_out_received
opt_in_received
help_received
channel_degraded
```
These states are SMS-native. They are not coordination result states.
## 10. SMS Evidence Assessment
`sms-connect` should provide an SMS-native assessment separate from coordination-engine state.
```yaml
SmsEvidenceAssessment:
sms_message_id: string
participant_id: string?
category: success | fail | undef
subclass: string
confidence: low | medium | high
strongest_signal: string?
evidence_summary:
- string
recommended_coordination_interpretation: string?
```
The assessment categories are adapter-level hints.
### 10.1 SMS Adapter Success
SMS-level `success` means the SMS channel produced strong SMS-channel evidence.
Possible subclasses:
```text
success.provider_accepted
success.carrier_accepted
success.delivered
success.reply_received
success.acknowledgement_reply_received
success.link_clicked
```
Important: These are not automatically coordination success.
`success.delivered` usually means a provider or carrier reports delivery to the handset or receiving network. It is stronger than email server acceptance, but it still does not prove human awareness unless scenario policy accepts delivery receipt as sufficient.
### 10.2 SMS Adapter Fail
SMS-level `fail` indicates strong evidence that the SMS channel failed or should not be used.
Subclasses:
```text
fail.missing_number
fail.invalid_number_format
fail.not_mobile_number
fail.unknown_subscriber
fail.unreachable_subscriber
fail.unavailable_subscriber
fail.ported_number_issue
fail.blocked_by_recipient
fail.opted_out
fail.consent_missing
fail.suppressed
fail.provider_rejected
fail.carrier_rejected
fail.filtered_by_carrier
fail.policy_rejected
fail.content_rejected
fail.sender_not_registered
fail.sender_not_allowed
fail.route_unavailable
fail.expired
fail.delivery_failed
fail.message_too_long_or_invalid
fail.encoding_unsupported
fail.account_or_quota_failure
```
### 10.3 SMS Adapter Undef
SMS-level `undef` is used when the adapter cannot determine final delivery or human awareness.
Subclasses:
```text
undef.pending
undef.provider_accepted_only
undef.queued
undef.dispatched
undef.carrier_accepted_only
undef.buffered
undef.deferred
undef.no_dlr
undef.dlr_unknown
undef.delivery_status_unknown
undef.delivery_receipt_missing
undef.delivered_but_awareness_unproven
undef.link_clicked_identity_uncertain
undef.reply_identity_uncertain
undef.conflicting_evidence
undef.channel_degraded
undef.expired_unknown
```
The `undef` category must not be empty because SMS delivery reporting is provider-, route-, country-, carrier-, and device-dependent.
## 11. Detailed SMS Scenario Classification
### 11.1 Pre-Send Scenarios
| Scenario | SMS assessment | Normalized event | Notes |
| -------------------------------------- | --------------------------------------------------------------- | ------------------------------------------ | ---------------------------------------- |
| Missing number | `fail.missing_number` | `notification.attempt.rejected_by_adapter` | No send possible |
| Invalid phone number syntax | `fail.invalid_number_format` | `notification.attempt.rejected_by_adapter` | Strong local failure |
| Number not suitable for SMS | `fail.not_mobile_number` | `notification.attempt.rejected_by_adapter` | Landline or unsupported endpoint |
| Missing consent where required | `fail.consent_missing` | `notification.attempt.rejected_by_adapter` | Policy/compliance block |
| Recipient opted out | `fail.opted_out` | `notification.channel.suppression_added` | Channel blocked |
| Suppression hit | `fail.suppressed` | `notification.channel.suppression_added` | Channel blocked |
| Template rendering failure | `fail.message_too_long_or_invalid` or `fail.provider_rejected` | `notification.attempt.rejected_by_adapter` | Notification unusable |
| Message contains invalid link | `fail.message_too_long_or_invalid` or scenario-specific failure | `notification.attempt.rejected_by_adapter` | Especially relevant for portal links |
| Sender/campaign missing | `fail.sender_not_registered` or `fail.sender_not_allowed` | `notification.attempt.rejected_by_adapter` | Common in regulated routes |
| Provider unavailable before acceptance | `undef.pending` or `fail.provider_rejected` | action error | Depends on retryability |
| Submission timeout | `undef.pending` | action result unknown | Could have been accepted despite timeout |
### 11.2 Provider-Side Scenarios
| Scenario | SMS assessment | Normalized event | Notes |
| ------------------------------ | ------------------------------- | ------------------------------------------------------- | ------------------------------ |
| Adapter accepted request | `undef.pending` | `notification.attempt.accepted_by_adapter` | Adapter accepted work |
| Provider accepted message | `undef.provider_accepted_only` | `notification.attempt.accepted_by_provider` | Sending began |
| Provider rejected message | `fail.provider_rejected` | `notification.attempt.rejected_by_provider` | Strong attempt failure |
| Provider queued message | `undef.queued` | `notification.attempt.queued` | Pending |
| Provider scheduled message | `undef.pending` | `notification.attempt.scheduled` | Not yet sent |
| Provider dispatched message | `undef.dispatched` | `notification.attempt.accepted_by_provider` or metadata | Provider handed off downstream |
| Provider delayed message | `undef.deferred` | `notification.attempt.delayed` | Pending/degraded |
| Provider route unavailable | `fail.route_unavailable` | `notification.attempt.rejected_by_provider` | Strong channel/route failure |
| Provider quota/account failure | `fail.account_or_quota_failure` | `notification.attempt.rejected_by_provider` | Operational failure |
| Provider suppression | `fail.suppressed` | `notification.channel.suppression_added` | Channel blocked |
### 11.3 Carrier and Downstream Network Scenarios
| Scenario | SMS assessment | Normalized event | Notes |
| ---------------------------- | ----------------------------------------- | --------------------------------------------------------------- | ---------------------------------------------------- |
| Carrier accepted | `undef.carrier_accepted_only` | `notification.endpoint.accepted` | Stronger than provider-only, still not handset proof |
| Buffered | `undef.buffered` | `notification.endpoint.deferred` | Held for later delivery |
| Deferred | `undef.deferred` | `notification.endpoint.deferred` | Retry or wait |
| Delivered | `success.delivered` | `notification.endpoint.accepted` with delivery metadata | Strong endpoint evidence, not human awareness |
| Undelivered | `fail.delivery_failed` | `notification.endpoint.rejected_permanent` or temporary | Use reason code |
| Failed | `fail.delivery_failed` | `notification.endpoint.rejected_permanent` | Strong negative evidence if final |
| Rejected | `fail.carrier_rejected` | `notification.endpoint.rejected_permanent` | Carrier refused delivery |
| Expired | `fail.expired` or `undef.expired_unknown` | `notification.endpoint.unknown` or rejected temporary/permanent | Depends on provider semantics |
| Unknown | `undef.dlr_unknown` | `notification.endpoint.unknown` | No useful final status |
| No DLR received | `undef.no_dlr` | none or timeout event | Common on some routes |
| Delivery receipt late | update current assessment | corresponding event | Must be accepted if relevant |
| Conflicting delivery reports | `undef.conflicting_evidence` | multiple events | Preserve all evidence |
### 11.4 Device and Recipient Availability Scenarios
| Scenario | SMS assessment | Notes |
| -------------------------------- | ------------------------------------------------- | ---------------------------------------------- |
| Handset off or unreachable | `undef.deferred` or `fail.unreachable_subscriber` | Depending on final DLR |
| Subscriber unavailable | `undef.deferred` or `fail.unavailable_subscriber` | Carrier-specific |
| Unknown subscriber | `fail.unknown_subscriber` | Remove or verify number |
| Roaming issue | `undef.deferred` or `fail.route_unavailable` | Route/country dependent |
| Blocked by recipient | `fail.blocked_by_recipient` | If provider/carrier reports it |
| Carrier filtering | `fail.filtered_by_carrier` | Often content/campaign/sender issue |
| Device received but user ignored | `undef.delivered_but_awareness_unproven` | Delivery does not prove reading |
| SIM swap/number reassigned | `undef.identity_uncertain` if suspected | Requires external identity/number intelligence |
| Shared phone | `undef.identity_uncertain` | Intended participant uncertain |
| Corporate device management | `undef.delivered_but_awareness_unproven` | User awareness uncertain |
### 11.5 Link Interaction Scenarios
SMS itself does not provide open tracking. Link interaction must be observed through tracked links or action surfaces.
| Scenario | SMS assessment | Normalized event | Notes |
| -------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------ | -------------------------------------- |
| No link click | `undef.no_signal` | none | Not evidence of failure |
| Link clicked | `success.link_clicked` or `undef.link_clicked_identity_uncertain` | `interaction.unverified_actor_interaction` | Identity uncertain |
| Link clicked then authenticated portal login | SMS event remains weak; portal event is strong | Portal adapter provides identity evidence | |
| Link clicked then payload downloaded | SMS contributed path evidence; delivery evidence is decisive | Portal/delivery adapter closes result | |
| Link scanner or preview fetch | `undef.link_clicked_identity_uncertain` or scanner-like if detected | `interaction.scanner_or_bot_interaction` | Less common than email but possible |
| Expired link clicked | `undef.link_clicked_identity_uncertain` | interaction plus access failure | Awareness possible, action path failed |
| Forwarded SMS link clicked | `undef.identity_uncertain` | unverified interaction | Intended actor unknown |
### 11.6 Inbound Reply Scenarios
SMS can be a useful lightweight response channel.
| Scenario | SMS assessment | Normalized event | Notes |
| ----------------------------------------------- | ---------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------- |
| Any reply received | `success.reply_received` | `interaction.reply_received` | Strong awareness signal, identity may still need validation |
| YES/OK/ACK reply | `success.acknowledgement_reply_received` | `interaction.acknowledgement_recorded` if policy accepts | Can be result evidence in low/medium assurance cases |
| STOP / unsubscribe | `fail.opted_out` | `notification.channel.unsubscribe_received` + suppression | Future channel constraint |
| START / opt-in | active/unknown | `notification.channel.suppression_removed` or opt-in metadata | Channel may become usable |
| HELP | neutral | `interaction.reply_received` | Support/compliance event |
| Free-text question | `success.reply_received` | `interaction.reply_received` | May trigger support workflow |
| Reply from reassigned/shared number | `undef.reply_identity_uncertain` | `interaction.reply_received` | Identity risk |
| Reply from unsupported alphanumeric sender path | no inbound possible | capability limitation | Must be declared by adapter |
A reply is often stronger awareness evidence than a delivery receipt, but it still may not prove that the intended participant acted unless phone-number ownership and context are sufficient for the scenario.
### 11.7 Opt-Out, Consent, and Suppression Scenarios
| Scenario | SMS assessment | Normalized event | Notes |
| -------------------- | ----------------------- | --------------------------------------------------------- | --------------------------- |
| Consent recorded | channel usable | adapter metadata or evidence | May be required before send |
| Consent missing | `fail.consent_missing` | `notification.attempt.rejected_by_adapter` | Local policy block |
| STOP received | `fail.opted_out` | `notification.channel.unsubscribe_received` + suppression | Channel blocked |
| START received | channel may be restored | `notification.channel.suppression_removed` | Provider/country dependent |
| HELP received | neutral/support event | `interaction.reply_received` | May trigger help response |
| Manual suppression | `fail.suppressed` | `notification.channel.suppression_added` | Operator action |
| Provider suppression | `fail.suppressed` | `notification.channel.suppression_added` | Provider-managed |
| Suppression removed | active/unknown | `notification.channel.suppression_removed` | Channel may become usable |
For non-marketing or legally required notifications, opt-out semantics must be scenario-specific. `sms-connect` records the event; `coordination-engine` decides whether SMS remains permissible, whether fallback is needed, or whether manual handling is required.
## 12. Adapter-to-Coordination Mapping
### 12.1 Core Mapping Table
| SMS-native event | SMS assessment | coordination-engine event | Coordination interpretation |
| -------------------- | ----------------------------------------- | -------------------------------------------------------- | ----------------------------------------- |
| message created | `undef.pending` | `notification.attempt.created` | Attempt exists |
| render failed | `fail.message_too_long_or_invalid` | `notification.attempt.rejected_by_adapter` | Notification failed before send |
| consent block | `fail.consent_missing` | `notification.attempt.rejected_by_adapter` | Local policy block |
| suppression hit | `fail.suppressed` | `notification.channel.suppression_added` | Channel blocked |
| adapter accepted | `undef.pending` | `notification.attempt.accepted_by_adapter` | Work accepted |
| adapter rejected | adapter-specific fail | `notification.attempt.rejected_by_adapter` | Attempt failed |
| provider accepted | `undef.provider_accepted_only` | `notification.attempt.accepted_by_provider` | Weak send evidence |
| provider rejected | `fail.provider_rejected` | `notification.attempt.rejected_by_provider` | Strong attempt failure |
| provider queued | `undef.queued` | `notification.attempt.queued` | Pending |
| dispatched | `undef.dispatched` | `notification.attempt.accepted_by_provider` + metadata | Sent downstream |
| carrier accepted | `undef.carrier_accepted_only` | `notification.endpoint.accepted` | Medium endpoint evidence |
| buffered | `undef.buffered` | `notification.endpoint.deferred` | Pending |
| delivered | `success.delivered` | `notification.endpoint.accepted` with delivered metadata | Strong endpoint evidence, not human proof |
| undelivered | `fail.delivery_failed` | `notification.endpoint.rejected_permanent` or temporary | Use reason code |
| failed | `fail.delivery_failed` | `notification.endpoint.rejected_permanent` | Strong final failure |
| rejected | `fail.carrier_rejected` | `notification.endpoint.rejected_permanent` | Strong final failure |
| expired | `fail.expired` or `undef.expired_unknown` | `notification.endpoint.unknown` or rejected | Depends on reason |
| unknown | `undef.dlr_unknown` | `notification.endpoint.unknown` | Unclear outcome |
| inbound reply | `success.reply_received` | `interaction.reply_received` | Strong awareness evidence |
| ACK reply | `success.acknowledgement_reply_received` | `interaction.acknowledgement_recorded` | Result evidence if policy accepts |
| STOP | `fail.opted_out` | `notification.channel.unsubscribe_received` | Channel constraint |
| START | active/unknown | `notification.channel.suppression_removed` | Channel may be usable |
| tracked link clicked | `undef.link_clicked_identity_uncertain` | `interaction.unverified_actor_interaction` | Identity uncertain |
### 12.2 Coordination Undef Subclasses
`coordination-engine` may derive these participant uncertainty classes from SMS evidence:
```text
undef.pending
undef.technical_acceptance_only
undef.endpoint_acceptance_only
undef.delivered_but_awareness_unproven
undef.no_signal
undef.weak_positive
undef.identity_uncertain
undef.channel_suspicious
undef.conflicting_evidence
undef.delivery_pending
undef.escalation_required
```
SMS evidence commonly produces:
```text
undef.pending
undef.endpoint_acceptance_only
undef.delivered_but_awareness_unproven
undef.identity_uncertain
undef.conflicting_evidence
```
## 13. Evidence Grading Rules
### 13.1 Provider Acceptance
```yaml
event_type: notification.attempt.accepted_by_provider
evidence_grade:
strength: weak
actor_certainty: none
authority_certainty: none
payload_certainty: low
interaction_certainty: none
timing_certainty: medium
channel_certainty: medium
non_repudiation_strength: none
notes:
- Provider accepted message for processing.
- Does not prove carrier acceptance or handset delivery.
```
### 13.2 Carrier Acceptance
```yaml
event_type: notification.endpoint.accepted
evidence_grade:
strength: medium
actor_certainty: none
authority_certainty: none
payload_certainty: low
interaction_certainty: none
timing_certainty: medium
channel_certainty: medium
non_repudiation_strength: low
notes:
- Downstream carrier or network accepted the message.
- Does not prove recipient read or understood the message.
```
### 13.3 Delivered DLR
```yaml
event_type: notification.endpoint.accepted
evidence_grade:
strength: strong
actor_certainty: none
authority_certainty: none
payload_certainty: medium
interaction_certainty: low
timing_certainty: high
channel_certainty: high
non_repudiation_strength: low
notes:
- Delivery receipt indicates successful delivery according to provider/carrier semantics.
- Does not prove human awareness or intended-recipient identity.
```
### 13.4 Undelivered / Failed
```yaml
event_type: notification.endpoint.rejected_permanent
evidence_grade:
strength: negative
actor_certainty: none
authority_certainty: none
payload_certainty: none
interaction_certainty: none
timing_certainty: medium
channel_certainty: high
non_repudiation_strength: low
notes:
- Strong evidence that the SMS channel failed for this attempt.
- Failure reason should determine retry, fallback, or suppression.
```
### 13.5 Buffered / Deferred
```yaml
event_type: notification.endpoint.deferred
evidence_grade:
strength: ambiguous
actor_certainty: none
authority_certainty: none
payload_certainty: none
interaction_certainty: none
timing_certainty: medium
channel_certainty: medium
non_repudiation_strength: none
notes:
- Message is pending or held for later delivery.
- Outcome remains uncertain until final DLR, timeout, or expiry.
```
### 13.6 Unknown / No DLR
```yaml
event_type: notification.endpoint.unknown
evidence_grade:
strength: ambiguous
actor_certainty: none
authority_certainty: none
payload_certainty: none
interaction_certainty: none
timing_certainty: low
channel_certainty: low
non_repudiation_strength: none
notes:
- No useful delivery status is available.
- Policy should decide wait, retry, alternate channel, or manual review.
```
### 13.7 Inbound Reply
```yaml
event_type: interaction.reply_received
evidence_grade:
strength: strong
actor_certainty: medium
authority_certainty: low
payload_certainty: medium
interaction_certainty: high
timing_certainty: high
channel_certainty: high
non_repudiation_strength: low
notes:
- Reply indicates interaction from the phone endpoint.
- Identity and authority may still require validation.
```
### 13.8 Acknowledgement Reply
```yaml
event_type: interaction.acknowledgement_recorded
evidence_grade:
strength: strong
actor_certainty: medium
authority_certainty: low
payload_certainty: medium
interaction_certainty: high
timing_certainty: high
channel_certainty: high
non_repudiation_strength: low
notes:
- Recipient endpoint replied with an acknowledgement keyword.
- Whether this satisfies the intended result is scenario-policy dependent.
```
### 13.9 Opt-Out
```yaml
event_type: notification.channel.unsubscribe_received
evidence_grade:
strength: negative
actor_certainty: medium
authority_certainty: low
payload_certainty: none
interaction_certainty: high
timing_certainty: high
channel_certainty: high
non_repudiation_strength: low
notes:
- Phone endpoint opted out or requested no further messages.
- Future use of the channel may be legally, contractually, or operationally constrained.
```
### 13.10 Link Click
```yaml
event_type: interaction.unverified_actor_interaction
evidence_grade:
strength: medium
actor_certainty: low
authority_certainty: none
payload_certainty: medium
interaction_certainty: medium
timing_certainty: medium
channel_certainty: medium
non_repudiation_strength: none
notes:
- Link was clicked, but actor identity is not proven.
- Stronger evidence should come from the action surface or identity adapter.
```
## 14. Message Timeline API
`sms-connect` SHOULD expose a message timeline suitable for standalone diagnostics and coordination audit.
```yaml
SmsMessageTimeline:
sms_message_id: string
sms_attempts:
- sms_attempt_id: string
provider_name: string
provider_message_id: string?
events:
- SmsTimelineEvent
segments:
- SmsSegment
current_assessment: SmsEvidenceAssessment
```
```yaml
SmsTimelineEvent:
event_id: string
event_type: string
occurred_at: timestamp
source: adapter | provider | carrier | inbound_sms | tracking | operator
native_event_type: string?
normalized_event_type: string?
summary: string
evidence_grade: EvidenceGrade
raw_event_ref: string?
```
## 15. Adapter Descriptor
`sms-connect` MUST expose an `AdapterDescriptor` compatible with AdapterInterfaceSpecification.md v1.0.
```yaml
adapter_id: sms-connect.default
adapter_name: sms-connect
adapter_version: 1.0.0
adapter_contract_version: 1.0
adapter_types:
- notification
- communication
- interaction
provider_family: sms
provider_name: configurable
deployment_mode: external
supported_channels:
- sms
supported_endpoint_types:
- phone_number
- short_code
- long_code
- toll_free
- alphanumeric_sender_id
supported_actions:
- action_type: notification.send
mode: async
idempotency_required: true
- action_type: notification.send_reminder
mode: async
idempotency_required: true
- action_type: notification.schedule
mode: scheduled
idempotency_required: true
- action_type: notification.register_tracking_context
mode: sync
idempotency_required: true
- action_type: recipient.suppress
mode: sync
idempotency_required: true
- action_type: recipient.unsuppress
mode: sync
idempotency_required: true
emitted_event_types:
- notification.attempt.created
- notification.attempt.accepted_by_adapter
- notification.attempt.rejected_by_adapter
- notification.attempt.accepted_by_provider
- notification.attempt.rejected_by_provider
- notification.attempt.queued
- notification.attempt.scheduled
- notification.attempt.delayed
- notification.endpoint.accepted
- notification.endpoint.deferred
- notification.endpoint.rejected_temporary
- notification.endpoint.rejected_permanent
- notification.endpoint.unreachable
- notification.endpoint.unknown
- notification.channel.unsubscribe_received
- notification.channel.suppression_added
- notification.channel.suppression_removed
- notification.channel.reputation_warning
- interaction.reply_received
- interaction.acknowledgement_recorded
- interaction.unverified_actor_interaction
- system.provider.degraded
- system.provider.unavailable
evidence_profile:
strongest_evidence_level: medium_to_strong
can_prove_human_awareness: false
can_prove_payload_delivery: false
can_prove_identity: false
identity_profile:
identity_strength: low_to_medium
authority_strength: none_to_low
limitations:
- SMS delivery receipts do not prove that the intended human read the message.
- Some routes do not provide reliable final delivery receipts.
- Delivered status semantics differ by provider, country, carrier, and route.
- Phone numbers may be reassigned, shared, forwarded, or unavailable.
- Link clicks do not prove actor identity.
- SMS content may be filtered by carriers or blocked by compliance rules.
- Alphanumeric sender IDs may not support inbound replies.
```
## 16. Action Request Handling
### 16.1 `notification.send`
`notification.send` sends a new SMS notification.
Required fields:
```text
request_id
action_type
coordination_case_id
participant_id
target_endpoint
content or template_ref
tracking_context
idempotency_key
requested_at
```
Example:
```yaml
request_id: req_001
action_type: notification.send
coordination_case_id: case_123
participant_id: participant_456
channel: sms
target_endpoint:
endpoint_type: phone_number
value: "+491701234567"
template_ref: secure-document-sms-reminder
variables:
portal_link: https://portal.example.com/access/abc
tracking_context:
correlation_id: corr_789
coordination_case_id: case_123
participant_id: participant_456
notification_id: notif_001
payload_id: payload_777
idempotency_key: case_123:participant_456:sms:notif_001
requested_at: 2026-01-01T12:00:00Z
```
### 16.2 Action Result
The adapter returns:
```yaml
request_id: req_001
adapter_id: sms-connect.default
accepted: true
action_state: accepted
adapter_operation_id: smsop_001
provider_operation_id: providerop_001
initial_events:
- event_type: notification.attempt.accepted_by_adapter
received_at: 2026-01-01T12:00:01Z
```
The result does not prove the SMS was delivered or read.
## 17. Provider Abstraction
`sms-connect` SHOULD support a provider abstraction layer.
Provider integration responsibilities:
* send SMS messages
* store provider message IDs
* verify webhooks
* ingest delivery receipts
* normalize provider statuses
* parse error codes
* handle opt-out events
* handle inbound replies
* expose provider health
* expose route/country/sender limitations
Provider model:
```yaml
SmsProvider:
provider_name: string
provider_account_ref: string
supported_features:
- sending
- delivery_receipts
- inbound_sms
- opt_out_handling
- sender_pools
- short_codes
- toll_free
- alphanumeric_sender_id
- scheduled_send
- status_callbacks
event_mapping_ref: string
configuration_ref: string
```
The first implementation MAY use a simulated provider. Real providers SHOULD be added behind this abstraction.
## 18. Native Provider Event Mapping
The adapter MUST support provider-specific mapping files or code modules.
Common provider-native status groups:
```text
accepted
queued
scheduled
sending
sent
dispatched
carrier_accepted
buffered
delivered
undelivered
failed
rejected
expired
unknown
deleted
opted_out
inbound
```
Important mapping rule:
Provider `delivered` events MUST be interpreted carefully.
For SMS, `delivered` usually means a provider or downstream network reports successful delivery according to its route-specific semantics. It SHOULD map to:
```text
notification.endpoint.accepted
```
with delivery metadata and strong endpoint evidence, but not to coordination result success unless the scenario policy explicitly accepts SMS DLR as sufficient.
## 19. Delivery Receipt Classification
`sms-connect` SHOULD classify delivery receipts into structured outcomes.
```yaml
SmsDeliveryReceipt:
provider_name: string
provider_message_id: string
provider_status: string
provider_error_code: string?
provider_error_text: string?
carrier_status: string?
carrier_error_code: string?
occurred_at: timestamp
final: boolean?
retryable: boolean?
classification:
- delivered
- accepted
- buffered
- deferred
- expired
- failed
- rejected
- unknown
- unknown_subscriber
- unavailable_subscriber
- unreachable_subscriber
- blocked
- filtered
- invalid_number
- route_unavailable
- sender_not_allowed
- content_not_allowed
- regulatory_rejected
- temporary_network_error
- provider_error
```
Suggested mappings:
| DLR class | SMS assessment | Normalized event |
| ----------------------- | ------------------------------------------------- | ----------------------------------------------------------------- |
| delivered | `success.delivered` | `notification.endpoint.accepted` |
| accepted | `undef.carrier_accepted_only` | `notification.endpoint.accepted` |
| buffered | `undef.buffered` | `notification.endpoint.deferred` |
| deferred | `undef.deferred` | `notification.endpoint.deferred` |
| expired | `fail.expired` or `undef.expired_unknown` | `notification.endpoint.unknown` or rejected |
| failed | `fail.delivery_failed` | `notification.endpoint.rejected_permanent` |
| rejected | `fail.carrier_rejected` | `notification.endpoint.rejected_permanent` |
| unknown | `undef.dlr_unknown` | `notification.endpoint.unknown` |
| unknown_subscriber | `fail.unknown_subscriber` | `notification.endpoint.rejected_permanent` |
| unavailable_subscriber | `undef.deferred` or `fail.unavailable_subscriber` | temporary or permanent by provider code |
| filtered | `fail.filtered_by_carrier` | `notification.endpoint.rejected_permanent` |
| sender_not_allowed | `fail.sender_not_allowed` | `notification.attempt.rejected_by_provider` or endpoint rejection |
| regulatory_rejected | `fail.policy_rejected` | `notification.endpoint.rejected_permanent` |
| temporary_network_error | `undef.deferred` | `notification.endpoint.rejected_temporary` |
## 20. Consent and Suppression Model
`sms-connect` SHOULD maintain or integrate with a consent and suppression model.
```yaml
SmsConsent:
endpoint_ref: EndpointRef
consent_state: opted_in | opted_out | unknown | not_required | disputed
consent_scope: global | tenant | sender_identity | campaign | coordination_case | purpose
consent_source: form | sms_keyword | contract | import | operator | external_system | unknown
consent_acquired_at: timestamp?
consent_evidence_ref: string?
expires_at: timestamp?
```
```yaml
SmsSuppression:
endpoint_ref: EndpointRef
suppression_type: opt_out | hard_failure | complaint | manual | provider_policy | consent_missing | unknown
scope: global | tenant | sender_identity | campaign | coordination_case | purpose
reason: string?
source: provider | adapter | operator | participant | policy
created_at: timestamp
expires_at: timestamp?
```
Suppression should produce evidence:
```text
notification.channel.suppression_added
notification.channel.suppression_removed
notification.channel.unsubscribe_received
```
coordination-engine decides whether suppression means participant failure, channel failure, alternate channel selection, or manual review.
## 21. Sender Identity and Campaign Model
SMS deliverability and compliance often depend on sender identity and campaign registration.
`sms-connect` SHOULD support sender identity metadata.
```yaml
SmsSenderIdentity:
sender_identity_id: string
sender_type: long_code | short_code | toll_free | alphanumeric_sender_id | sender_pool | unknown
sender_value: string?
country_scope:
- string
registration_state: unknown | not_required | pending | registered | rejected | expired
use_case: transactional | informational | marketing | verification | alert | mixed | unknown
brand_ref: string?
campaign_ref: string?
provider_account_ref: string?
throughput_profile_ref: string?
limitations:
- string
```
Examples of limitations:
```text
inbound_replies_not_supported
country_not_supported
marketing_not_allowed
registration_required
low_throughput
content_filtering_risk
```
## 22. Message Content, Encoding, and Segmentation
`sms-connect` SHOULD analyze message content before sending.
```yaml
SmsContentAnalysis:
body_length: integer
encoding: gsm7 | ucs2 | binary | unknown
segment_count: integer
per_segment_limit: integer
contains_url: boolean
contains_tracking_link: boolean
contains_opt_out_text: boolean
contains_non_gsm_characters: boolean
estimated_cost_units: number?
warnings:
- string
```
Potential warnings:
```text
message_requires_multiple_segments
unicode_reduces_segment_capacity
tracking_link_may_increase_length
message_missing_required_opt_out_text
content_filtering_risk
sender_identity_not_allowed_for_replies
```
Content analysis should not by itself determine coordination success, but it is important for cost, reliability, compliance, and diagnostics.
## 23. Link Tracking Model
SMS has no native open tracking. Link tracking may provide interaction evidence if a tracked URL is included.
```yaml
SmsLinkClickEvent:
sms_message_id: string
link_id: string
occurred_at: timestamp
url: string
ip_address: string?
user_agent: string?
scanner_classification: none | suspected | likely | confirmed | unknown
confidence: low | medium | high
```
Possible classifications:
```text
human_like_click
scanner_click
link_preview_fetch
unverified_click
unknown_click
```
The adapter SHOULD classify link clicks conservatively.
A click is not identity-bound unless paired with trusted identity evidence from the action surface.
## 24. Inbound Reply Model
`sms-connect` SHOULD support inbound SMS where the sender type and route support replies.
```yaml
SmsInboundMessage:
inbound_message_id: string
provider_name: string
provider_message_id: string?
from_endpoint: SmsEndpoint
to_endpoint: SmsEndpoint
received_at: timestamp
body_text: string
keyword_classification: none | opt_out | opt_in | help | acknowledgement | free_text | unknown
correlation: CorrelationContext?
raw_event_ref: string?
```
Keyword classifications:
```text
STOP / UNSUBSCRIBE / CANCEL / END / QUIT
START / UNSTOP
HELP / INFO
YES / OK / ACK / CONFIRM
NO / DECLINE
```
Actual keyword handling should be configurable by country, provider, language, sender identity, and scenario.
## 25. Phone Endpoint Quality
`sms-connect` SHOULD maintain phone endpoint quality signals.
```yaml
SmsEndpointQuality:
endpoint_ref: EndpointRef
e164_valid: boolean?
country_code: string?
number_type: mobile | landline | voip | toll_free | unknown
reachable: boolean?
carrier_name: string?
ported: boolean?
roaming: boolean?
consent_state: string?
suppression_state: string?
last_provider_acceptance_at: timestamp?
last_carrier_acceptance_at: timestamp?
last_delivered_at: timestamp?
last_failed_at: timestamp?
last_opt_out_at: timestamp?
last_reply_at: timestamp?
```
Endpoint quality may be emitted as diagnostics but should not by itself create coordination success.
## 26. Channel Health
`sms-connect` SHOULD expose channel health.
```yaml
SmsChannelHealth:
sender_identity_ref: string
provider_account_ref: string?
country_scope: string?
status: healthy | degraded | failing | unknown
registration_status: registered | pending | rejected | expired | not_required | unknown
route_status: healthy | degraded | unavailable | unknown
deliverability_status: good | warning | poor | unknown
opt_out_rate: number?
failure_rate: number?
unknown_rate: number?
filtering_rate: number?
provider_degradation:
- string
```
Health-related normalized events:
```text
notification.channel.reputation_warning
system.provider.degraded
system.provider.unavailable
system.adapter.health_changed
```
## 27. Security Requirements
`sms-connect` MUST:
* protect provider credentials
* verify provider webhooks where possible
* validate inbound provider event authenticity where possible
* preserve idempotency
* prevent duplicate sends for repeated idempotency keys
* protect opt-out and consent records
* avoid leaking phone numbers in logs where possible
* avoid exposing tracking tokens unnecessarily
* sanitize inbound SMS bodies before processing
* support tenant or sender separation where applicable
## 28. Privacy Requirements
`sms-connect` SHOULD:
* store message content only when necessary
* support metadata-only mode
* support raw event redaction
* support configurable retention of raw provider events
* store endpoint references instead of full phone numbers where possible
* support masking of phone numbers
* support deletion or anonymization workflows
* separate operational diagnostics from coordination evidence
* avoid unnecessary retention of link-click metadata
* allow link tracking to be disabled
## 29. Reliability Requirements
`sms-connect` MUST support:
* idempotent send requests
* duplicate webhook event detection
* out-of-order event handling
* late DLR handling
* retryable provider failures
* non-retryable provider failures
* provider timeout handling
* correlation preservation
* dead-letter handling for unprocessable events
* explicit timeout/expiry handling for missing final DLRs
Late events MUST be preserved.
Example:
```text
Provider accepted at 10:00
No DLR by 12:00
Participant unresolved at 14:00
Delivery receipt arrives at 18:00
```
The late DLR must still be recorded and emitted as evidence.
## 30. Raw Event Preservation
`sms-connect` SHOULD preserve raw provider events or references to them.
```yaml
RawSmsEventRef:
raw_event_id: string
provider_name: string
storage_ref: string?
received_at: timestamp
redacted: boolean
```
Normalized events should reference raw event data where available:
```yaml
raw_event_ref: raw_sms_event_123
```
## 31. Minimal API Surface
`sms-connect` SHOULD expose a headless API.
### 31.1 Adapter Contract API
Required conceptual operations:
```text
GET /adapter/descriptor
GET /adapter/health
POST /adapter/actions
POST /adapter/events/provider
GET /adapter/events
GET /adapter/messages/{id}/timeline
GET /adapter/messages/{id}/assessment
```
The actual transport may differ, but these conceptual operations should exist.
### 31.2 Standalone API
Useful standalone operations:
```text
POST /sms/send
GET /sms/messages/{id}
GET /sms/messages/{id}/timeline
GET /sms/messages/{id}/assessment
GET /sms/endpoints/{id}/quality
POST /sms/suppressions
DELETE /sms/suppressions/{id}
POST /sms/consents
GET /sms/channel-health
GET /sms/content/analyze
```
## 32. Example End-to-End Flows
### 32.1 Secure Document Reminder
1. `coordination-engine` creates a coordination case.
2. Email notification remains unresolved after threshold.
3. Policy engine selects SMS fallback.
4. `coordination-engine` sends `notification.send` to `sms-connect`.
5. `sms-connect` validates consent, suppression, sender identity, content, and segmentation.
6. Provider accepts the SMS.
7. `sms-connect` emits `notification.attempt.accepted_by_provider`.
8. Carrier reports delivery.
9. `sms-connect` emits `notification.endpoint.accepted` with delivered metadata.
10. Recipient clicks link.
11. `sms-connect` emits `interaction.unverified_actor_interaction`.
12. Recipient authenticates in portal.
13. `portal-connect` emits `identity.actor_authenticated`.
14. Recipient downloads document.
15. `portal-connect` emits `delivery.payload.downloaded`.
16. `coordination-engine` marks participant complete.
SMS contributed stronger notification evidence than email, but the portal event closes the result.
### 32.2 Undelivered SMS and Alternate Channel
1. `sms-connect` sends SMS.
2. Provider accepts the message.
3. Carrier returns unknown subscriber.
4. `sms-connect` emits `notification.endpoint.rejected_permanent`.
5. `coordination-engine` marks SMS channel failed for that participant.
6. Policy engine selects alternate channel or manual review.
### 32.3 SMS Acknowledgement
1. `coordination-engine` sends alert via SMS.
2. Carrier reports delivery.
3. Participant replies `ACK`.
4. `sms-connect` emits `interaction.acknowledgement_recorded`.
5. If scenario policy accepts SMS acknowledgement, `coordination-engine` marks the participant as acknowledged.
6. If stronger identity is required, the participant remains incomplete until identity-bound evidence is provided.
### 32.4 Opt-Out Handling
1. Participant replies `STOP`.
2. `sms-connect` records opt-out and adds suppression.
3. `sms-connect` emits `notification.channel.unsubscribe_received` and `notification.channel.suppression_added`.
4. `coordination-engine` updates channel viability.
5. Policy engine selects fallback channel or manual review depending on scenario.
## 33. Provider Implementation Guidance
The first real provider integration SHOULD be selected based on:
* delivery receipt quality
* clear status callbacks
* error-code detail
* inbound SMS support
* opt-out handling support
* sender identity support
* country coverage
* webhook security
* correlation metadata support
* cost and local availability
* compatibility with transactional and high-assurance notifications
The implementation SHOULD avoid hardcoding provider semantics into the core SMS model.
Provider-specific modules should map to the SMS-native model first, then to normalized coordination events.
```text
Provider event
→ sms-native event
→ SmsEvidenceAssessment
→ EvidenceEvent for coordination-engine
```
## 34. Message Stream Separation
`sms-connect` SHOULD support sender identities, campaign scopes, and message streams.
Recommended streams:
```text
transactional
notification
legal_or_high_assurance_notice
marketing
verification
system_alert
test
```
High-assurance or legally relevant notifications SHOULD NOT share th sender configuration with marketing traffic unless explicitly accepted by policy.
Stream separation may affect:
* sender number
* sender pool
* short code
* toll-free number
* alphanumeric sender ID
* campaign registration
* consent scope
* opt-out scope
* throughput
* carrier filtering risk
* delivery diagnostics
## 35. Legal and Compliance Disclaimer
`sms-connect` does not by itself provide legal proof of delivery, legal notice, acceptance, signature, payment, or contract closure.
It provides evidence from the SMS channel.
Scenario-specific applications and `coordination-engine` policies may combine SMS evidence with stronger evidence from portal, identity, signature, payment, archive, or manual processes.
The adapter MUST avoid naming technical SMS events in ways that imply legal success.
Use:
```text
notification.endpoint.accepted
```
Avoid:
```text
recipient_legally_notified
delivery_legally_completed
human_read_confirmed
```
## 36. MVP Scope
The first useful version of `sms-connect` should implement:
1. Adapter descriptor.
2. Adapter health endpoint.
3. `notification.send`.
4. Idempotent send request handling.
5. Simulated provider or one real provider.
6. SMS message and attempt records.
7. Provider event ingestion.
8. Basic delivery receipt classification.
9. Basic phone endpoint validation.
10. Basic segmentation and encoding analysis.
11. Basic opt-out/suppression support.
12. Basic inbound reply support if provider allows.
13. Evidence event generation.
14. Message timeline.
15. Message assessment.
16. Mapping to AdapterInterfaceSpecification.md v1.0.
### MVP Required SMS Events
```text
notification.attempt.accepted_by_adapter
notification.attempt.rejected_by_adapter
notification.attempt.accepted_by_provider
notification.attempt.rejected_by_provider
notification.attempt.queued
notification.endpoint.accepted
notification.endpoint.deferred
notification.endpoint.rejected_temporary
notification.endpoint.rejected_permanent
notification.endpoint.unknown
notification.channel.unsubscribe_received
notification.channel.suppression_added
interaction.reply_received
interaction.acknowledgement_recorded
interaction.unverified_actor_interaction
```
### MVP Acceptance Criteria
The MVP is acceptable when it can:
1. Accept a coordination-compatible SMS send request.
2. Dispatch or simulate an SMS.
3. Preserve correlation and idempotency.
4. Ingest or simulate provider delivery receipts.
5. Produce normalized evidence events.
6. Classify provider acceptance as weak evidence.
7. Classify delivered DLR as strong endpoint evidence but not human-awareness proof.
8. Classify final undelivered/failed/rejected states as negative channel evidence.
9. Classify unknown/no-DLR cases as unresolved.
10. Record STOP/opt-out as suppression evidence.
11. Record inbound replies as interaction evidence.
12. Provide a message timeline.
13. Provide an SMS evidence assessment.
14. Integrate with coordination-engine without overclaiming success.
## 37. Future Extensions
Potential future capabilities:
* multi-provider routing
* provider failover
* country-specific routing rules
* sender pool optimization
* throughput management
* advanced number lookup
* number reassignment risk detection
* HLR or carrier lookup integration where lawful and available
* advanced opt-in/opt-out workflow
* advanced keyword routing
* two-way conversational SMS support
* natural-language reply classification
* URL shortening and tracking integration
* adaptive fallback between email, SMS, push, and voice
* RCS adapter extension or separate `rcs-connect`
* MMS support
* WhatsApp or messaging-app adapters
* regulatory diagnostics by country
* A2P registration diagnostics
* carrier filtering risk scoring
* cost forecasting by segment count and country
* consent evidence archive integration
## 38. Non-Goals
`sms-connect` is not:
* a marketing automation platform
* a full conversational messaging platform
* a CRM
* a full workflow engine
* a legal notice system by itself
* a payment system
* a signature system
* an identity verification system by itself
* the owner of coordination case success
It may integrate with such systems or be used by them.
## 39. Summary
`sms-connect` models SMS as a useful but still uncertain notification, reminder, and lightweight interaction channel.
Its job is to:
* send SMS messages
* ingest provider and carrier delivery receipts
* classify SMS outcomes
* normalize SMS evidence
* manage opt-out and suppression state
* record inbound replies
* analyze content, encoding, and segmentation
* expose endpoint and channel diagnostics
* integrate cleanly with `coordination-engine`
The key rule is:
> SMS events are evidence, not result satisfaction. sms-connect reports SMS-channel facts and uncertainty. coordination-engine evaluates intended results.
[1]: https://help.twilio.com/articles/223134347-What-are-the-Possible-SMS-and-MMS-Message-Statuses-and-What-do-They-Mean-?utm_source=chatgpt.com "What are the possible SMS and MMS message statuses ..."
[2]: https://developer.vonage.com/en/messaging/sms/guides/delivery-receipts?utm_source=chatgpt.com "SMS Delivery Receipts API Guide"
[3]: https://developers.sinch.com/docs/sms/api-reference/sms/delivery-reports/deliveryreport?utm_source=chatgpt.com "Delivery Report"
[4]: https://www.twilio.com/docs/glossary/what-sms-character-limit?utm_source=chatgpt.com "How long can a message be? | Twilio"
[5]: https://www.twilio.com/docs/messaging/tutorials/advanced-opt-out?utm_source=chatgpt.com "Customize users' opt-in and opt-out experience with ..."