← Developers

00.2 — Engine isolation

Spec matching SPEC-DX-01

The Invariant

Every engine in Axiom-Trace owns exactly one bounded context and talks to the rest of the system exclusively through production events — never through shared tables, never through direct calls.

Strict isolation of responsibilities is the only shield against technical debt and the end of scalability.

Violating this — a foreign-key into another engine’s table, a synchronous cross-engine call — creates a distributed monolith. The architecture exists precisely to prevent that.

The Contract

The engine map — one responsibility each, no overlap:

Engine Owns Publishes
Edge runtime (manifest-driven) Business writes: RBAC, FSM, constraints, data-link, audit ax_cdc_outbox → cp_events
CDC sync engine Outbox drain, retry, backoff, signed envelopes POST /sync/ingest → Control Plane
Control Plane Tenancy, billing, fleet sync, manifest/license authority Signed manifests/licenses → edge
Notification workers Outbox delivery (mail, SIEM webhooks), retention Reads cp_notification_outbox / cp_audit_outbox
Vertical profiles (profiles/) Domain triggers/queries via manifest Read models on cp_events, biz_* on edge

Cross-engine rule: engines may read the shared event stream and their own tables — nothing else. A new vertical gets the same deal: one bounded context, events in, projections out.

The Flow

producer (dashboard / machine client)
   │  POST /actions/:trigger
   ▼
edge runtime ── FSM + RBAC + constraints ──► biz_* + audit + ax_cdc_outbox
                                                    │  drain, signed
                                                    ▼
                                              cp_events ──► cp_aggregates
                                                    │
              ┌──────────────┬──────────────────────┤
              ▼              ▼                      ▼
        portal reads     SIEM webhooks read    admin reads
        (usage/audit)    (signed push)         (fleet/events)

No arrow ever bypasses the event stream. The notification worker does not query the edge; the portal does not query the sync channel; profiles do not write each other’s tables. Everyone reads facts.

Payload Example

There is intentionally no example of a cross-engine call — it cannot be expressed in the contract. What you can write:

# A read surface consuming committed facts (the only integration shape that exists)
curl -s "https://cp.axiom-trace.eu/api/v1/tenant/audit?limit=100" \
  -H "Authorization: Bearer $PORTAL_TOKEN"

To produce facts, a new vertical registers manifest triggers — see Playbook: adding a vertical.

Known Failures

Temptation Why it fails
“Just read the edge’s local files” Filesystem coupling — the FileEventStore format is private to the runtime
“Let a profile write the business row directly” Bypasses RBAC/FSM/audit/dedup — the row is a fact, only the action engine writes facts
“Call the notification worker synchronously from the action” Latency coupling: a slow mailer now stalls production writes — that’s why the outbox exists
Shared “common” table between two engines Hidden contract — the classic distributed-monolith seed