Kronaxis Compliance Book a pilot
Integrations · where the gate physically sits

Certify at the
egress.

The gate sits at the last controllable moment before an action becomes real or irreversible. The egress can be a piece of software (an SMTP relay, an SMS gateway, a publish webhook) or a physical actuator (the electronic lock on a medicine cabinet, the door release at a nursery). The same gate, the same receipt, the same maths.

nine egress patterns catalogued built vs reference, badged honestly wrap, do not rewrite
The principle in one paragraph

If it happens, we certify it. Deployed inline, we stop it.

A regulated action does not become real at the moment the user clicks send. It becomes real at the egress: the SMTP 250 OK, the SMS submit, the RTP packets going out over the trunk, the publish API 2xx, the database write commit, the unlock signal to a controlled actuator. The gate sits at that boundary and binds a permit to the descriptor of the action before the boundary is crossed.

Two consequences fall out of this. Out of band, the gate certifies everything that happens and writes a sealed receipt; it never blocks. Inline, a permit is required before the boundary is crossed; no permit, no action. The verdict and the proof are byte identical in either deployment.

One mapping per surface. An adapter takes whatever event the surface emits (an outbound email, an SMS request, a SIP INVITE, a publish API call, a row insert, an actuator command) and produces one canonical descriptor. The engine never asks the surface to change shape.
Two deployment shapes

Inline. Out of band.

Both consume the same engine, the same ruleset, the same quorum and the same on ledger proof. The only thing that changes is whether the action is allowed to proceed in parallel with certification, or has to wait for a permit.

Inline · enforce

A permit is required to proceed.

The gate sits in the critical path. The surface calls certify() before it does the send. On refuse, the surface refuses; on comply, the surface goes ahead and the permit is bound to the action.

Source CRM / API / agent Compliance gate baseline + overlay quorum + consensus PERMIT REQUIRED Egress SEND / UNLOCK Refused 451 / locked comply refuse
  • Adds one round trip per action. Policy evaluation is sub millisecond; the BFT commit dominates.
  • On refuse: HTTP 451 with refusal code, or actuator stays in its safe default position.
  • Reference: modes.NewEnforceMiddleware wraps any http.Handler.
Out of band · observe

A tap. Never in the critical path.

The gate sees a mirror of every action: a CDC stream, a bus tap, a log shipper, a webhook receiver. The verdict and the proof are written; the surface is never blocked. Refusals become alerts.

Source CRM / API / agent Egress unchanged production path: not touched mirror Compliance gate certify, record, alert NEVER BLOCKS Alert sink SIEM / Slack
  • Adds zero latency to the production path by construction.
  • Refusals become alerts to the firm’s SIEM, Slack, or PagerDuty.
  • Reference: modes.NewIngester reads any source feeding NormalisedAction records.
Identity of verdict across shapes
The same descriptor produces the same descriptor hash, the same verdict, the same refusal code and the same proof shape whether it crossed the gate inline or via a mirror. The pilot a buyer runs in Observe is not a different product from the eventual Enforce deployment. Graduation is a per surface flag flip.
Egress point catalogue

Nine surfaces. One boundary.

Each card names the egress, the chokepoint the gate wires into, and what happens when a refusal lands in observe or enforce. Built pattern means the canonical software shape is shipped today and exercised on the reference build. Reference design means the wiring against real hardware is designed and reviewed, not deployed.

Email

Built pattern

What: outbound email leaves through an SMTP relay or a send API (SES, SendGrid, Mailgun, Postmark, Stalwart). The egress is the moment the relay accepts the message for delivery.

Wiring: an SMTP proxy or milter in front of the relay, or HTTP middleware in front of the send API. The proxy lifts recipient, content class, jurisdiction and ruleset from the message into a descriptor and calls certify() before relaying.

Observe
Tap a Bcc copy or read the relay’s queue log; alert on refuse, deliver as normal.
Enforce
Refusal returns 5xx to the sender; the relay never sees the message.

SMS

Built pattern

What: outbound SMS submits to an aggregator (Twilio, Vonage, BT Wholesale, MessageBird) over HTTP, SMPP, or a local SIM bank. The egress is the submit API call or the SMPP submit_sm.

Wiring: a thin gateway shim in front of the aggregator API. The shim accepts the firm’s existing send shape, certifies the descriptor, and forwards on comply.

Observe
Mirror the submit log; alert on refuse, no change to delivery.
Enforce
Refusal returns an error to the caller before the aggregator is touched.

Voice and calls

Built pattern

What: outbound voice leaves through a SIP trunk or a telephony API (Twilio Voice, our own sip-voice-bridge on the Kronaxis voice stack). The egress is the SIP INVITE sent to the carrier or the dial API call.

Wiring: a permit check in the dial path before the INVITE is sent. The descriptor carries called number, caller ID, campaign and operating hours; the gate refuses or permits before the trunk is engaged.

Observe
Mirror CDR / SIP trace; alert on a call that should not have been placed.
Enforce
Refusal aborts the dial before any RTP is exchanged.

Push, in app and ad networks

Built pattern

What: APNs / FCM pushes, in app messages from a CDP, and ad feed publishes to Meta / Google / TikTok / DV360. The egress is the notification service API call or the ad feed upload.

Wiring: HTTP middleware in front of the notification or ad publication API. The same NewEnforceMiddleware shape covers all of these because they are HTTP calls; the descriptor extractor is per provider.

Observe
Webhook receiver on send confirm events; alert on policy violating sends.
Enforce
Refusal returns 451; the push or ad never reaches the network.

Web and content publishing

Built pattern

What: a CMS publishes a page, a landing page builder pushes a variant, a static site build promotes content to production. The egress is the publish webhook or the CDN cache warm.

Wiring: a pre publish webhook calls certify() with a descriptor representing the page, the audience, the ruleset and the jurisdiction. On refuse the publish is held; on comply it goes live and the proof is co resident with the published version.

Observe
Post publish crawler diff feeds the ingester; alert on non conforming pages.
Enforce
Refusal blocks the publish step; the build can show the refusal code in the CI log.

Database writes and automated decisions

Built pattern

What: a service writes a row that represents a regulatory decision (an account opened, a credit limit increase, an affordability override, an AI agent action). The egress is the commit, or the API call upstream of the commit.

Wiring: two options. Upstream: the calling service calls the SDK before issuing the write. Downstream: a CDC stream (Debezium, logical decoding) feeds the JSONL ingester in Observe; a pre commit trigger fires the SDK and aborts on refuse in Enforce.

Observe
CDC mirror; alert on a write that should not have committed.
Enforce
Refusal aborts the transaction (Enforce capable databases) or rejects the upstream API call.

Pharmacy · medicine cabinet

Reference design

What: a computer controlled medicine cabinet (an electronic lock, a controlled drug cupboard, an automated dispensing unit) holds a a Schedule 2 or Schedule 3 medicine. The egress is the unlock signal sent to the actuator that releases the drug.

Wiring: the dispensing system asks the gate for a permit before firing the unlock. The descriptor carries patient, prescriber, schedule, the dispensing pharmacist’s identity and the GPhC ruleset. No permit: the cabinet stays locked. Every dispense leaves a tamper evident proof bound to the unlock event.

Observe
Mirror the dispense log; alert on a release that should not have happened.
Enforce
Unlock is conditional on a fresh permit; the actuator is fail CLOSED by design.

Early years · door release & photos

Reference design

What: two egresses in a nursery setting. The door release that authorises a child to be collected, and the publish step that releases a photo or video of a child to a parent or to the nursery feed.

Wiring: the access control panel and the photo sharing service each call the gate before acting. The descriptor carries child, collecting adult (against the authorised collector list), photo consent state and the EYFS aligned overlay. No permit: the door stays locked, the image is not released.

Observe
Tap the access log and the photo publish log; alert on a release that breached consent.
Enforce
Door release / photo publish gated on permit. Life safety nuance below.

Generic actuator · IoT, PLC, robot

Reference design

What: any device boundary where a software signal turns into a physical change: a PLC opening a valve, a robot starting a motion, an access control relay closing, a smart meter disconnect command, an industrial chemical dosing pump firing.

Wiring: a signed permit to actuate at the device boundary. The edge controller checks the permit’s signature and binding before firing the actuator. The descriptor names the actuator, the operator, the safety ruleset, and the conditions under which actuation is allowed.

Observe
Tap the actuation log over MQTT / OPC UA / Modbus mirror; alert on policy violating actuations.
Enforce
Edge controller refuses to actuate without a valid permit; fail default is per device.
Integration mechanics

A few lines. One hop.

The wiring pattern is small and repeatable. Whatever the surface, the integrator picks one of four shapes. The engine’s entry point is the same in every case: one certify() call against one NormalisedAction.

SDK call

First party code links the Go SDK (TypeScript and Python wrappers planned for release) and calls Certify directly. The lowest latency shape; the surface owns the descriptor mapping.

// inline at the send site
v, err := svc.Certify(ctx, ingest.NormalisedAction{
    Origin:     ingest.OriginService,
    Mode:       ingest.ModeEnforce,
    Descriptor: descriptorFromSend(req),
})
if v.Outcome == action.Refuse { return refuse(v) }

Sidecar proxy

The HTTP shim is mounted as a sidecar in front of an existing API (SMTP relay, SMS aggregator, push service, ad publish API). No code changes in the wrapped service; the proxy adapts the request shape.

# the proxy is the surface's new front door
POST /certify  Content-Type: application/json
{ "origin":"service", "mode":"enforce",
  "descriptor": { "kind":"sendPromo", ... } }

200  { "outcome":"refuse",
       "refusal_code":"SELF_EXCLUDED",
       "proof_ref": { "log_root_hex":"fd5b..." } }

Webhook / callback

The surface fires a pre action webhook (publish API, CMS, dispense API, door release API). The webhook receiver certifies and returns an authoritative permit or refusal to the caller.

# CMS hook before publishing
POST https://gate.local/hooks/pre-publish
{ "page_id":"...", "audience":"GB-18+", ... }

200  { "permit":"signed:...",
       "proof_ref":{ "index":42, "log_root_hex":"..." } }

403  { "refusal_code":"AD_CODE_VIOLATION",
       "refused_by":"did:kxc:asa-cap-baseline" }

Message bus interceptor

A consumer on the firm’s Kafka / Rabbit / NATS / Pub Sub topic. In Observe, a mirror consumer reads read only. In Enforce, a pull permit then pull job pattern means noncompliant messages never reach the downstream worker.

# mirror consumer (observe)
for msg in bus.subscribe("outbound-sms"):
    v = svc.certify(normalise(msg), mode="observe")
    if v.outcome == "refuse":
        alerts.emit(v.refusal_code, msg, v.proof_ref)

A worked retrofit example ships alongside the engine at examples/retrofit-gambling-crm/: a sample CRM with an /send endpoint, retrofitted in three shapes (no gate, observe, enforce) by adding two or four lines at startup. The CRM’s send handler is byte identical across the three shapes; only the wiring changes.

Failure modes & safety

Fail CLOSED vs fail SAFE. Not the same thing.

Every inline surface has to answer one question: if the gate is unreachable, what does the egress do? The answer is context specific and we treat it that way. Anything else is malpractice dressed up as certainty.

Surface Default on unreachable gate Why
Outbound marketing (email, SMS, voice, push, ads) Fail CLOSED The cost of a noncompliant send is a regulator fine. Holding the message until the gate recovers is the safe choice; the firm replays from queue once the gate is back.
Database write (account change, credit limit, affordability) Fail CLOSED The audit faceable record is the write itself. A committed write the gate did not certify is exactly the gap the gate exists to close.
Pharmacy medicine cabinet Fail CLOSED A controlled drug must not be released without a valid permit. The cabinet stays locked. Local override is a separate, witnessed and logged path.
Fire egress door, life safety release Fail SAFE / fail OPEN Life safety overrides compliance. The door must release on alarm whether the gate is reachable or not; the gate records the event and surfaces a refusal code style alert if the release breached safeguarding policy, but the actuator must never trap a person.
Nursery collection door (steady state, not emergency) Fail CLOSED A child must not be released to an unauthorised adult because a server was down. Local manual procedure (signed paper register, second staff member) is the documented fallback.
Industrial actuator (valve, robot, dosing pump) Per device The safety case decides. A chemical dosing pump fails CLOSED to prevent over dosing; a coolant valve may fail OPEN to prevent overheating. The integrator’s safety engineer owns this; the gate records the choice and the outcome.
What this means in practice

Latency budgets. Policy evaluation is sub millisecond. The BFT commit is the dominant cost on inline surfaces and lands in the low single digit second range on commodity validators. Two patterns soften this without weakening the claim: pre certify at queue time and bind the resulting permit to the descriptor hash; or local quorum commit with asynchronous on chain commit afterwards. Both trade offs are explicit, not hidden.

Degraded mode and offline. A surface that cannot reach the gate either holds its queue (Enforce CLOSED), falls back to a witnessed local procedure (physical surfaces), or runs in Observe only with a documented gap (legacy surfaces with no inline chokepoint).

What we will not do. We will not silently fail open on a refused verdict. We will not paper over an offline gate. We will not pretend physical safety and policy compliance are the same question. Honest engineering, no exception.

Latency and capacity

What inline costs. How to spend it well.

Policy evaluation is sub millisecond. The BFT commit is the dominant cost on inline surfaces and lands in the low single digit second range on commodity validators today. Two patterns soften this without weakening the bound claim; both trade offs are explicit and named here.

Layer Typical cost What it does Surface impact
Descriptor canonicalisation and fingerprint under 1 ms Length prefixed binary encoding with sorted field order, hashed by a standard cryptographic fingerprint. Imperceptible on every surface.
Policy evaluation (baseline + overlay) under 1 ms Bounded time evaluation by construction. The static analyser guarantees no unbounded recursion. Imperceptible on every surface.
Digital signature verification (per signer) under 1 ms Standard unforgeable signature verification. Two role typed signatures per attestation; constant cost regardless of payload size. Imperceptible on every surface.
BFT consensus commit 2 to 4 s typical Block proposal, pre vote, pre commit, finalise. Dominates inline latency on a commodity four validator cluster. Felt on inline marketing channels; acceptable on most batch and physical actuator workflows.
Local quorum commit (variant) under 100 ms The dual authority signature is gathered locally; the consensus commit happens asynchronously afterwards. The proof binds when the commit lands; refusals are still authoritative immediately. Useful for high throughput inline surfaces; the auditor reads the eventual on chain anchor.
Pre certify at queue time (variant) amortised The descriptor is certified at queue time and the permit is bound to the descriptor hash. The egress checks the permit, not the gate, at send time. Works where the egress fires inside a freshness SLA window; the in window invalidation set still applies.
The honest tradeoff in one paragraph
The naive inline pattern (one synchronous BFT commit per action) is correct, complete, and slow. The two variants above keep the proof property intact while cutting the latency the egress sees. The choice between them is per surface, named in the integration contract, and surfaced in the audit console. We will not hide a latency variant behind language that implies the naive pattern was always used.
What goes over the wire

One call shape. Three return shapes.

Every integration surface ends up making one of three shapes of call into the engine. The descriptor extractor changes per surface; the call and return shapes do not.

Request: Certify

The surface presents a normalised action to the engine. Origin names where the action came from; Mode names whether the surface expects to block on refuse (Enforce) or just be told (Observe).

// Go SDK call (shapes are isomorphic in TS/Python)
v, err := svc.Certify(ctx, ingest.NormalisedAction{
    Origin:     ingest.OriginService,
    Mode:       ingest.ModeEnforce,
    Descriptor: action.Descriptor{
        Kind:        action.KindSendPromo,
        Tenant:      "tenant-alpha",
        Recipient:   "rcp-clean-001",
        Channel:     "email",
        ContentClass: "low_value_bonus",
        Jurisdiction: "GB",
        HourLocal:    12,
        Payload:      payloadBytes,
    },
})

Response: Permit verdict

A permit carries a signed proof reference. The surface can attach this reference to the outbound action so the receiving system also has the proof. The proof reference points at the on ledger record by index plus log root.

{
  "outcome": "permit",
  "verdict_at_unix": 1780849742263,
  "rule_set_id": "tenant-alpha/ukgc-gambling-marketing/v1",
  "proof_ref": {
    "index": 42,
    "log_root_hex": "fd5b...",
    "leaf_hash_hex": "4238...",
    "audit_path_hex": ["2415...", "189f..."]
  },
  "signatures": [
    { "did": "did:kxc:regulator-baseline:kronaxis", ... },
    { "did": "did:kxc:client-signer:tenant-alpha",  ... }
  ]
}

Response: Refuse verdict

A refuse verdict carries the named refusal code, the signing DID that refused (so the audit trail is attributable), and a proof reference to the on chain violation record. Enforce surfaces return HTTP 451 with these fields in headers and body.

{
  "outcome": "refuse",
  "refusal_code": "SELF_EXCLUDED",
  "refused_by": "did:kxc:regulator-baseline:kronaxis",
  "refused_at_unix": 1780849742263,
  "rule_set_id": "tenant-alpha/ukgc-gambling-marketing/v1",
  "proof_ref": {
    "violation_height": 8,
    "violation_hash_hex": "b5ac...",
    "outcome": "REFUSED"
  }
}

Response: Refdata stale verdict

A refdata stale verdict is a refusal whose root cause is freshness, not policy. The verdict names the register that fell behind and the SLA window it breached. The buyer’s incident response gets a contractable code to escalate against.

{
  "outcome": "refuse",
  "refusal_code": "REFDATA_STALE",
  "refused_by": "did:kxc:regulator-baseline:kronaxis",
  "stale_register": "GAMSTOP",
  "age_at_check_seconds": 1872,
  "sla_window_seconds": 900,
  "remediation": "resync upstream register; retry"
}
Trust at the edge

Same gate. Same receipt.

Every egress in the catalogue emits the same proof shape. The descriptor is canonical, the verdict is signed, the per action proof lives on the ledger next to the ruleset and the attestations. A regulator (or you, or the firm’s General Counsel) rederives the verdict from the bundle without our cooperation.

An adapter written for one surface ports to another by changing the extractor and the ruleset ID. The boundary, the canonical bytes, the verdict shape and the proof shape do not move. That is the property that makes “wrap, do not rewrite” honest.

Honest about the bounded claim
Built pattern means the integration is shipped in the product today and exercised on the reference deployment: the SDK and HTTP boundary, the NewIngester for Observe, the NewEnforceMiddleware for Enforce, the worked CRM retrofit example, and the voice stack. The six software surfaces above (email, SMS, voice, push and ads, web publishing, database writes) wrap the same boundary in a transport shaped adapter; an integrator writes the extractor for their stack. Reference design means the physical actuator integrations (pharmacy cabinet, nursery door and photo release, generic industrial actuator) are designed and reviewed against the same boundary but not yet deployed against real hardware. A pilot against a real cabinet or a real door release is the next step for those surfaces, not a current claim.