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.
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.
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.
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.
- 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.NewEnforceMiddlewarewraps anyhttp.Handler.
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.
- Adds zero latency to the production path by construction.
- Refusals become alerts to the firm’s SIEM, Slack, or PagerDuty.
- Reference:
modes.NewIngesterreads any source feedingNormalisedActionrecords.
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.
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.
SMS
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.
Voice and calls
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.
Push, in app and ad networks
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.
Web and content publishing
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.
Database writes and automated decisions
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.
Pharmacy · medicine cabinet
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.
Early years · door release & photos
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.
Generic actuator · IoT, PLC, robot
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.
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.
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. |
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.
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. |
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"
}
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.
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.