# Design

This document captures the **full architecture** implemented in this repository.
It is written as a "soup-to-nuts" design spec so the implementation can be ported to other languages (e.g., the existing Matrix-3 TypeScript codebase) without losing intent.

## 1. Ubiquitous Language

### 1.1 Realm
A **realm** is the routing domain / tenant boundary (e.g., `matrix-3`, `flowpad-demo`, `flowpad-demo.tab-01`, `acme.com`).

- A realm may be a DNS name, an environment-qualified name, or a hierarchical dot-separated name.
- A realm **must be a single subject token** (i.e., it cannot contain `.` or `/`).

### 1.2 Path / toPath
A **path** (`toPath`, `fromPath`, `replyToPath`) is the internal semantic address of an atomic component method or event.

In the "Matrix-3" heritage this is represented as:

```
<mountSegments...>/<atom>

atom := <component.path>.<plane>.<message>
plane := accepts | emits
```

Examples:

- `project/daemon.project.accepts.scan`
- `root.ui.app.editor.accepts.setText`
- `root.push.emits.message`

### 1.3 Atomic component
An **atomic component** is the smallest independently addressable service endpoint, identified by an `atom` (component path + plane + message).

This matters because the federation layer must preserve atomicity: it routes to the exact atomic `accepts` handler, and forwards atomic `emits` events.

### 1.4 Mailbox
A **mailbox** is the realm's public ingress topic on the backbone transport.

- Legacy mailbox namespace: `public.ingress.<realm>`
- MX mailbox namespace: `mx/in/1/<realm>/<shard>`

The core property: **no wildcards required on the backbone**. Each realm subscribes to *its own* mailbox topic.

### 1.5 Backbone vs local bus
We separate two transports:

- **Backbone**: inter-realm federation transport (e.g., NATS cluster reachable from the public Internet).
- **Local bus**: intra-realm transport (component invocation within a single realm). This may allow wildcard subscriptions.

This is a deliberate "Ports & Adapters" (Hexagonal Architecture) decision:

- Federation code depends on an abstract `Transport` port.
- Concrete transports (in-memory, NATS, etc.) are adapters.

## 2. Protocol surface

### 2.1 MXURI/1 tolerant parsing
Supported forms:

1. **Legacy compact** (Matrix-3)

```
matrix://<realm>/<mount...>/<component.path>.<plane>.<message>
```

2. **Segmented** (new spec with explicit delimiter)

```
matrix://<realm>/<mount...>/-/<component/...>/<plane>/<message>
```

Both canonicalize to the same `(realm, mountSegments, componentPath, plane, messageName)`.

### 2.2 MXINGRESS/1
Ingress topics:

- `mx/in/1/<realm>/<shard>`

This implementation defaults `shard = "00"`.

### 2.3 Legacy ingress (Matrix-3)
Ingress topic:

- `public.ingress.<mxesc1(realm)>`

### 2.4 MXENV/1 envelope
The canonical envelope model is `MxEnvelopeV1`:

- `msgType`: `Cmd | Evt | Result | Sub | Unsub | Nack`
- nested routing objects `to`, `from`, `replyTo`
- `msgId`: stable dedup key
- `correlationId`: request/response correlation
- `principal` + `auth` placeholders

**TTL semantics**:

- `MxEnvelopeV1.ttl` is a *hop limit* for multi-hop forwarding (routing-level TTL).
- `CrossRealmEnvelopeLegacy.ttlMs` (when present) is an *expiry duration* in milliseconds relative to `timestamp`.
- This implementation preserves legacy `ttlMs` as-is and does **not** coerce it into `MxEnvelopeV1.ttl`.

### 2.5 Matrix-3 legacy envelope
Legacy profile supports:

- request: `CrossRealmEnvelopeLegacy` (flat fields)
- reply: `ReplyEnvelopeLegacy` (flat fields)
- optional legacy event: `EventEnvelopeLegacy` (extension point)

## 3. Layered architecture

### 3.1 Ports & Adapters

**Port**:

- `Transport` (`publish(topic, payload, meta?)` / `subscribe(filter, handler)`), where `meta` may carry transport-specific delivery options (e.g., QoS, retain).

**Adapters**:

- `InMemoryExactBroker`: exact-match topics only (simulates "no wildcards" backbone)
- `InMemoryFilterBroker`: NATS filter semantics (supports `*` and `>`)

The intent is pluggability via Strategy + Adapter:

- Swap in a real NATS adapter by implementing `Transport`.

### 3.2 Codec layer

- `mxesc1.ts`: deterministic percent-encoding for legacy mailbox compatibility
- `uri.ts`: tolerant MXURI parser
- `topics.ts`: mailbox/internal topic naming
- `envelope_codec.ts`: (de)serialization of both envelope profiles
- `wire_profile.ts`: profile registry (matrix3 vs mxenv1)

### 3.3 Federation edge

#### 3.3.1 `EdgeGateway`
The **EdgeGateway** is the "anti-corruption layer" between the backbone and the realm-local bus.

Responsibilities:

1. Subscribe to the realm mailbox topics (dual subscription for strangler migration).
2. Deserialize inbound payloads into a tagged envelope (matrix3 or mxenv1).
3. Apply inbound guard rails:
   - anti-open-relay (replyTo must target fromRealm)
   - optional replay cache (msgId dedup)
   - optional rate limiter
   - optional policy
4. Route inbound `Cmd/Sub/Unsub` to the **internal bus** by publishing an `InternalRequest`.
5. Subscribe to the per-request internal reply topic, then emit `Result` / legacy reply on the backbone.
   - If no internal reply arrives within `internalTimeoutMs`, EdgeGateway emits an error (`Nack` for MXENV/1, `ok:false` reply for legacy) with code `MX.EDGE.TIMEOUT`.
6. Route inbound `Evt` to the internal bus (fire-and-forget publish).

Key property:

- Backbones remain **wildcard-free**, but the local bus can be wildcard-capable.

#### 3.3.2 Internal request/reply protocol
EdgeGateway routes a backbone command/subscription into the local realm by publishing an **internal request message** to:

- `mx/1/<localRealm>/<toPath>`

Wire-level request shape:

```ts
interface InternalRequestWire {
  correlationId: string;
  replyTo: string;          // full internal topic (string)
  params: unknown;          // decoded envelope body

  // Optional local meta (enabled by default)
  _mx?: {
    fromRealm: string;
    incomingProfile: 'matrix3' | 'mxenv1';
    msgId?: string;
    principalKey?: string;
    traceId?: string;
  };

  // Optional: attach the inbound envelope for debugging/adapters
  // (enabled via `includeInboundEnvelope`)
  envelope?: unknown;
}
```

Components reply by publishing **anything** to the `replyTo` topic.

Strict reply shape (recommended):

```ts
interface InternalReply {
  correlationId?: string; // optional (replyTopic is unique per request)
  ok?: boolean;           // optional (defaults to ok=true)
  body?: unknown;         // optional (defaults to the whole JSON value)
  result?: unknown;       // optional convenience (treated as ok=true, body=result)
  error?: { code: string; message: string; details?: unknown };
}
```

Lenient decoding (supported for integration convenience):

- If payload matches `InternalReply`, it is used as-is.
- If payload is an object with `{ ok: boolean, body?, error? }` but lacks `correlationId`, the gateway supplies the correlationId.
- If payload is an object with `{ result: X }`, the gateway treats it as `ok=true` and `body=X`.
- If payload is any other JSON value/object, the gateway treats it as `ok=true` and `body=<that value>`.
- If payload is not valid JSON, the gateway treats it as `ok=true` and `body=<raw string>`.

This is intentionally similar to Request/Reply messaging patterns (Enterprise Integration Patterns), but keeps the internal contract soft so existing handler systems can adapt with minimal churn.


### 3.4 Runtime components

#### 3.4.1 `FederationFacade`
Implements subscription leases and event forwarding.

- Handles internal RPC endpoints:
  - `_federation.accepts.subscribe`
  - `_federation.accepts.refresh`
  - `_federation.accepts.unsubscribe`

- Maintains subscription state:

```ts
{ id, sourceTopic, sinkRealm, sinkPath, expiresAtMs }
```

- Subscribes to each source topic on the local bus.
- On event publish, wraps as `MxEnvelopeV1` with `msgType='Evt'` and publishes to sink realm mailbox.

This maps to the EIP patterns:

- "Message Channel" (NATS subjects)
- "Message Router" (forwarding)
- "Idempotent Receiver" (lease refresh)

#### 3.4.2 `SessionDirectory` + `SessionsFacade`
Implements a home-realm directory mapping `principalKey → [tabRealm...]`.

- Prevents spoofing: tabRealm is derived from the envelope's `fromRealm` (via internal meta), not from request body.
- Supports:
  - `sessions.accepts.register`
  - `sessions.accepts.heartbeat`
  - `sessions.accepts.lookup`

This enables unsolicited push:

1. Agent looks up principal tabs in home realm.
2. Agent sends `Evt` to each tab realm mailbox.
3. Tab realm EdgeGateway delivers event to local bus.

#### 3.4.3 `RouterBridge`
Implements a hierarchical routing overlay (MXROUTE-style).

- Each realm has a route inbox:
  - `mx/route/1/<realm>/<shard>`
- Routers form a tree (parent + child prefixes).
- Messages are forwarded upward until reaching a router whose subtree contains the destination, then forwarded down.
- TTL (`env.ttl`) is decremented at each hop.

This is a classic POSA-style "Broker" / "Forwarder" pattern combined with EIP "Routing Slip" semantics.

#### 3.4.4 `LocalRequestReplyClient`
Provides intra-realm request/reply on the internal bus (useful for tests and as a reference).

### 3.5 Security (MVP scaffolding)

Security in this repo is explicitly MVP-level but structurally correct:

- `principal.ts`: derives a stable `principalKey`
- `policy.ts`: policy port, plus a prefix-deny example policy
- `ratelimit.ts`: token bucket limiter
- `replay.ts`: replay cache

The *pattern intent* is the important part:

- **Chain of Responsibility** for inbound checks.
- All checks are concentrated in `EdgeGateway`.

## 4. Compatibility strategy

### 4.1 Strangler Fig dual subscription
Both client and server subscribe to:

- legacy mailbox (`public.ingress.<realm>`)
- mx mailbox (`mx/in/1/<realm>/00`)

Which encoding is used on publish is controlled by `WireProfile.encode`:

- `matrix3` profile publishes legacy by default
- `mxenv1` profile publishes MXENV/1 by default

### 4.2 Tolerant URI parsing
MXURI parsing accepts both legacy and segmented representations.

## 5. Test suite & coverage matrix

Tests are split into unit + integration.

### 5.1 Unit tests

- `tests/unit/mxesc1.test.ts`: encoding/decoding
- `tests/unit/topics.test.ts`: mailbox + internal topic derivations
- `tests/unit/uri.test.ts`: tolerant MXURI parsing
- `tests/unit/topic_filter.test.ts`: wildcard matching semantics

### 5.2 Integration tests

- `tests/integration/request_reply.test.ts`
  - local-to-local (internal bus)
  - public-to-realm (matrix3 legacy)
  - public-to-realm (mxenv1)
  - confirms backbone subscriptions contain no wildcards

- `tests/integration/subscription.test.ts`
  - subscribe / refresh / unsubscribe
  - event forwarding from source realm local bus → backbone → sink realm local bus
  - lease expiry behavior

- `tests/integration/directory.test.ts`
  - register + heartbeat + lookup
  - spoof prevention (tabRealm derived from fromRealm)
  - expiry cleanup
  - unsolicited push via Evt envelopes

- `tests/integration/discovery.test.ts`
  - direct preferred when available
  - fallback to backbone when direct publish fails
  - verifies the "either direct or public transport" requirement

- `tests/integration/router.test.ts`
  - hierarchical routing overlay end-to-end
  - TTL exhaustion drop
  - unknown route drop

- `tests/integration/security.test.ts`
  - anti-open-relay drop
  - msgId dedup via replay cache
  - rate limiting emits Nack
  - policy denial emits Nack

## 6. What is intentionally *not* implemented

This repo is a protocol-focused reference; a production deployment would add:

- Real NATS adapter (`Transport` implementation using a real client)
- MXDISC/1 discovery (`/.well-known/...`) and endpoint negotiation
- MXSEC/1 JWT/JWKS validation (cryptographic verification)
- Durable storage for directory and subscriptions
- Distributed replay cache

The abstractions are intentionally shaped so these can be plugged in without rewriting core logic.
