1992 lines
48 KiB
Markdown
1992 lines
48 KiB
Markdown
|
|
# AdapterInterfaceSpecification.md
|
|||
|
|
|
|||
|
|
## 1. Document Status
|
|||
|
|
|
|||
|
|
**Document:** AdapterInterfaceSpecification.md
|
|||
|
|
**Project:** coordination-engine
|
|||
|
|
**Version:** 1.1
|
|||
|
|
**Status:** Updated Draft
|
|||
|
|
**Scope:** Contract between coordination-engine and external adapters
|
|||
|
|
**Primary Reference Adapters:** email-connect, sms-connect, rss-connect, xmpp-connect, hybridmail-connect
|
|||
|
|
|
|||
|
|
## 2. Version 1.1 Change Summary
|
|||
|
|
|
|||
|
|
Version 1.1 extends the original adapter interface based on concrete adapter design work for:
|
|||
|
|
|
|||
|
|
* Email
|
|||
|
|
* SMS
|
|||
|
|
* RSS / Atom / WebSub
|
|||
|
|
* XMPP
|
|||
|
|
* Hybrid Mail
|
|||
|
|
|
|||
|
|
The main changes are:
|
|||
|
|
|
|||
|
|
1. Added `AdapterCapabilityProfile`.
|
|||
|
|
2. Added `EvidenceCeiling`.
|
|||
|
|
3. Added `NativeStatusMapping` / `NativeEventSemantics`.
|
|||
|
|
4. Added universal weakest-safe-mapping rule.
|
|||
|
|
5. Added `AdapterEvidenceAssessment`.
|
|||
|
|
6. Added `EndpointQuality`.
|
|||
|
|
7. Added `LateEventPolicy`.
|
|||
|
|
8. Added `EventObservation`.
|
|||
|
|
9. Added `FeatureDependency`.
|
|||
|
|
10. Added `AssuranceCapability`.
|
|||
|
|
11. Added adapter conformance levels.
|
|||
|
|
12. Added golden test requirements.
|
|||
|
|
13. Strengthened semantic underclaiming requirements.
|
|||
|
|
14. Clarified that adapters provide evidence, not coordination-result truth.
|
|||
|
|
|
|||
|
|
## 3. Purpose
|
|||
|
|
|
|||
|
|
This document defines the adapter interface contract between `coordination-engine` and external adapter components such as:
|
|||
|
|
|
|||
|
|
* `email-connect`
|
|||
|
|
* `sms-connect`
|
|||
|
|
* `rss-connect`
|
|||
|
|
* `xmpp-connect`
|
|||
|
|
* `hybridmail-connect`
|
|||
|
|
* `push-connect`
|
|||
|
|
* `portal-connect`
|
|||
|
|
* `payment-connect`
|
|||
|
|
* `signature-connect`
|
|||
|
|
* `document-connect`
|
|||
|
|
* `identity-connect`
|
|||
|
|
* future adapters
|
|||
|
|
|
|||
|
|
The adapter interface allows `coordination-engine` to remain protocol-neutral while integrating with concrete technologies, providers, systems, and communication channels.
|
|||
|
|
|
|||
|
|
Adapters translate between external systems and the internal coordination model by:
|
|||
|
|
|
|||
|
|
1. Declaring capabilities.
|
|||
|
|
2. Declaring evidence ceilings.
|
|||
|
|
3. Accepting action requests.
|
|||
|
|
4. Returning action results.
|
|||
|
|
5. Preserving native events.
|
|||
|
|
6. Mapping native events conservatively.
|
|||
|
|
7. Emitting normalized evidence events.
|
|||
|
|
8. Providing advisory evidence assessments.
|
|||
|
|
9. Exposing endpoint quality and adapter health.
|
|||
|
|
10. Preserving correlation between coordination cases and external provider events.
|
|||
|
|
|
|||
|
|
The goal of this specification is to ensure that adapters are independently useful components while still being compatible with `coordination-engine`.
|
|||
|
|
|
|||
|
|
## 4. Core Design Principle
|
|||
|
|
|
|||
|
|
Adapters are not merely transport drivers.
|
|||
|
|
|
|||
|
|
An adapter is a capability component that can perform actions, observe signals, preserve native events, classify evidence, and expose its own limitations.
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Adapter =
|
|||
|
|
Capability Descriptor
|
|||
|
|
+ Action Provider
|
|||
|
|
+ Signal Provider
|
|||
|
|
+ Evidence Normalizer
|
|||
|
|
+ Evidence Ceiling Declaration
|
|||
|
|
+ Health / Diagnostics Provider
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The coordination engine remains responsible for:
|
|||
|
|
|
|||
|
|
* coordination case lifecycle
|
|||
|
|
* result evaluation
|
|||
|
|
* participant state derivation
|
|||
|
|
* policy decisions
|
|||
|
|
* follow-up decisions
|
|||
|
|
* uncertainty handling
|
|||
|
|
* case-level success/failure/expiry/escalation
|
|||
|
|
* final interpretation of adapter evidence
|
|||
|
|
|
|||
|
|
The adapter remains responsible for:
|
|||
|
|
|
|||
|
|
* provider-specific integration
|
|||
|
|
* protocol-specific action execution
|
|||
|
|
* native event ingestion
|
|||
|
|
* native event preservation
|
|||
|
|
* native-to-normalized event mapping
|
|||
|
|
* adapter-level evidence assessment
|
|||
|
|
* adapter-specific diagnostics
|
|||
|
|
* provider-level correlation
|
|||
|
|
* adapter health reporting
|
|||
|
|
* explicit limitation reporting
|
|||
|
|
|
|||
|
|
## 5. Semantic Underclaiming Rule
|
|||
|
|
|
|||
|
|
Adapters MUST underclaim rather than overclaim.
|
|||
|
|
|
|||
|
|
If a native event or provider status is ambiguous, the adapter MUST map it to the weakest semantically safe normalized event and preserve the raw native event or status in metadata.
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Email provider "delivered"
|
|||
|
|
→ notification.endpoint.accepted
|
|||
|
|
→ not recipient awareness
|
|||
|
|
|
|||
|
|
SMS provider "delivered"
|
|||
|
|
→ notification.endpoint.accepted with delivery-receipt metadata
|
|||
|
|
→ not human read confirmation
|
|||
|
|
|
|||
|
|
RSS item "published"
|
|||
|
|
→ feed.item.published
|
|||
|
|
→ not participant awareness
|
|||
|
|
|
|||
|
|
XMPP stream acknowledgement
|
|||
|
|
→ notification.attempt.accepted_by_provider
|
|||
|
|
→ not client delivery
|
|||
|
|
|
|||
|
|
Hybrid mail "sent"
|
|||
|
|
→ delivery.payload.submitted or delivery.postal.handed_over only if semantics prove handover
|
|||
|
|
→ not delivery confirmation
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The central rule is:
|
|||
|
|
|
|||
|
|
> Adapters report what happened and what it may mean. coordination-engine decides what it means for the coordination case.
|
|||
|
|
|
|||
|
|
## 6. Boundary Between coordination-engine and Adapters
|
|||
|
|
|
|||
|
|
### 6.1 coordination-engine Owns
|
|||
|
|
|
|||
|
|
`coordination-engine` owns:
|
|||
|
|
|
|||
|
|
* `CoordinationCase`
|
|||
|
|
* `Participant`
|
|||
|
|
* `IntendedResult`
|
|||
|
|
* case-level state
|
|||
|
|
* participant-level state
|
|||
|
|
* result predicates
|
|||
|
|
* policy evaluation
|
|||
|
|
* next-action selection
|
|||
|
|
* evidence ledger
|
|||
|
|
* adapter selection
|
|||
|
|
* scenario-specific orchestration
|
|||
|
|
* closure, failure, expiry, escalation, and manual override
|
|||
|
|
|
|||
|
|
### 6.2 Adapters Own
|
|||
|
|
|
|||
|
|
Adapters own:
|
|||
|
|
|
|||
|
|
* provider communication
|
|||
|
|
* protocol-specific execution
|
|||
|
|
* provider credentials and configuration
|
|||
|
|
* native event ingestion
|
|||
|
|
* provider-native identifiers
|
|||
|
|
* native status interpretation
|
|||
|
|
* native-to-normalized event mapping
|
|||
|
|
* adapter-specific retries where appropriate
|
|||
|
|
* adapter-specific diagnostics
|
|||
|
|
* adapter health
|
|||
|
|
* adapter-native evidence assessment
|
|||
|
|
|
|||
|
|
### 6.3 Shared Contract
|
|||
|
|
|
|||
|
|
The shared contract consists of:
|
|||
|
|
|
|||
|
|
* `AdapterDescriptor`
|
|||
|
|
* `AdapterCapabilityProfile`
|
|||
|
|
* `AdapterActionCapability`
|
|||
|
|
* `AdapterActionRequest`
|
|||
|
|
* `AdapterActionResult`
|
|||
|
|
* `AdapterEvent`
|
|||
|
|
* `EvidenceEvent`
|
|||
|
|
* `AdapterEvidenceAssessment`
|
|||
|
|
* `EvidenceGrade`
|
|||
|
|
* `EvidenceCeiling`
|
|||
|
|
* `NativeStatusMapping`
|
|||
|
|
* `NativeEventSemantics`
|
|||
|
|
* `EndpointQuality`
|
|||
|
|
* `AdapterHealth`
|
|||
|
|
* `CorrelationContext`
|
|||
|
|
* `ErrorDescriptor`
|
|||
|
|
* `LateEventPolicy`
|
|||
|
|
* `FeatureDependency`
|
|||
|
|
* `AssuranceCapability`
|
|||
|
|
* `AdapterGoldenTest`
|
|||
|
|
|
|||
|
|
## 7. Adapter Types
|
|||
|
|
|
|||
|
|
An adapter may belong to one or more adapter types.
|
|||
|
|
|
|||
|
|
Recommended canonical adapter types:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
notification
|
|||
|
|
communication
|
|||
|
|
publication
|
|||
|
|
access
|
|||
|
|
delivery
|
|||
|
|
interaction
|
|||
|
|
identity
|
|||
|
|
authority
|
|||
|
|
payment
|
|||
|
|
signature
|
|||
|
|
document
|
|||
|
|
archive
|
|||
|
|
crm
|
|||
|
|
erp
|
|||
|
|
webhook
|
|||
|
|
feed
|
|||
|
|
system
|
|||
|
|
manual
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
| Adapter repo | Likely adapter types |
|
|||
|
|
| -------------------- | ---------------------------------------------- |
|
|||
|
|
| `email-connect` | notification, communication, interaction |
|
|||
|
|
| `sms-connect` | notification, communication, interaction |
|
|||
|
|
| `rss-connect` | publication, feed, notification |
|
|||
|
|
| `xmpp-connect` | notification, communication, interaction, feed |
|
|||
|
|
| `hybridmail-connect` | delivery, communication, document, archive |
|
|||
|
|
| `portal-connect` | access, delivery, interaction, identity |
|
|||
|
|
| `payment-connect` | payment, interaction, delivery |
|
|||
|
|
| `signature-connect` | signature, identity, authority, delivery |
|
|||
|
|
| `identity-connect` | identity, authority |
|
|||
|
|
| `webhook-connect` | system, delivery, interaction |
|
|||
|
|
|
|||
|
|
Adapter type is descriptive, not exclusive.
|
|||
|
|
|
|||
|
|
## 8. Normative Language
|
|||
|
|
|
|||
|
|
The following terms are used in this specification:
|
|||
|
|
|
|||
|
|
* **MUST** means required for contract compliance.
|
|||
|
|
* **SHOULD** means recommended unless a documented reason exists.
|
|||
|
|
* **MAY** means optional.
|
|||
|
|
* **MUST NOT** means prohibited for contract compliance.
|
|||
|
|
|
|||
|
|
## 9. Core Interface Objects
|
|||
|
|
|
|||
|
|
## 9.1 AdapterDescriptor
|
|||
|
|
|
|||
|
|
An `AdapterDescriptor` declares the identity, version, capabilities, event support, evidence profile, and operational characteristics of an adapter.
|
|||
|
|
|
|||
|
|
Adapters MUST expose a descriptor.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterDescriptor:
|
|||
|
|
adapter_id: string
|
|||
|
|
adapter_name: string
|
|||
|
|
adapter_version: string
|
|||
|
|
adapter_contract_version: string
|
|||
|
|
adapter_types:
|
|||
|
|
- string
|
|||
|
|
provider_family: string?
|
|||
|
|
provider_name: string?
|
|||
|
|
deployment_mode: embedded | sidecar | external | unknown
|
|||
|
|
capability_profile: AdapterCapabilityProfile
|
|||
|
|
supported_actions:
|
|||
|
|
- AdapterActionCapability
|
|||
|
|
emitted_event_types:
|
|||
|
|
- string
|
|||
|
|
supported_channels:
|
|||
|
|
- string
|
|||
|
|
supported_endpoint_types:
|
|||
|
|
- string
|
|||
|
|
evidence_profile: AdapterEvidenceProfile
|
|||
|
|
evidence_ceiling: EvidenceCeiling
|
|||
|
|
assurance_capability: AssuranceCapability
|
|||
|
|
identity_profile: AdapterIdentityProfile
|
|||
|
|
late_event_policy: LateEventPolicy
|
|||
|
|
feature_dependencies:
|
|||
|
|
- FeatureDependency
|
|||
|
|
latency_profile: AdapterLatencyProfile?
|
|||
|
|
cost_profile: AdapterCostProfile?
|
|||
|
|
reliability_profile: AdapterReliabilityProfile?
|
|||
|
|
configuration_schema_ref: string?
|
|||
|
|
native_status_mapping_ref: string?
|
|||
|
|
golden_tests_ref: string?
|
|||
|
|
health_endpoint_ref: string?
|
|||
|
|
documentation_ref: string?
|
|||
|
|
limitations:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Required Fields
|
|||
|
|
|
|||
|
|
The following fields are REQUIRED:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
adapter_id
|
|||
|
|
adapter_name
|
|||
|
|
adapter_version
|
|||
|
|
adapter_contract_version
|
|||
|
|
adapter_types
|
|||
|
|
capability_profile
|
|||
|
|
supported_actions
|
|||
|
|
emitted_event_types
|
|||
|
|
supported_channels
|
|||
|
|
supported_endpoint_types
|
|||
|
|
evidence_profile
|
|||
|
|
evidence_ceiling
|
|||
|
|
assurance_capability
|
|||
|
|
identity_profile
|
|||
|
|
late_event_policy
|
|||
|
|
limitations
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.2 AdapterCapabilityProfile
|
|||
|
|
|
|||
|
|
An `AdapterCapabilityProfile` declares what the adapter can do, observe, and never prove.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterCapabilityProfile:
|
|||
|
|
can_notify: boolean
|
|||
|
|
can_publish: boolean
|
|||
|
|
can_deliver_payload: boolean
|
|||
|
|
can_collect_payload: boolean
|
|||
|
|
can_grant_access: boolean
|
|||
|
|
can_revoke_access: boolean
|
|||
|
|
can_observe_interaction: boolean
|
|||
|
|
can_observe_identity: boolean
|
|||
|
|
can_observe_authority: boolean
|
|||
|
|
can_emit_delivery_receipts: boolean
|
|||
|
|
can_emit_display_or_read_receipts: boolean
|
|||
|
|
can_emit_return_or_failure_events: boolean
|
|||
|
|
can_emit_late_events: boolean
|
|||
|
|
can_cancel_after_dispatch: boolean
|
|||
|
|
supports_webhooks: boolean
|
|||
|
|
supports_polling: boolean
|
|||
|
|
supports_idempotency: native | adapter_managed | none | unknown
|
|||
|
|
supports_endpoint_quality: boolean
|
|||
|
|
supports_native_status_mapping: boolean
|
|||
|
|
supports_golden_tests: boolean
|
|||
|
|
limitations:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Example: email-connect
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterCapabilityProfile:
|
|||
|
|
can_notify: true
|
|||
|
|
can_publish: false
|
|||
|
|
can_deliver_payload: false
|
|||
|
|
can_collect_payload: false
|
|||
|
|
can_grant_access: false
|
|||
|
|
can_revoke_access: false
|
|||
|
|
can_observe_interaction: true
|
|||
|
|
can_observe_identity: false
|
|||
|
|
can_observe_authority: false
|
|||
|
|
can_emit_delivery_receipts: false
|
|||
|
|
can_emit_display_or_read_receipts: false
|
|||
|
|
can_emit_return_or_failure_events: true
|
|||
|
|
can_emit_late_events: true
|
|||
|
|
can_cancel_after_dispatch: false
|
|||
|
|
supports_webhooks: true
|
|||
|
|
supports_polling: false
|
|||
|
|
supports_idempotency: adapter_managed
|
|||
|
|
supports_endpoint_quality: true
|
|||
|
|
supports_native_status_mapping: true
|
|||
|
|
supports_golden_tests: true
|
|||
|
|
limitations:
|
|||
|
|
- Recipient mail server acceptance does not prove inbox placement.
|
|||
|
|
- Open and click tracking are ambiguous.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Example: hybridmail-connect
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterCapabilityProfile:
|
|||
|
|
can_notify: false
|
|||
|
|
can_publish: false
|
|||
|
|
can_deliver_payload: true
|
|||
|
|
can_collect_payload: false
|
|||
|
|
can_grant_access: false
|
|||
|
|
can_revoke_access: false
|
|||
|
|
can_observe_interaction: false
|
|||
|
|
can_observe_identity: false
|
|||
|
|
can_observe_authority: false
|
|||
|
|
can_emit_delivery_receipts: true
|
|||
|
|
can_emit_display_or_read_receipts: false
|
|||
|
|
can_emit_return_or_failure_events: true
|
|||
|
|
can_emit_late_events: true
|
|||
|
|
can_cancel_after_dispatch: false
|
|||
|
|
supports_webhooks: true
|
|||
|
|
supports_polling: true
|
|||
|
|
supports_idempotency: adapter_managed
|
|||
|
|
supports_endpoint_quality: true
|
|||
|
|
supports_native_status_mapping: true
|
|||
|
|
supports_golden_tests: true
|
|||
|
|
limitations:
|
|||
|
|
- Postal handover does not prove recipient reading.
|
|||
|
|
- Ordinary letters often do not provide final delivery confirmation.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.3 EvidenceCeiling
|
|||
|
|
|
|||
|
|
An `EvidenceCeiling` declares the strongest evidence the adapter can provide under its configured capabilities.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
EvidenceCeiling:
|
|||
|
|
max_positive_event: string
|
|||
|
|
max_positive_strength: none | weak | medium | strong | conclusive | unknown
|
|||
|
|
can_prove_human_awareness: boolean | partially
|
|||
|
|
can_prove_payload_access: boolean | partially
|
|||
|
|
can_prove_payload_delivery: boolean | partially
|
|||
|
|
can_prove_identity: boolean | partially
|
|||
|
|
can_prove_authority: boolean | partially
|
|||
|
|
can_prove_non_repudiation: boolean | partially
|
|||
|
|
conditions:
|
|||
|
|
- string
|
|||
|
|
limitations:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Examples
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
email:
|
|||
|
|
max_positive_event: interaction.unverified_actor_interaction
|
|||
|
|
max_positive_strength: medium
|
|||
|
|
can_prove_human_awareness: false
|
|||
|
|
can_prove_payload_access: false
|
|||
|
|
can_prove_payload_delivery: false
|
|||
|
|
can_prove_identity: false
|
|||
|
|
can_prove_authority: false
|
|||
|
|
can_prove_non_repudiation: false
|
|||
|
|
limitations:
|
|||
|
|
- Email tracking cannot reliably prove intended-recipient awareness.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
sms:
|
|||
|
|
max_positive_event: notification.endpoint.accepted
|
|||
|
|
max_positive_strength: strong
|
|||
|
|
can_prove_human_awareness: false
|
|||
|
|
can_prove_payload_access: false
|
|||
|
|
can_prove_payload_delivery: false
|
|||
|
|
can_prove_identity: false
|
|||
|
|
can_prove_authority: false
|
|||
|
|
can_prove_non_repudiation: false
|
|||
|
|
conditions:
|
|||
|
|
- Strongest evidence depends on carrier delivery receipts.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
xmpp_with_display_markers:
|
|||
|
|
max_positive_event: interaction.notification.opened
|
|||
|
|
max_positive_strength: strong
|
|||
|
|
can_prove_human_awareness: partially
|
|||
|
|
can_prove_payload_access: false
|
|||
|
|
can_prove_payload_delivery: false
|
|||
|
|
can_prove_identity: partially
|
|||
|
|
can_prove_authority: false
|
|||
|
|
can_prove_non_repudiation: false
|
|||
|
|
conditions:
|
|||
|
|
- Requires client support for displayed markers.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
hybridmail_registered:
|
|||
|
|
max_positive_event: delivery.postal.delivery_confirmed
|
|||
|
|
max_positive_strength: strong
|
|||
|
|
can_prove_human_awareness: false
|
|||
|
|
can_prove_payload_access: partially
|
|||
|
|
can_prove_payload_delivery: partially
|
|||
|
|
can_prove_identity: false
|
|||
|
|
can_prove_authority: false
|
|||
|
|
can_prove_non_repudiation: partially
|
|||
|
|
conditions:
|
|||
|
|
- Requires registered or delivery-confirmation postal product.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.4 AssuranceCapability
|
|||
|
|
|
|||
|
|
`AssuranceCapability` allows coordination-engine to compare adapter capabilities against scenario assurance requirements.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AssuranceCapability:
|
|||
|
|
awareness_assurance: none | weak | medium | strong | conclusive | conditional | unknown
|
|||
|
|
delivery_assurance: none | weak | medium | strong | conclusive | conditional | unknown
|
|||
|
|
identity_assurance: none | weak | medium | strong | conclusive | conditional | unknown
|
|||
|
|
authority_assurance: none | weak | medium | strong | conclusive | conditional | unknown
|
|||
|
|
non_repudiation_assurance: none | weak | medium | strong | conclusive | conditional | unknown
|
|||
|
|
conditions:
|
|||
|
|
- string
|
|||
|
|
limitations:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Example:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
email:
|
|||
|
|
awareness_assurance: weak
|
|||
|
|
delivery_assurance: none
|
|||
|
|
identity_assurance: none
|
|||
|
|
authority_assurance: none
|
|||
|
|
non_repudiation_assurance: none
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
portal:
|
|||
|
|
awareness_assurance: strong
|
|||
|
|
delivery_assurance: strong
|
|||
|
|
identity_assurance: strong
|
|||
|
|
authority_assurance: conditional
|
|||
|
|
non_repudiation_assurance: medium
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.5 AdapterActionCapability
|
|||
|
|
|
|||
|
|
An `AdapterActionCapability` declares one action an adapter can perform.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterActionCapability:
|
|||
|
|
action_type: string
|
|||
|
|
description: string?
|
|||
|
|
mode: sync | async | scheduled
|
|||
|
|
idempotency_required: boolean
|
|||
|
|
required_fields:
|
|||
|
|
- string
|
|||
|
|
optional_fields:
|
|||
|
|
- string
|
|||
|
|
supported_channels:
|
|||
|
|
- string
|
|||
|
|
supported_endpoint_types:
|
|||
|
|
- string
|
|||
|
|
preconditions:
|
|||
|
|
- string
|
|||
|
|
postconditions:
|
|||
|
|
- string
|
|||
|
|
capability_dependencies:
|
|||
|
|
- string
|
|||
|
|
unsupported_when:
|
|||
|
|
- string
|
|||
|
|
expected_initial_events:
|
|||
|
|
- string
|
|||
|
|
possible_later_events:
|
|||
|
|
- string
|
|||
|
|
known_failure_modes:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Action Type Naming
|
|||
|
|
|
|||
|
|
Action types SHOULD use dotted semantic names.
|
|||
|
|
|
|||
|
|
Recommended families:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
notification.*
|
|||
|
|
publication.*
|
|||
|
|
access.*
|
|||
|
|
delivery.*
|
|||
|
|
interaction.*
|
|||
|
|
identity.*
|
|||
|
|
authority.*
|
|||
|
|
payment.*
|
|||
|
|
signature.*
|
|||
|
|
document.*
|
|||
|
|
archive.*
|
|||
|
|
feed.*
|
|||
|
|
webhook.*
|
|||
|
|
recipient.*
|
|||
|
|
system.*
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
notification.send
|
|||
|
|
notification.send_reminder
|
|||
|
|
publication.publish
|
|||
|
|
access.grant
|
|||
|
|
access.revoke
|
|||
|
|
delivery.submit_payload
|
|||
|
|
delivery.submit_letter
|
|||
|
|
delivery.request_submission
|
|||
|
|
payment.create_request
|
|||
|
|
payment.cancel_request
|
|||
|
|
signature.create_envelope
|
|||
|
|
signature.cancel_envelope
|
|||
|
|
feed.publish_item
|
|||
|
|
recipient.suppress
|
|||
|
|
recipient.unsuppress
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.6 AdapterActionRequest
|
|||
|
|
|
|||
|
|
An `AdapterActionRequest` is a command from `coordination-engine` to an adapter.
|
|||
|
|
|
|||
|
|
Adapters MUST accept action requests in this conceptual shape, even if transport-specific serialization differs.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterActionRequest:
|
|||
|
|
request_id: string
|
|||
|
|
action_type: string
|
|||
|
|
coordination_case_id: string
|
|||
|
|
participant_id: string?
|
|||
|
|
payload_ref: ResourceRef?
|
|||
|
|
action_surface_ref: ActionSurfaceRef?
|
|||
|
|
channel: string?
|
|||
|
|
target_endpoint: EndpointRef?
|
|||
|
|
actor_context: ActorContext?
|
|||
|
|
content: ActionContent?
|
|||
|
|
template_ref: string?
|
|||
|
|
variables: object?
|
|||
|
|
tracking_context: TrackingContext
|
|||
|
|
policy_context: PolicyContext?
|
|||
|
|
security_context: SecurityContext?
|
|||
|
|
idempotency_key: string
|
|||
|
|
requested_at: timestamp
|
|||
|
|
expires_at: timestamp?
|
|||
|
|
metadata: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Required Fields
|
|||
|
|
|
|||
|
|
The following fields are REQUIRED:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
request_id
|
|||
|
|
action_type
|
|||
|
|
coordination_case_id
|
|||
|
|
tracking_context
|
|||
|
|
idempotency_key
|
|||
|
|
requested_at
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Fields such as `participant_id`, `payload_ref`, `target_endpoint`, or `action_surface_ref` may be optional for system-level, broadcast, or publication actions, but adapters MAY require them for specific action types.
|
|||
|
|
|
|||
|
|
## 9.7 Idempotency
|
|||
|
|
|
|||
|
|
`idempotency_key` MUST be provided for all externally visible actions.
|
|||
|
|
|
|||
|
|
Adapters MUST treat repeated action requests with the same `idempotency_key` as duplicates of the same logical request.
|
|||
|
|
|
|||
|
|
Adapters SHOULD return the original or current action result for duplicate requests.
|
|||
|
|
|
|||
|
|
For irreversible or expensive side-effect actions, such as hybrid-mail physical dispatch or payment creation, adapters MUST implement strict duplicate prevention.
|
|||
|
|
|
|||
|
|
If the same idempotency key is used with conflicting request content, the adapter MUST return an idempotency conflict.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
IdempotencyConflict:
|
|||
|
|
idempotency_key: string
|
|||
|
|
original_request_ref: string
|
|||
|
|
conflicting_request_ref: string
|
|||
|
|
conflict_fields:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.8 TrackingContext
|
|||
|
|
|
|||
|
|
`tracking_context` MUST contain enough information to correlate later adapter events back to the coordination case.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
TrackingContext:
|
|||
|
|
correlation_id: string
|
|||
|
|
coordination_case_id: string
|
|||
|
|
participant_id: string?
|
|||
|
|
notification_id: string?
|
|||
|
|
delivery_id: string?
|
|||
|
|
interaction_id: string?
|
|||
|
|
payload_id: string?
|
|||
|
|
action_surface_id: string?
|
|||
|
|
external_context:
|
|||
|
|
- key: string
|
|||
|
|
value: string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Adapters MUST preserve correlation identifiers where technically possible.
|
|||
|
|
|
|||
|
|
Adapters SHOULD include correlation identifiers in outbound provider metadata, message headers, webhook metadata, URLs, tokens, provider custom arguments, or provider-specific reference fields when supported.
|
|||
|
|
|
|||
|
|
## 9.9 EndpointRef
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
EndpointRef:
|
|||
|
|
endpoint_id: string?
|
|||
|
|
endpoint_type: string
|
|||
|
|
value: string?
|
|||
|
|
display_name: string?
|
|||
|
|
verified: boolean?
|
|||
|
|
metadata: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Examples of `endpoint_type`:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
email_address
|
|||
|
|
phone_number
|
|||
|
|
push_token
|
|||
|
|
xmpp_jid
|
|||
|
|
rss_feed
|
|||
|
|
atom_feed
|
|||
|
|
webhook_url
|
|||
|
|
portal_account
|
|||
|
|
payment_account
|
|||
|
|
signature_recipient
|
|||
|
|
api_client
|
|||
|
|
postal_address
|
|||
|
|
physical_address
|
|||
|
|
muc_room_jid
|
|||
|
|
pubsub_node
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.10 EndpointQuality
|
|||
|
|
|
|||
|
|
Adapters SHOULD expose endpoint quality where meaningful.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
EndpointQuality:
|
|||
|
|
endpoint_ref: EndpointRef
|
|||
|
|
endpoint_type: string
|
|||
|
|
validity: valid | invalid | suspected_invalid | unknown
|
|||
|
|
reachability: reachable | unreachable | degraded | unknown
|
|||
|
|
verification_state: unverified | syntax_validated | provider_verified | recently_successful | failed | unknown
|
|||
|
|
suppression_state: active | suppressed | blocked | opted_out | unknown
|
|||
|
|
last_success_at: timestamp?
|
|||
|
|
last_failure_at: timestamp?
|
|||
|
|
quality_signals:
|
|||
|
|
- string
|
|||
|
|
confidence: low | medium | high
|
|||
|
|
adapter_specific:
|
|||
|
|
email: object?
|
|||
|
|
sms: object?
|
|||
|
|
rss: object?
|
|||
|
|
xmpp: object?
|
|||
|
|
hybridmail: object?
|
|||
|
|
other: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Examples of adapter-specific quality signals:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
email: mx_exists, hard_bounce_history, catch_all_suspected
|
|||
|
|
sms: e164_valid, number_type, carrier, opt_out_state
|
|||
|
|
rss: feed_valid, last_fetch_observed, cache_status
|
|||
|
|
xmpp: presence_state, roster_state, resource_known
|
|||
|
|
hybridmail: address_valid, address_position_valid, return_history
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.11 ActionSurfaceRef
|
|||
|
|
|
|||
|
|
Adapters often point participants toward action surfaces rather than completing results themselves.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
ActionSurfaceRef:
|
|||
|
|
action_surface_id: string
|
|||
|
|
action_surface_type: portal | payment_page | signature_flow | upload_form | api_endpoint | physical_letter | chat_command | feed_item | other
|
|||
|
|
uri: string?
|
|||
|
|
requires_authentication: boolean?
|
|||
|
|
expected_interactions:
|
|||
|
|
- string
|
|||
|
|
metadata: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Adapters SHOULD include `action_surface_ref` when the action contains a link, command, form, payment flow, signature flow, or physical action prompt.
|
|||
|
|
|
|||
|
|
## 9.12 ActionContent
|
|||
|
|
|
|||
|
|
`ActionContent` represents content or content references.
|
|||
|
|
|
|||
|
|
Adapters SHOULD prefer references over large inline content where possible.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
ActionContent:
|
|||
|
|
content_ref: string?
|
|||
|
|
subject: string?
|
|||
|
|
body_text: string?
|
|||
|
|
body_html: string?
|
|||
|
|
payload_refs:
|
|||
|
|
- ResourceRef
|
|||
|
|
action_links:
|
|||
|
|
- ActionLink
|
|||
|
|
attachments:
|
|||
|
|
- ResourceRef
|
|||
|
|
inline_data: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.13 ResourceRef
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
ResourceRef:
|
|||
|
|
ref_type: string
|
|||
|
|
ref_id: string
|
|||
|
|
uri: string?
|
|||
|
|
version: string?
|
|||
|
|
integrity_hash: string?
|
|||
|
|
metadata: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.14 ActionLink
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
ActionLink:
|
|||
|
|
link_id: string
|
|||
|
|
purpose: string
|
|||
|
|
url: string
|
|||
|
|
expires_at: timestamp?
|
|||
|
|
tokenized: boolean?
|
|||
|
|
requires_authentication: boolean?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.15 AdapterActionResult
|
|||
|
|
|
|||
|
|
An `AdapterActionResult` is the adapter’s response to an action request.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterActionResult:
|
|||
|
|
request_id: string
|
|||
|
|
adapter_id: string
|
|||
|
|
accepted: boolean
|
|||
|
|
action_state: AdapterActionState
|
|||
|
|
adapter_operation_id: string?
|
|||
|
|
provider_operation_id: string?
|
|||
|
|
initial_events:
|
|||
|
|
- EvidenceEvent
|
|||
|
|
raw_response_ref: string?
|
|||
|
|
error: ErrorDescriptor?
|
|||
|
|
received_at: timestamp
|
|||
|
|
completed_at: timestamp?
|
|||
|
|
metadata: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### AdapterActionState
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
accepted
|
|||
|
|
rejected
|
|||
|
|
queued
|
|||
|
|
scheduled
|
|||
|
|
in_progress
|
|||
|
|
completed
|
|||
|
|
failed
|
|||
|
|
cancelled
|
|||
|
|
duplicate
|
|||
|
|
idempotency_conflict
|
|||
|
|
unknown
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Important Rule
|
|||
|
|
|
|||
|
|
An accepted action result is not proof that the intended result was achieved.
|
|||
|
|
|
|||
|
|
Example:
|
|||
|
|
|
|||
|
|
For email, `accepted: true` means the email adapter accepted the send request. It does not prove that the recipient received, saw, understood, or acted on the notification.
|
|||
|
|
|
|||
|
|
For hybrid mail, `accepted: true` means the adapter accepted the request. It does not prove that the letter was validated, printed, handed over, delivered, or read.
|
|||
|
|
|
|||
|
|
## 9.16 AdapterEvent
|
|||
|
|
|
|||
|
|
An `AdapterEvent` is an incoming event from an adapter before or during evidence normalization.
|
|||
|
|
|
|||
|
|
Adapters MAY expose native-like adapter events, but MUST provide a mapping to `EvidenceEvent`.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterEvent:
|
|||
|
|
event_id: string
|
|||
|
|
adapter_id: string
|
|||
|
|
adapter_event_type: string
|
|||
|
|
native_event_type: string?
|
|||
|
|
native_status: string?
|
|||
|
|
occurred_at: timestamp?
|
|||
|
|
received_at: timestamp
|
|||
|
|
observation: EventObservation
|
|||
|
|
correlation: CorrelationContext
|
|||
|
|
participant_id: string?
|
|||
|
|
payload_ref: ResourceRef?
|
|||
|
|
action_surface_ref: ActionSurfaceRef?
|
|||
|
|
endpoint_ref: EndpointRef?
|
|||
|
|
actor_context: ActorContext?
|
|||
|
|
provider_refs:
|
|||
|
|
- ProviderRef
|
|||
|
|
raw_event_ref: string?
|
|||
|
|
normalization_status: normalized | ignored | failed | pending
|
|||
|
|
normalized_events:
|
|||
|
|
- EvidenceEvent
|
|||
|
|
metadata: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 9.17 EventObservation
|
|||
|
|
|
|||
|
|
`EventObservation` distinguishes the event source from the event meaning.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
EventObservation:
|
|||
|
|
source_type: adapter | provider_api | provider_webhook | endpoint | carrier | recipient_client | postal_carrier | feed_server | action_surface | manual | system | unknown
|
|||
|
|
observed_at: timestamp
|
|||
|
|
occurred_at: timestamp?
|
|||
|
|
source_confidence: low | medium | high
|
|||
|
|
observer_ref: string?
|
|||
|
|
transport_ref: string?
|
|||
|
|
notes:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
This is useful because provider events may be delayed, forwarded, batched, inferred, or partially observed.
|
|||
|
|
|
|||
|
|
## 9.18 EvidenceEvent
|
|||
|
|
|
|||
|
|
An `EvidenceEvent` is the normalized event format consumed by the `evidence-ledger`.
|
|||
|
|
|
|||
|
|
Adapters MUST produce or enable production of `EvidenceEvent` records.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
EvidenceEvent:
|
|||
|
|
evidence_event_id: string
|
|||
|
|
event_type: string
|
|||
|
|
event_family: string
|
|||
|
|
occurred_at: timestamp?
|
|||
|
|
observed_at: timestamp
|
|||
|
|
source_adapter_id: string?
|
|||
|
|
source_adapter_event_id: string?
|
|||
|
|
coordination_case_id: string
|
|||
|
|
participant_id: string?
|
|||
|
|
payload_ref: ResourceRef?
|
|||
|
|
action_surface_ref: ActionSurfaceRef?
|
|||
|
|
endpoint_ref: EndpointRef?
|
|||
|
|
actor_context: ActorContext?
|
|||
|
|
observation: EventObservation?
|
|||
|
|
provider_refs:
|
|||
|
|
- ProviderRef
|
|||
|
|
normalized_meaning: string
|
|||
|
|
evidence_grade: EvidenceGrade
|
|||
|
|
confidence: ConfidenceGrade
|
|||
|
|
raw_event_ref: string?
|
|||
|
|
correlation: CorrelationContext
|
|||
|
|
native_status_mapping_ref: string?
|
|||
|
|
metadata: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Required Fields
|
|||
|
|
|
|||
|
|
The following fields are REQUIRED:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
evidence_event_id
|
|||
|
|
event_type
|
|||
|
|
event_family
|
|||
|
|
observed_at
|
|||
|
|
coordination_case_id
|
|||
|
|
normalized_meaning
|
|||
|
|
evidence_grade
|
|||
|
|
confidence
|
|||
|
|
correlation
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`occurred_at` SHOULD be included when the source provides it.
|
|||
|
|
|
|||
|
|
## 10. Canonical Event Families
|
|||
|
|
|
|||
|
|
The following event families are canonical for adapter-generated evidence.
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
notification
|
|||
|
|
publication
|
|||
|
|
access
|
|||
|
|
delivery
|
|||
|
|
interaction
|
|||
|
|
identity
|
|||
|
|
authority
|
|||
|
|
payload
|
|||
|
|
payment
|
|||
|
|
signature
|
|||
|
|
feed
|
|||
|
|
webhook
|
|||
|
|
system
|
|||
|
|
manual
|
|||
|
|
result
|
|||
|
|
policy
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Adapters SHOULD map native events into these families.
|
|||
|
|
|
|||
|
|
## 11. Canonical Event Types
|
|||
|
|
|
|||
|
|
This version defines a starter vocabulary. It is not exhaustive.
|
|||
|
|
|
|||
|
|
## 11.1 Notification Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
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.attempt.cancelled
|
|||
|
|
notification.endpoint.accepted
|
|||
|
|
notification.endpoint.deferred
|
|||
|
|
notification.endpoint.rejected_temporary
|
|||
|
|
notification.endpoint.rejected_permanent
|
|||
|
|
notification.endpoint.unreachable
|
|||
|
|
notification.endpoint.unknown
|
|||
|
|
notification.channel.complaint_received
|
|||
|
|
notification.channel.unsubscribe_received
|
|||
|
|
notification.channel.suppression_added
|
|||
|
|
notification.channel.suppression_removed
|
|||
|
|
notification.channel.reputation_warning
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11.2 Publication and Feed Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
publication.item.published
|
|||
|
|
publication.item.updated
|
|||
|
|
publication.item.removed
|
|||
|
|
feed.item.published
|
|||
|
|
feed.item.updated
|
|||
|
|
feed.item.removed
|
|||
|
|
feed.item.expired
|
|||
|
|
feed.item.fetched
|
|||
|
|
feed.feed.fetched
|
|||
|
|
feed.feed.validated
|
|||
|
|
feed.feed.validation_failed
|
|||
|
|
feed.hub.notified
|
|||
|
|
feed.hub.notification_failed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11.3 Access Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
access.grant.created
|
|||
|
|
access.grant.issued
|
|||
|
|
access.grant.used
|
|||
|
|
access.grant.denied
|
|||
|
|
access.grant.expired
|
|||
|
|
access.grant.revoked
|
|||
|
|
access.grant.delegated
|
|||
|
|
access.grant.suspicious_use_detected
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11.4 Delivery Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
delivery.payload.available
|
|||
|
|
delivery.payload.presented
|
|||
|
|
delivery.payload.viewed
|
|||
|
|
delivery.payload.retrieved
|
|||
|
|
delivery.payload.downloaded
|
|||
|
|
delivery.payload.submitted
|
|||
|
|
delivery.payload.received
|
|||
|
|
delivery.payload.validated
|
|||
|
|
delivery.payload.validation_failed
|
|||
|
|
delivery.payload.accepted
|
|||
|
|
delivery.payload.rejected
|
|||
|
|
delivery.payload.archived
|
|||
|
|
delivery.payload.failed
|
|||
|
|
delivery.production.started
|
|||
|
|
delivery.production.completed
|
|||
|
|
delivery.production.failed
|
|||
|
|
delivery.postal.handed_over
|
|||
|
|
delivery.postal.in_transit
|
|||
|
|
delivery.postal.delivery_confirmed
|
|||
|
|
delivery.postal.undeliverable
|
|||
|
|
delivery.postal.return_received
|
|||
|
|
delivery.postal.forwarded
|
|||
|
|
delivery.postal.address_corrected
|
|||
|
|
delivery.postal.status_unknown
|
|||
|
|
delivery.postal.expired_without_final_status
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The event `delivery.postal.delivered` SHOULD be avoided because it is ambiguous. Use `delivery.postal.delivery_confirmed` where actual confirmation semantics exist.
|
|||
|
|
|
|||
|
|
## 11.5 Interaction Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
interaction.surface.opened
|
|||
|
|
interaction.notification.opened
|
|||
|
|
interaction.link.clicked
|
|||
|
|
interaction.proxy_or_privacy_interaction
|
|||
|
|
interaction.scanner_or_bot_interaction
|
|||
|
|
interaction.unverified_actor_interaction
|
|||
|
|
interaction.authenticated_actor_interaction
|
|||
|
|
interaction.authorized_actor_interaction
|
|||
|
|
interaction.reply_received
|
|||
|
|
interaction.out_of_office_received
|
|||
|
|
interaction.acknowledgement_recorded
|
|||
|
|
interaction.decline_recorded
|
|||
|
|
interaction.dispute_opened
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11.6 Identity Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
identity.actor_unknown
|
|||
|
|
identity.actor_suspected
|
|||
|
|
identity.actor_authenticated
|
|||
|
|
identity.actor_mfa_verified
|
|||
|
|
identity.actor_verified_by_provider
|
|||
|
|
identity.actor_mismatch_detected
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11.7 Authority Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
authority.unknown
|
|||
|
|
authority.self_asserted
|
|||
|
|
authority.delegate_authorized
|
|||
|
|
authority.organizational_representative_verified
|
|||
|
|
authority.signer_authorized
|
|||
|
|
authority.payment_authorized
|
|||
|
|
authority.authorization_failed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11.8 Payment Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
payment.request.created
|
|||
|
|
payment.request.presented
|
|||
|
|
payment.started
|
|||
|
|
payment.failed
|
|||
|
|
payment.cancelled
|
|||
|
|
payment.succeeded
|
|||
|
|
payment.settled
|
|||
|
|
payment.partially_settled
|
|||
|
|
payment.refunded
|
|||
|
|
payment.disputed
|
|||
|
|
payment.promise_to_pay_recorded
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11.9 Signature Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
signature.envelope.created
|
|||
|
|
signature.envelope.sent
|
|||
|
|
signature.document.viewed
|
|||
|
|
signature.signing.started
|
|||
|
|
signature.signing.completed
|
|||
|
|
signature.signing.declined
|
|||
|
|
signature.signing.expired
|
|||
|
|
signature.signing.cancelled
|
|||
|
|
signature.document.finalized
|
|||
|
|
signature.document.archived
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 11.10 Webhook/System Events
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
webhook.request.sent
|
|||
|
|
webhook.response.accepted
|
|||
|
|
webhook.response.rejected
|
|||
|
|
webhook.delivery.failed
|
|||
|
|
system.adapter.health_changed
|
|||
|
|
system.provider.degraded
|
|||
|
|
system.provider.unavailable
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 12. Acceptance-Level Metadata
|
|||
|
|
|
|||
|
|
Some generic event names, especially `notification.endpoint.accepted`, may represent different strengths depending on protocol.
|
|||
|
|
|
|||
|
|
Adapters SHOULD include acceptance-level metadata.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AcceptanceSemantics:
|
|||
|
|
acceptance_level: provider | relay | carrier | server | endpoint | client | device | mailbox | physical_handover | unknown
|
|||
|
|
finality: preliminary | intermediate | final | unknown
|
|||
|
|
does_not_mean:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
email_mx_accepted:
|
|||
|
|
acceptance_level: server
|
|||
|
|
finality: intermediate
|
|||
|
|
does_not_mean:
|
|||
|
|
- inbox placement
|
|||
|
|
- human awareness
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
sms_delivered:
|
|||
|
|
acceptance_level: device
|
|||
|
|
finality: final
|
|||
|
|
does_not_mean:
|
|||
|
|
- human read
|
|||
|
|
- intended-recipient identity
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
xmpp_delivery_receipt:
|
|||
|
|
acceptance_level: client
|
|||
|
|
finality: intermediate
|
|||
|
|
does_not_mean:
|
|||
|
|
- displayed
|
|||
|
|
- understood
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
hybridmail_postal_handover:
|
|||
|
|
acceptance_level: physical_handover
|
|||
|
|
finality: intermediate
|
|||
|
|
does_not_mean:
|
|||
|
|
- final delivery confirmation
|
|||
|
|
- human reading
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 13. EvidenceGrade
|
|||
|
|
|
|||
|
|
An `EvidenceGrade` describes what an event can reasonably support.
|
|||
|
|
|
|||
|
|
Adapters MUST assign an evidence grade to normalized evidence events.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
EvidenceGrade:
|
|||
|
|
strength: none | weak | medium | strong | conclusive | negative | ambiguous
|
|||
|
|
actor_certainty: none | low | medium | high
|
|||
|
|
authority_certainty: none | low | medium | high
|
|||
|
|
payload_certainty: none | low | medium | high
|
|||
|
|
interaction_certainty: none | low | medium | high
|
|||
|
|
timing_certainty: none | low | medium | high
|
|||
|
|
channel_certainty: none | low | medium | high
|
|||
|
|
non_repudiation_strength: none | low | medium | high
|
|||
|
|
notes:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 14. ConfidenceGrade
|
|||
|
|
|
|||
|
|
`ConfidenceGrade` expresses how confident the adapter is in the normalized interpretation.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
ConfidenceGrade:
|
|||
|
|
level: low | medium | high
|
|||
|
|
basis:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Example:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
level: medium
|
|||
|
|
basis:
|
|||
|
|
- Provider event type is known.
|
|||
|
|
- Native event contains provider message ID.
|
|||
|
|
- Event was correlated to known action request.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 15. NativeStatusMapping
|
|||
|
|
|
|||
|
|
Adapters MUST define native-to-normalized mappings for provider statuses or native events where applicable.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
NativeStatusMapping:
|
|||
|
|
native_status: string
|
|||
|
|
native_event_type: string?
|
|||
|
|
native_status_scope: provider | endpoint | transport | interaction | delivery | production | postal | payment | signature | publication | feed | system | unknown
|
|||
|
|
normalized_event: string
|
|||
|
|
normalized_state: string?
|
|||
|
|
evidence_grade: EvidenceGrade
|
|||
|
|
confidence: low | medium | high
|
|||
|
|
terminal: boolean
|
|||
|
|
retryable: boolean?
|
|||
|
|
ambiguous: boolean
|
|||
|
|
product_or_feature_dependent: boolean
|
|||
|
|
required_features:
|
|||
|
|
- string
|
|||
|
|
warning: string?
|
|||
|
|
examples:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 16. NativeEventSemantics
|
|||
|
|
|
|||
|
|
Adapters SHOULD document native event semantics for agent-friendly implementation.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
NativeEventSemantics:
|
|||
|
|
native_event_type: string
|
|||
|
|
source_system: string
|
|||
|
|
plain_meaning: string
|
|||
|
|
does_not_mean:
|
|||
|
|
- string
|
|||
|
|
normalized_mapping: string
|
|||
|
|
evidence_grade: EvidenceGrade
|
|||
|
|
examples:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Example:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
native_event_type: delivered
|
|||
|
|
source_system: email_provider
|
|||
|
|
plain_meaning: Recipient mail server accepted the message.
|
|||
|
|
does_not_mean:
|
|||
|
|
- Message reached inbox.
|
|||
|
|
- Human recipient saw the message.
|
|||
|
|
- Payload was accessed.
|
|||
|
|
normalized_mapping: notification.endpoint.accepted
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 17. AdapterEvidenceAssessment
|
|||
|
|
|
|||
|
|
Adapters SHOULD provide a native evidence assessment for standalone use and diagnostics.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterEvidenceAssessment:
|
|||
|
|
subject_ref: string
|
|||
|
|
coordination_case_id: string?
|
|||
|
|
participant_id: string?
|
|||
|
|
adapter_id: string
|
|||
|
|
category: success | fail | undef
|
|||
|
|
subclass: string
|
|||
|
|
confidence: low | medium | high
|
|||
|
|
strongest_signal: string?
|
|||
|
|
evidence_summary:
|
|||
|
|
- string
|
|||
|
|
recommended_coordination_interpretation: string?
|
|||
|
|
limitations:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Adapter assessment is advisory.
|
|||
|
|
|
|||
|
|
`coordination-engine` remains authoritative for participant and case state.
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
email:
|
|||
|
|
category: undef
|
|||
|
|
subclass: endpoint_accepted_only
|
|||
|
|
|
|||
|
|
sms:
|
|||
|
|
category: success
|
|||
|
|
subclass: delivered
|
|||
|
|
|
|||
|
|
hybridmail:
|
|||
|
|
category: success
|
|||
|
|
subclass: handed_to_postal_service
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
These adapter-native classifications do not automatically become coordination-case success.
|
|||
|
|
|
|||
|
|
## 18. ActorContext
|
|||
|
|
|
|||
|
|
`ActorContext` describes the actor associated with an event, if known.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
ActorContext:
|
|||
|
|
actor_ref: string?
|
|||
|
|
actor_type: human | organization | system | agent | bot | unknown
|
|||
|
|
identity_strength: none | low | medium | high
|
|||
|
|
authority_strength: none | low | medium | high
|
|||
|
|
authenticated: boolean?
|
|||
|
|
delegated: boolean?
|
|||
|
|
provider_identity_ref: string?
|
|||
|
|
metadata: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Adapters SHOULD avoid overclaiming identity.
|
|||
|
|
|
|||
|
|
For example:
|
|||
|
|
|
|||
|
|
* `email-connect` SHOULD NOT mark a click as authenticated unless backed by trusted identity or portal evidence.
|
|||
|
|
* `sms-connect` SHOULD NOT assume phone possession equals intended participant identity.
|
|||
|
|
* `rss-connect` SHOULD NOT assume feed fetch equals participant identity.
|
|||
|
|
* `xmpp-connect` MAY provide medium/high identity evidence if JID mapping and authentication are reliable.
|
|||
|
|
* `hybridmail-connect` SHOULD NOT infer recipient identity merely from postal dispatch.
|
|||
|
|
|
|||
|
|
## 19. CorrelationContext
|
|||
|
|
|
|||
|
|
Correlation is mandatory for useful adapter integration.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
CorrelationContext:
|
|||
|
|
correlation_id: string
|
|||
|
|
request_id: string?
|
|||
|
|
coordination_case_id: string
|
|||
|
|
participant_id: string?
|
|||
|
|
notification_id: string?
|
|||
|
|
delivery_id: string?
|
|||
|
|
interaction_id: string?
|
|||
|
|
payload_id: string?
|
|||
|
|
action_surface_id: string?
|
|||
|
|
adapter_operation_id: string?
|
|||
|
|
provider_operation_id: string?
|
|||
|
|
provider_message_id: string?
|
|||
|
|
external_refs:
|
|||
|
|
- ProviderRef
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Adapters MUST preserve correlation identifiers where technically possible.
|
|||
|
|
|
|||
|
|
## 20. ProviderRef
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
ProviderRef:
|
|||
|
|
provider_name: string
|
|||
|
|
ref_type: string
|
|||
|
|
ref_value: string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
provider_name: sendgrid
|
|||
|
|
ref_type: message_id
|
|||
|
|
ref_value: abc123
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
provider_name: stripe
|
|||
|
|
ref_type: payment_intent_id
|
|||
|
|
ref_value: pi_123
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
provider_name: pingen
|
|||
|
|
ref_type: letter_id
|
|||
|
|
ref_value: letter_123
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 21. FeatureDependency
|
|||
|
|
|
|||
|
|
`FeatureDependency` describes provider-, route-, product-, or configuration-specific requirements.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
FeatureDependency:
|
|||
|
|
feature_name: string
|
|||
|
|
dependency_type: provider | product | route | country | endpoint | recipient_client | configuration | policy | account | unknown
|
|||
|
|
required_for_events:
|
|||
|
|
- string
|
|||
|
|
fallback_behavior: string
|
|||
|
|
limitation: string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
feature_name: email_click_tracking
|
|||
|
|
dependency_type: configuration
|
|||
|
|
required_for_events:
|
|||
|
|
- interaction.link.clicked
|
|||
|
|
fallback_behavior: no click events emitted
|
|||
|
|
limitation: Link clicks cannot be observed without tracking links.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
feature_name: xmpp_displayed_markers
|
|||
|
|
dependency_type: recipient_client
|
|||
|
|
required_for_events:
|
|||
|
|
- interaction.notification.opened
|
|||
|
|
fallback_behavior: delivery receipts only
|
|||
|
|
limitation: Displayed markers depend on client support.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
feature_name: hybridmail_delivery_confirmation
|
|||
|
|
dependency_type: product
|
|||
|
|
required_for_events:
|
|||
|
|
- delivery.postal.delivery_confirmed
|
|||
|
|
fallback_behavior: postal handover is maximum positive evidence
|
|||
|
|
limitation: Ordinary letters do not provide delivery confirmation.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 22. LateEventPolicy
|
|||
|
|
|
|||
|
|
Adapters frequently produce late events.
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
| Adapter | Late event example |
|
|||
|
|
| ----------- | ------------------------ |
|
|||
|
|
| Email | async bounce |
|
|||
|
|
| SMS | late delivery receipt |
|
|||
|
|
| RSS | delayed feed fetch log |
|
|||
|
|
| XMPP | delayed delivery receipt |
|
|||
|
|
| Hybrid mail | return mail weeks later |
|
|||
|
|
|
|||
|
|
Adapters MUST declare their late-event policy.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
LateEventPolicy:
|
|||
|
|
accepts_late_events: boolean
|
|||
|
|
late_events_can_revise_assessment: boolean
|
|||
|
|
late_events_can_reopen_case: boolean
|
|||
|
|
default_late_event_window: string?
|
|||
|
|
expected_late_event_types:
|
|||
|
|
- string
|
|||
|
|
notes:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Normative rule:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Adapters MUST emit late events if they are relevant.
|
|||
|
|
coordination-engine decides whether to revise, annotate, reopen, or ignore case state.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 23. ErrorDescriptor
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
ErrorDescriptor:
|
|||
|
|
code: string
|
|||
|
|
message: string
|
|||
|
|
retryable: boolean
|
|||
|
|
category: validation | authentication | authorization | configuration | provider | network | rate_limit | timeout | conflict | idempotency_conflict | unsupported_capability | unknown
|
|||
|
|
native_error_code: string?
|
|||
|
|
native_error_message: string?
|
|||
|
|
details: object?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Adapters MUST return an `ErrorDescriptor` when an action request is rejected or fails before acceptance.
|
|||
|
|
|
|||
|
|
## 24. AdapterHealth
|
|||
|
|
|
|||
|
|
Adapters MUST expose health state.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterHealth:
|
|||
|
|
adapter_id: string
|
|||
|
|
status: healthy | degraded | unavailable | misconfigured | unknown
|
|||
|
|
checked_at: timestamp
|
|||
|
|
provider_connectivity: healthy | degraded | unavailable | unknown
|
|||
|
|
configuration_validity: valid | invalid | partial | unknown
|
|||
|
|
credential_status: valid | expired | missing | insufficient | unknown
|
|||
|
|
webhook_status: healthy | degraded | unavailable | not_supported | unknown
|
|||
|
|
polling_status: healthy | degraded | unavailable | not_supported | unknown
|
|||
|
|
last_action_success_at: timestamp?
|
|||
|
|
last_event_received_at: timestamp?
|
|||
|
|
known_degradations:
|
|||
|
|
- string
|
|||
|
|
metrics:
|
|||
|
|
actions_accepted_last_24h: integer?
|
|||
|
|
actions_failed_last_24h: integer?
|
|||
|
|
events_received_last_24h: integer?
|
|||
|
|
average_action_latency_ms: integer?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 25. Transport Patterns
|
|||
|
|
|
|||
|
|
This specification does not mandate one technical transport.
|
|||
|
|
|
|||
|
|
Adapters MAY integrate through:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
REST API
|
|||
|
|
event bus
|
|||
|
|
message queue
|
|||
|
|
webhook
|
|||
|
|
gRPC
|
|||
|
|
embedded library
|
|||
|
|
CLI
|
|||
|
|
file drop
|
|||
|
|
polling
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
However, any transport MUST preserve the semantic contract defined here.
|
|||
|
|
|
|||
|
|
## 26. Adapter Integration Modes
|
|||
|
|
|
|||
|
|
## 26.1 Embedded Mode
|
|||
|
|
|
|||
|
|
Adapter code runs in the same process as `coordination-engine`.
|
|||
|
|
|
|||
|
|
Suitable for:
|
|||
|
|
|
|||
|
|
* local development
|
|||
|
|
* test adapters
|
|||
|
|
* simulated adapters
|
|||
|
|
* simple deployments
|
|||
|
|
|
|||
|
|
## 26.2 Sidecar Mode
|
|||
|
|
|
|||
|
|
Adapter runs next to the engine but is deployed separately.
|
|||
|
|
|
|||
|
|
Suitable for:
|
|||
|
|
|
|||
|
|
* credential isolation
|
|||
|
|
* provider-specific webhook handling
|
|||
|
|
* protocol-specific runtime dependencies
|
|||
|
|
|
|||
|
|
## 26.3 External Service Mode
|
|||
|
|
|
|||
|
|
Adapter is an independently deployed service.
|
|||
|
|
|
|||
|
|
Suitable for:
|
|||
|
|
|
|||
|
|
* reusable `*-connect` components
|
|||
|
|
* multi-tenant installations
|
|||
|
|
* independent scaling
|
|||
|
|
* provider abstraction
|
|||
|
|
* operational separation
|
|||
|
|
|
|||
|
|
Preferred direction for production adapters:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
*-connect repositories SHOULD implement external service mode first,
|
|||
|
|
while optionally also offering embedded or sidecar modes.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 27. Adapter Lifecycle
|
|||
|
|
|
|||
|
|
Adapters SHOULD support the following lifecycle:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
registered
|
|||
|
|
configured
|
|||
|
|
healthy
|
|||
|
|
degraded
|
|||
|
|
disabled
|
|||
|
|
retired
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 27.1 Registration
|
|||
|
|
|
|||
|
|
During registration, the adapter provides its `AdapterDescriptor`.
|
|||
|
|
|
|||
|
|
### 27.2 Configuration
|
|||
|
|
|
|||
|
|
Configuration may include credentials, provider selection, endpoint settings, webhook secrets, templates, routing policies, tenant-specific settings, product settings, or feature flags.
|
|||
|
|
|
|||
|
|
### 27.3 Health Monitoring
|
|||
|
|
|
|||
|
|
The engine or platform periodically checks `AdapterHealth`.
|
|||
|
|
|
|||
|
|
### 27.4 Action Dispatch
|
|||
|
|
|
|||
|
|
The engine dispatches `AdapterActionRequest` objects to the adapter.
|
|||
|
|
|
|||
|
|
### 27.5 Event Ingestion
|
|||
|
|
|
|||
|
|
The adapter emits `AdapterEvent` or `EvidenceEvent` objects.
|
|||
|
|
|
|||
|
|
### 27.6 Degradation Handling
|
|||
|
|
|
|||
|
|
If an adapter is degraded, the policy engine may switch channel, delay actions, retry later, or escalate.
|
|||
|
|
|
|||
|
|
## 28. Event Ordering, Idempotency, and Late Events
|
|||
|
|
|
|||
|
|
### 28.1 Event Ordering
|
|||
|
|
|
|||
|
|
Adapters MUST NOT assume events arrive in causal order.
|
|||
|
|
|
|||
|
|
The engine MUST be able to process late events.
|
|||
|
|
|
|||
|
|
Adapters SHOULD include accurate `occurred_at` and `observed_at` timestamps.
|
|||
|
|
|
|||
|
|
### 28.2 Duplicate Events
|
|||
|
|
|
|||
|
|
Adapters SHOULD provide stable event identifiers where possible.
|
|||
|
|
|
|||
|
|
The engine MUST deduplicate events using:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
evidence_event_id
|
|||
|
|
adapter_event_id
|
|||
|
|
provider event id
|
|||
|
|
correlation context
|
|||
|
|
event type
|
|||
|
|
timestamp
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 28.3 Late Events
|
|||
|
|
|
|||
|
|
Late events MUST still be accepted and recorded if they are relevant.
|
|||
|
|
|
|||
|
|
Examples:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Email: late hard bounce
|
|||
|
|
SMS: late delivery receipt
|
|||
|
|
RSS: delayed fetch log
|
|||
|
|
XMPP: delayed receipt after offline delivery
|
|||
|
|
Hybrid mail: return mail event after postal handover
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 28.4 Idempotent Actions
|
|||
|
|
|
|||
|
|
All externally visible actions MUST include `idempotency_key`.
|
|||
|
|
|
|||
|
|
Adapters MUST avoid duplicate external side effects for repeated action requests with the same key.
|
|||
|
|
|
|||
|
|
## 29. Adapter Conformance Levels
|
|||
|
|
|
|||
|
|
Adapters MAY implement different maturity levels.
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Level 0: Descriptor only / simulated
|
|||
|
|
Level 1: Action execution + basic evidence events
|
|||
|
|
Level 2: Native status mapping + health + idempotency
|
|||
|
|
Level 3: Evidence grading + endpoint quality + late events
|
|||
|
|
Level 4: Full provider flavor / product semantics / golden tests
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Level 0
|
|||
|
|
|
|||
|
|
The adapter exposes a descriptor and may simulate actions/events.
|
|||
|
|
|
|||
|
|
### Level 1
|
|||
|
|
|
|||
|
|
The adapter can execute at least one supported action and emit basic normalized evidence events.
|
|||
|
|
|
|||
|
|
### Level 2
|
|||
|
|
|
|||
|
|
The adapter supports health, idempotency, native status mapping, and error handling.
|
|||
|
|
|
|||
|
|
### Level 3
|
|||
|
|
|
|||
|
|
The adapter supports evidence grading, endpoint quality, late events, and advisory assessments.
|
|||
|
|
|
|||
|
|
### Level 4
|
|||
|
|
|
|||
|
|
The adapter includes provider/product semantics, capability profiles, native status mapping registry, golden tests, and conformance documentation.
|
|||
|
|
|
|||
|
|
Production adapters SHOULD target Level 3 or higher.
|
|||
|
|
|
|||
|
|
Provider-flavor-heavy adapters, such as `hybridmail-connect`, SHOULD target Level 4.
|
|||
|
|
|
|||
|
|
## 30. Golden Test Requirements
|
|||
|
|
|
|||
|
|
Every adapter SHOULD define golden test scenarios.
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
AdapterGoldenTest:
|
|||
|
|
test_id: string
|
|||
|
|
scenario: string
|
|||
|
|
adapter_id: string
|
|||
|
|
native_events:
|
|||
|
|
- object
|
|||
|
|
expected_evidence_events:
|
|||
|
|
- EvidenceEvent
|
|||
|
|
expected_assessment: AdapterEvidenceAssessment
|
|||
|
|
must_not_emit:
|
|||
|
|
- string
|
|||
|
|
notes:
|
|||
|
|
- string
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Recommended test categories:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
duplicate action request
|
|||
|
|
idempotency conflict
|
|||
|
|
provider acceptance
|
|||
|
|
provider rejection
|
|||
|
|
ambiguous native event
|
|||
|
|
late event
|
|||
|
|
out-of-order event
|
|||
|
|
unsupported capability
|
|||
|
|
endpoint failure
|
|||
|
|
strongest supported positive event
|
|||
|
|
status overclaim prevention
|
|||
|
|
raw event preservation
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Example:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
test_id: hybridmail_ordinary_handover_not_delivery_confirmation
|
|||
|
|
scenario: Ordinary letter handed over to postal service.
|
|||
|
|
expected_evidence_events:
|
|||
|
|
- event_type: delivery.postal.handed_over
|
|||
|
|
must_not_emit:
|
|||
|
|
- delivery.postal.delivery_confirmed
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Example:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
test_id: email_provider_delivered_not_awareness
|
|||
|
|
scenario: Email provider reports delivered.
|
|||
|
|
expected_evidence_events:
|
|||
|
|
- event_type: notification.endpoint.accepted
|
|||
|
|
must_not_emit:
|
|||
|
|
- interaction.notification.opened
|
|||
|
|
- delivery.payload.downloaded
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 31. Security Requirements
|
|||
|
|
|
|||
|
|
Adapters MUST:
|
|||
|
|
|
|||
|
|
* protect provider credentials
|
|||
|
|
* verify incoming provider webhooks where possible
|
|||
|
|
* validate action request authenticity
|
|||
|
|
* avoid leaking sensitive payloads in logs
|
|||
|
|
* support least-privilege configuration
|
|||
|
|
* preserve correlation without exposing unnecessary personal data
|
|||
|
|
* avoid storing raw sensitive data unless explicitly configured
|
|||
|
|
* distinguish test/sandbox from production where relevant
|
|||
|
|
|
|||
|
|
Adapters SHOULD:
|
|||
|
|
|
|||
|
|
* support tenant separation
|
|||
|
|
* support secret rotation
|
|||
|
|
* support signed callbacks or event signatures
|
|||
|
|
* support audit logging of action execution
|
|||
|
|
|
|||
|
|
## 32. Privacy Requirements
|
|||
|
|
|
|||
|
|
Adapters SHOULD minimize personal data.
|
|||
|
|
|
|||
|
|
Adapters SHOULD support:
|
|||
|
|
|
|||
|
|
* endpoint references instead of full endpoint values where possible
|
|||
|
|
* redaction of raw provider events
|
|||
|
|
* retention limits for raw event data
|
|||
|
|
* configurable storage of message content
|
|||
|
|
* metadata-only mode
|
|||
|
|
* data deletion or anonymization workflows where applicable
|
|||
|
|
|
|||
|
|
The adapter interface MUST allow references to external payloads rather than requiring payload content to be copied into the adapter.
|
|||
|
|
|
|||
|
|
## 33. Standalone Adapter Requirements
|
|||
|
|
|
|||
|
|
Adapters are encouraged to be useful outside `coordination-engine`.
|
|||
|
|
|
|||
|
|
A standalone adapter MAY provide:
|
|||
|
|
|
|||
|
|
* provider abstraction
|
|||
|
|
* operational dashboard
|
|||
|
|
* message or delivery timeline API
|
|||
|
|
* diagnostic API
|
|||
|
|
* native event archive
|
|||
|
|
* normalized event stream
|
|||
|
|
* suppression management
|
|||
|
|
* provider health checks
|
|||
|
|
* local policy hints
|
|||
|
|
* endpoint quality diagnostics
|
|||
|
|
* adapter-native evidence assessment
|
|||
|
|
|
|||
|
|
However, standalone features MUST NOT contradict the coordination-engine contract.
|
|||
|
|
|
|||
|
|
For example:
|
|||
|
|
|
|||
|
|
* `email-connect` may expose `delivered_to_mx`, but MUST NOT expose it as business-level awareness.
|
|||
|
|
* `sms-connect` may expose `delivered_to_device`, but MUST NOT expose it as human-read proof.
|
|||
|
|
* `rss-connect` may expose `published`, but MUST NOT expose it as participant awareness.
|
|||
|
|
* `xmpp-connect` may expose `displayed`, but MUST NOT expose it as comprehension.
|
|||
|
|
* `hybridmail-connect` may expose `handed_to_postal_service`, but MUST NOT expose it as final delivery confirmation.
|
|||
|
|
|
|||
|
|
## 34. Compatibility Requirements for Adapter Repositories
|
|||
|
|
|
|||
|
|
Every `*-connect` repository SHOULD contain:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
INTENT.md
|
|||
|
|
docs/AdapterImplementation.md
|
|||
|
|
docs/EventMapping.md
|
|||
|
|
docs/ProviderModel.md
|
|||
|
|
docs/EvidenceClassification.md
|
|||
|
|
docs/GoldenTests.md
|
|||
|
|
schemas/
|
|||
|
|
src/
|
|||
|
|
tests/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Every adapter repository MUST document:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
Implemented adapter contract version
|
|||
|
|
Conformance level
|
|||
|
|
Supported actions
|
|||
|
|
Emitted normalized events
|
|||
|
|
Native event mappings
|
|||
|
|
Evidence grading rules
|
|||
|
|
Evidence ceiling
|
|||
|
|
Endpoint quality model
|
|||
|
|
Late event policy
|
|||
|
|
Known limitations
|
|||
|
|
Provider-specific assumptions
|
|||
|
|
Security model
|
|||
|
|
Privacy model
|
|||
|
|
Standalone usage
|
|||
|
|
coordination-engine integration mode
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 35. Versioning
|
|||
|
|
|
|||
|
|
### 35.1 Contract Version
|
|||
|
|
|
|||
|
|
Adapters MUST declare `adapter_contract_version`.
|
|||
|
|
|
|||
|
|
This document defines:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
adapter_contract_version: 1.1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 35.2 Backward Compatibility
|
|||
|
|
|
|||
|
|
Minor extensions MAY add:
|
|||
|
|
|
|||
|
|
* optional fields
|
|||
|
|
* new event types
|
|||
|
|
* new action types
|
|||
|
|
* new adapter types
|
|||
|
|
* new evidence metadata
|
|||
|
|
* new capability flags
|
|||
|
|
|
|||
|
|
Breaking changes include:
|
|||
|
|
|
|||
|
|
* removing required fields
|
|||
|
|
* changing meaning of existing fields
|
|||
|
|
* changing event semantics
|
|||
|
|
* changing idempotency requirements
|
|||
|
|
* changing evidence grade semantics
|
|||
|
|
* changing weakest-safe-mapping requirements
|
|||
|
|
|
|||
|
|
Breaking changes require a new major version.
|
|||
|
|
|
|||
|
|
## 36. Minimal Compliance Checklist
|
|||
|
|
|
|||
|
|
An adapter is minimally compliant with AdapterInterfaceSpecification 1.1 if it:
|
|||
|
|
|
|||
|
|
1. Exposes an `AdapterDescriptor`.
|
|||
|
|
2. Exposes an `AdapterCapabilityProfile`.
|
|||
|
|
3. Declares supported actions.
|
|||
|
|
4. Declares emitted event types.
|
|||
|
|
5. Declares an `EvidenceCeiling`.
|
|||
|
|
6. Declares `AssuranceCapability`.
|
|||
|
|
7. Accepts `AdapterActionRequest` objects for supported actions.
|
|||
|
|
8. Returns `AdapterActionResult` objects.
|
|||
|
|
9. Supports idempotency keys.
|
|||
|
|
10. Emits or maps to `EvidenceEvent` objects.
|
|||
|
|
11. Provides `EvidenceGrade` and `ConfidenceGrade`.
|
|||
|
|
12. Preserves `CorrelationContext`.
|
|||
|
|
13. Exposes `AdapterHealth`.
|
|||
|
|
14. Documents known limitations.
|
|||
|
|
15. Does not overclaim result success.
|
|||
|
|
16. Clearly separates provider-native events from normalized evidence.
|
|||
|
|
17. Applies weakest safe mapping to ambiguous native events.
|
|||
|
|
18. Preserves raw native event references where possible.
|
|||
|
|
19. Declares late-event behavior.
|
|||
|
|
20. Provides advisory `AdapterEvidenceAssessment` or explains why not.
|
|||
|
|
|
|||
|
|
## 37. Non-Goals
|
|||
|
|
|
|||
|
|
This adapter specification does not define:
|
|||
|
|
|
|||
|
|
* the internal storage model of adapters
|
|||
|
|
* the provider-specific API shape
|
|||
|
|
* the transport protocol used between engine and adapter
|
|||
|
|
* legal validity of evidence
|
|||
|
|
* UI requirements
|
|||
|
|
* billing models
|
|||
|
|
* tenant management model
|
|||
|
|
* full workflow semantics
|
|||
|
|
* complete event vocabulary for every possible domain
|
|||
|
|
|
|||
|
|
Those concerns may be defined in separate documents or scenario-specific specifications.
|
|||
|
|
|
|||
|
|
## 38. Strategic Summary
|
|||
|
|
|
|||
|
|
The adapter interface allows `coordination-engine` to remain a generalized coordination runtime while integrating with many concrete systems.
|
|||
|
|
|
|||
|
|
Adapters perform actions and emit evidence. They translate external provider realities into a normalized coordination vocabulary without deciding overall business success.
|
|||
|
|
|
|||
|
|
Version 1.1 strengthens the interface by requiring adapters to declare what they can prove, what they cannot prove, how native statuses map to normalized evidence, and how ambiguity is handled.
|
|||
|
|
|
|||
|
|
The central rule is:
|
|||
|
|
|
|||
|
|
> Adapters must preserve facts, underclaim semantics, expose limitations, and let coordination-engine decide result meaning.
|
|||
|
|
|
|||
|
|
This distinction is essential for reliable, extensible, evidence-driven digital coordination.
|
|||
|
|
|