Status: Proposed
Version: 1.0
Date: 2025-12-28
Supersedes: N/A
Related ADRs: ADR-033 (Kernel-Shell), ADR-030 (VibesPro™ Foundation)
Related PRDs: PRD-022
SEA™ and VibesPro™ are separate bounded contexts with:
These contexts need reliable communication for:
The transcript evaluated multiple options:
We adopt NATS JetStream with the following architecture:
| Stream | Owner | Subjects | Purpose |
|---|---|---|---|
SEA_EVENTS |
SEA™ | sea.event.> |
Events emitted by SEA™ |
VIBESPRO_EVENTS |
VibesPro™ | vibespro.event.> |
Events emitted by VibesPro™ |
1
{context}.event.{snake_case_name}.v{n}
Examples:
vibespro.event.vibe_created.v1vibespro.event.vibe_scored.v1sea.event.governance_decision_recorded.v1Rule: Never change meaning of .v1 once emitted. Create .v2 on breaking changes.
Outbox (per context DB):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREATE TABLE outbox_events (
id UUID PRIMARY KEY,
aggregate_type TEXT NOT NULL,
aggregate_id TEXT NOT NULL,
event_type TEXT NOT NULL,
payload JSONB NOT NULL,
occurred_at TIMESTAMPTZ NOT NULL,
correlation_id UUID,
causation_id UUID,
published_at TIMESTAMPTZ,
publish_attempts INT DEFAULT 0,
publish_error TEXT
);
CREATE INDEX idx_outbox_unpublished ON outbox_events (occurred_at)
WHERE published_at IS NULL;
Inbox (per context DB):
1
2
3
4
5
6
7
8
CREATE TABLE inbox_messages (
message_id UUID PRIMARY KEY,
subject TEXT NOT NULL,
received_at TIMESTAMPTZ NOT NULL,
processed_at TIMESTAMPTZ,
attempts INT DEFAULT 0,
last_error TEXT
);
1
2
Durable Consumer: {target_context}__from_{source_context}
Example: sea__from_vibespro
| Setting | Value | Rationale |
|---|---|---|
| Ack Policy | Explicit | Reliable processing |
| Ack Wait | 60-120s | Handle slow handlers |
| Max Deliver | 10-20 | DLQ after failures |
| Max In-Flight | 10-50 | Backpressure control |
Use Nats-Msg-Id header set to outbox event UUID:
NATS JetStream advantages:
Nats-Msg-IdPer-context streams:
Outbox pattern:
Inbox pattern:
Nats-Msg-Id header to outbox event UUIDprocessed_at before ACKing.v1, .v2).v1 payload meaning post-release| Spec Concept | SEA-DSL Target | Mapping |
|---|---|---|
| OutboxEvent | Entity node | 1:1 field mapping |
| InboxMessage | Entity node | 1:1 field mapping |
| JetStream stream | Infrastructure config | Per-context |
| Subject convention | Event contract | Schema preservation |
| INV-ID | Invariant | Type | Enforcement |
|---|---|---|---|
| INV-020 | At-least-once delivery | System | JetStream redelivery |
| INV-021 | Exactly-once processing | System | Inbox PK constraint |
| INV-022 | State and event atomically written | Process | Same DB transaction |
| INV-023 | Events versioned immutably | Contract | Subject naming |
| Attribute | Target | Rationale |
|---|---|---|
| Reliability | Zero lost events | Outbox guarantees |
| Idempotency | No duplicate processing | Inbox PK |
| Latency | p99 < 500ms event delivery | Pull batch efficiency |
| Recoverability | Full replay from stream | JetStream persistence |
When Rust consumer pulls a message:
message_id from Nats-Msg-Id headerINSERT INTO inbox_messages ... ON CONFLICT DO NOTHING/handle)