JJijibora Docs
docs.jijibora.online
On this page (8 sections)

Data Fabric — Message Bus and Engine Interfaces (Developer Concept Doc)

Status: 2026-11-09. Audience: engineers who build event producers, consumers, and payload bridges. Contract: each mechanism below is a declared path; nothing here invents a new path. (Source: operational memory event-spine design and claims orchestration docs.)

1. Event spine — interest-based subject fabric

PROBLEM — producers and consumers are coupled by direct calls. If every vertical calls every other vertical, a change in one vertical breaks all its callers, and no governance surface exists for the coupling. (Source: Doc 32 spine scope.)

MECHANISM — the event spine owns one canonical envelope format, a broadcast family, and interest-based subject routing. Producers emit the canonical envelope on their criteria-style subject; consumers subscribe by interest rather than by point-to-point address; the fabric is aligned to ceilings, tiered evaluation, and explicit playbook publisher/consumer declarations. (Source: Doc 32 §§1–5.)

INTERFACES — envelope definition, criteria subjects, playbook contracts.

  • Canonical envelope format. Payload = { correlation_id, trace_id, voyage_id, envelope_subject, payload, headers?, signature?, proof? }. The envelope_subject is a criteria-style subject that the router matches against subscribed playbooks. correlation_id is a globally unique id for this claim end-to-end. trace_id is the hop-level trace. voyage_id is the full claim-voyage reference. payload is the structured data for the declared stage; headers carries forward any request headers as key/value pairs; signature and proof carry PoCE or gate signatures. Empty or missing fields are permitted and handled by the consumer's declared allowlist.
  • Criteria-style subjects. Subjects follow the platform.criteria.v1.* family: platform.criteria.v1.assert, platform.criteria.v1.lifecycle, platform.criteria.v1.claim, platform.criteria.v1.subscription, platform.criteria.v1.delivery, platform.criteria.v1.playbook.request, and platform.criteria.v1.playbook.response. The subject egress.camel.{route} is the outbound protocol-gateway bridge; ingress.camel.{route}.response and ingress.camel.{route}.failed are the response and error families. A playbook's publisher_subject and consumer_subject are declared in the playbook and used to route.
  • Playbook contract. A playbook declares publisher_subject, consumer_subject, enrichments, and resolver — the engine resolves the subject, validates against the allowlist, and dispatches the declared handler.

INVARIANTS — never direct-publish as the record; the durable store remains the record plus a bounded vocabulary; delivery is transactional first and published second; background work uses events, not polling; sweep endpoints are recovery only. (Source: operational memory mandates.)

2. Outbox + relay — durable delivery + guaranteed publish

PROBLEM — if a producer writes an event and the bus is down, the event is lost. Synchronous call chains then swallow errors and cannot be replayed. (Source: operational memory outbox design.)

MECHANISM — the outbox is a durable table; the producer writes a delivery anchor transactionally (CREATE nats_outbox). A relay reads from the outbox and publishes to NATS JetStream. The producer writes { subject, payload, headers, status, created_at, correlation_id, trace_id, envelope_subject } to the outbox table; the relay reads pending rows, marks status='sent', publishes to the NATS subject, and on success marks status='delivered'; on failure marks status='failed'. Every row has a bounded retry count; after max retries status='dead-letter' and an audit row is created. The relay reads per-subject bounded prefixes, and every nats_outbox row has an auto-index on (subject, status) so the relay can SELECT ... WHERE status='pending' LIMIT 100 without a full scan. (Source: Doc 32 §§3–5 and operational memory outbox relay.)

INTERFACES — producer writes to outbox, relay reads and publishes.

  • Producer write (at transition, finalise, or lifecycle signal). CREATE nats_outbox SET subject='platform.criteria.v1.lifecycle', payload={claim_id, stage}, correlation_id='...', trace_id='...', envelope_subject='platform.criteria.v1.lifecycle'; The exact field names are determined by the schema; the anchor fields are: correlation_id, trace_id, envelope_subject, status (pending/sent/delivered/failed/dead-letter), created_at.
  • Relay read + publish. SELECT * FROM nats_outbox WHERE status='pending' LIMIT 100; per subject. For each row: publish to the NATS subject; on success UPDATE nats_outbox SET status='delivered' WHERE id = $row.id; on failure UPDATE nats_outbox SET status='failed' WHERE id = $row.id; then after max retries UPDATE nats_outbox SET status='dead-letter'.
  • Delivery anchor fields. correlation_id, trace_id, envelope_subject, payload, headers, status, created_at. The anchor is the durable write that survives process restart.

INVARIANTS — never skip the anchor; relay is best-effort — failure never blocks the legacy write (LET $_ = ...); every row has bounded retry count and a dead-letter after max retries; the durable store remains the record plus a bounded vocabulary; background work uses events, not polling; sweep endpoints are recovery only. (Source: operational memory mandates.)

3. Claims-spine consumer — event-to-claim dispatch

PROBLEM — lifecycle events arrive on the bus but must be turned into claim transitions. Without a consumer, events sit undelivered and the claim path does not advance. (Source: claims orchestration backlog REVIEW-03.)

MECHANISM — a Kestra-based consumer on the event spine subject family. The consumer listens on platform.criteria.v1.lifecycle, validates each event against its pack's declarative allowlist, computes the required transition, and dispatches the claim plane's guarded transition function. The consumer also records the event in the claims outbox and emits a delivery anchor. If the transition guard refuses, the consumer records the refusal as a failed outbox row and emits an error envelope. The consumer does not re-emit the same event; it only advances the claim once per event. (Source: claims-spine consumer design; REVIEW-03.)

INTERFACES — consume, dispatch, record refusal. Callers publish lifecycle events on platform.criteria.v1.lifecycle; the consumer validates and dispatches; on refusal the caller receives the guard's typed error.

INVARIANTS — the consumer does not re-emit the same event; it only advances the claim once per event; event refusal is recorded as a failed outbox row; the consumer does not advance if the guard refuses. (Source: claims-spine consumer invariants.)

4. Money subject families — billing and entitlement events

PROBLEM — billing and entitlement events need their own subject families distinct from lifecycle. The claims spine and money spine use different envelopes and subject families so that billing middleware does not accidently read claims events and vice versa. (Source: Doc 32 money subject families.)

INTERFACES — money events on their own subjects. platform.criteria.v1.money.billing, platform.criteria.v1.money.entitlement, platform.criteria.v1.money.settlement, platform.criteria.v1.money.refund. Payloads carry subscription-id, wallet-id, split-profile-id, invoice-id, credit-note-id, and the declared amount/rate. Money events do not carry claim payloads; they carry money-specific fields only. (Source: money spine design.)

INVARIANTS — money events never carry claim payloads; billing middleware never reads claims subjects; the money spine never advances a claim. (Source: money spine invariants.)

5. Solver bridge — matcher engine dispatch

PROBLEM — sourcing decisions need to go through the solver engine. Bids, baskets, and split allocations originate from solver calls. (Source: matching engine design.)

**MECHANISM — the solver bridge subscribes to sourcing subjects on the event spine and invokes the matching engine (fn::matching::solver::greedy, etc.) with capability procurement.basket_split@1 and branch_and_bound 1.4.0. The solver bridge receives the solver result and emits the corresponding outbound event on the money/spending subject families. (Source: matching engine design; solver capability references.)

INTERFACES — subscribe to sourcing subjects, invoke solver, emit result.

  • Subscribe. Listen on platform.criteria.v1.assert or platform.criteria.v1.claim with a basket specification in the payload.
  • Invoke. SELECT fn::matching::solver::greedy(...), or the basket-split or re-route functions.
  • Emit result. On success, emit a money event on platform.criteria.v1.money.settlement; on failure, emit an error envelope.

INVARIANTS — solver results never bypass the event spine; every solver invocation emits an outbox anchor; solver bridge failures produce typed errors, never synthetic success. (Source: matching engine invariants.)

6. Interface catalogue — capability-to-route resolution

PROBLEM — every new capability needs a routing target; without a catalogue the caller must hand-code which BFF endpoint or integration route to use. (Source: gateway architecture.)

MECHANISM — the interface catalogue is the CNS-registered mapping from capability name to BFF route or integration path. Capability names are CNS-typed paths (e.g. cns://capability/kujenga/project/manage), and the catalogue resolves one route entry per capability: { capability, bff_route, integration_route, camel_route, use_camel, fail_closed_on_missing }. The catalogue is populated declaratively (pack configuration + CNS registration) and queried at runtime by the Agent BFF dispatcher (apps/agent-bff/src/compliance-api-dispatcher.js). (Source: Doc 02 gateway capability resolution; operational memory interface catalogue.)

INTERFACES — lookup, resolve, register. Callers look up a capability in the catalogue; the dispatcher resolves the route and dispatches accordingly; on missing capability the dispatcher fails closed with HTTP 502/503 and a PoCE receipt on success.

INVARIANTS — no hardcoded route per capability; every route is declared in the catalogue; fail-closed on missing capability. (Source: gateway invariants.)

Interface summary

CapabilityCore interfaceContract
Event spineCanonical envelope, criteria subjects, playbook contractenvelope_subject, correlation_id, trace_id, voyage_id, payload; subject is criteria-style
Outbox + relayProducer writes delivery anchor, relay publishes to NATS{correlation_id, trace_id, envelope_subject, payload, status, created_at}; status flows pending→sent→delivered→failed→dead-letter
Claims-spine consumerConsume lifecycle events, dispatch guarded transitionsValidate against pack allowlist; dispatch transition; record refusal as failed outbox
Money subject familiesBilling/entitlement/settlement/refund eventsmoney-specific payloads, never carry claim payloads
Solver bridgeSubscribe to sourcing, invoke matching engine, emit resultsfn::matching::solver::greedy, capability procurement.basket_split@1
Interface catalogueCapability → route resolutionCNS-typed capability → BFF/integration/camel route, fail-closed on missing