Skip to content

Independent R&D project · Cologne

Probabilistic Boundary

A probabilistic component is bounded and cannot directly become an authoritative domain output.

Non-normative

Companion version
1.0
Maps to COADF Core
2.2
Status
Current
Last reviewed
COADF principles
P-1, P-5

Architectural property

COADF P-1 states the minimum: a probabilistic component returns a value together with a confidence and the method the value was obtained by, never a bare value, and it never reaches an output directly. This pattern is about the second half, which is the half implementations lose. A model's answer may enter the system. What it may not do is become, by any path, the thing the system treats as established.

Three things have to hold at once:

  • The output has a type of its own. A proposal and an authoritative record are different types, different tables or different messages. Code holding one cannot pass it where the other is expected without an explicit step somebody can review.
  • The boundary validates at run time. The contract is checked when the reply arrives, in the process that receives it, whatever the sender says it checked.
  • Provenance travels with the value. The method, the model and its revision, the prompt revision and the location in the source stay attached through every step, serialisation included. Without them P-4 cannot reconstruct and P-5 cannot disclose.

P-1 also has the component report a confidence. How confidence is expressed, assigned and used belongs to P-2, which COADF publishes as a principle only. This Companion does not describe it, and nothing below depends on it.

Why it matters

A model's output comes from a process that cannot be reproduced from its inputs the way a parser's output can: sampling, model updates and prompt changes all move it. That is acceptable for a proposal and unacceptable for a fact. The risk is not that a model is sometimes wrong; everything is sometimes wrong. The risk is losing the ability to say which values came from where, because every later control depends on it. A gate stops only what it can see, a disclosure names only what is marked, and a reviewer checks only what still points at its source.

The loss is rarely a decision. It happens on an ordinary line of code: an ORM entity populated from the model's JSON because the field names happened to match, a response model that drops the provenance because nobody added it, a batch import that bypasses the form where the validation lived. The pattern exists to make that line impossible to write without noticing.

Valid implementation strategies

Isolation is architectural, not necessarily physical

Microservices are not required. The property holds when no code path lets the probabilistic side produce an authoritative object, and a single process can keep it as well as a network can. Choose the topology for its own reasons (scaling an inference workload separately, isolating a vendor's client library, deploying independently) and then build the boundary in whichever shape you chose. The four figures below keep the same property in four shapes.

Example architecture · Non-normative

Modular monolith

Example architecture, non-normative: a modular monolith in which a model client, a boundary module, a domain core and a classification adapter share one process, with the audit trail and an external service outside it.Inside one process: a model client, marked probabilistic, passes its raw reply to a boundary module, which passes a Proposal to the domain core. A classification adapter, also inside the process, may pass an enrichment to the domain core, and it looks up an external classification service outside the process. The domain core writes entries to the audit trail, a separate database. The only path from the model client to the domain core runs through the boundary.One process, one deployable unitModel clientprobabilisticBoundarytyped contract,validation, provenanceDomain coreproposals kept apartfrom verified recordsClassification adapterbehind a portAudit trailappend-onlyExternal serviceclassificationraw replyProposalentries
  • Data flow in this example
  • Optional: may be unavailable
One process. The boundary is a module, and import contracts keep the model client from reaching the domain core except through it.

Text description. Inside one process: a model client, marked probabilistic, passes its raw reply to a boundary module, which passes a Proposal to the domain core. A classification adapter, also inside the process, may pass an enrichment to the domain core, and it looks up an external classification service outside the process. The domain core writes entries to the audit trail, a separate database. The only path from the model client to the domain core runs through the boundary.

Example architecture · Non-normative

Service-oriented

Example architecture, non-normative: an inference service with a model client and a boundary, and a domain service with its own boundary, domain core, classification adapter and audit trail.An inference service contains a model client, marked probabilistic, and a boundary that validates what it sends. It sends over HTTP, under a JSON contract, to a domain service, whose own boundary validates what it receives and passes a Proposal to the domain core. The domain service also contains a classification adapter, which looks up an external service and may pass an enrichment to the domain core, and the audit trail, to which the domain core writes entries. The inference service has no connection to the audit trail.Inference serviceDomain service and its storeModel clientprobabilisticBoundaryvalidates whatit sendsBoundaryvalidates whatit receivesDomain coreproposals apartfrom verified recordsClassificationadapterAudit trailappend-onlyExternal serviceclassificationraw replyHTTP, JSONProposalentries
  • Data flow in this example
  • Optional: may be unavailable
Two services. Each side validates: the sender what it sends, the receiver what it receives. The inference service holds no credentials for the domain's store.

Text description. An inference service contains a model client, marked probabilistic, and a boundary that validates what it sends. It sends over HTTP, under a JSON contract, to a domain service, whose own boundary validates what it receives and passes a Proposal to the domain core. The domain service also contains a classification adapter, which looks up an external service and may pass an enrichment to the domain core, and the audit trail, to which the domain core writes entries. The inference service has no connection to the audit trail.

Example architecture · Non-normative

Event-driven

Example architecture, non-normative: an inference worker publishes proposals to a topic, and a domain consumer validates them on receipt before the domain core writes audit entries.An inference worker contains a model client, marked probabilistic, and a boundary. It publishes a message to a topic of proposals. The message body carries the audit trace_id; its headers carry the execution context as a W3C traceparent. A domain consumer reads the topic, validates each message on receipt, and passes a Proposal to the domain core, which writes entries to the audit trail.Inference workerDomain consumerModel clientprobabilisticBoundaryvalidatesbefore publishingTopicproposalsBoundaryvalidateson receiptDomain coreproposals apartfrom verified recordsAudit trailappend-onlybody: trace_idheaders: traceparentpublishconsumeProposalentries
  • Data flow in this example
A topic between the two sides. The audit trace_id travels in the message body as part of the contract; the execution context travels in the message headers.

Text description. An inference worker contains a model client, marked probabilistic, and a boundary. It publishes a message to a topic of proposals. The message body carries the audit trace_id; its headers carry the execution context as a W3C traceparent. A domain consumer reads the topic, validates each message on receipt, and passes a Proposal to the domain core, which writes entries to the audit trail.

Example architecture · Non-normative

Cloud-native deployment

Example architecture, non-normative: an inference namespace, a model-serving namespace and a records namespace, with egress from inference allowed only to the model endpoint and to the proposal intake.In the inference namespace, an inference pod runs the model client and its boundary. It may send to the model endpoint in the model-serving namespace, and to the proposal intake in the records namespace, on its API port only. The proposal intake validates what it receives and passes a Proposal to the domain core, which writes to the audit trail and records database. A note states that the inference namespace has no route and no credential to that database.Namespace: inferenceNamespace: model-servingNamespace: recordsInference podmodel clientand boundaryModel endpointProposal intakevalidateson receiptDomain coreproposals apartfrom verified recordsAudit trail andrecords databaseNo route and nocredential from theinference namespaceegress allowedAPI port onlyProposalentries
  • Data flow in this example
Three namespaces. The inference pods may reach the model endpoint and the proposal intake's API port; no route and no credential reaches the database.

Text description. In the inference namespace, an inference pod runs the model client and its boundary. It may send to the model endpoint in the model-serving namespace, and to the proposal intake in the records namespace, on its API port only. The proposal intake validates what it receives and passes a Proposal to the domain core, which writes to the audit trail and records database. A note states that the inference namespace has no route and no credential to that database.

The same four elements in every topology

  • Distinct types. The probabilistic side can construct a proposal and nothing else. The authoritative record is built only by domain code, from a proposal plus something the probabilistic side cannot produce.
  • Runtime validation on every receiving side. A strict schema: undeclared fields rejected, no type coercion, closed vocabularies for categorical values, bounded lengths. In a distributed topology each receiver validates, the domain side included when the sender is your own service: "we validated before sending" is a claim about another deployable, possibly an older version of it.
  • Provenance in the contract. Declared, required, and preserved by every mapper and serialiser on the way out.
  • An explicit promotion step. The only route from proposal to authoritative record is a function, endpoint or command that demands what the probabilistic side cannot supply. For values derived by a language model, COADF's public fence F-03 requires human verification before they reach a published output. The promotion is itself recorded in the audit trail.

Deterministic validation around stochastic output

Checks that read only the value (its form, its vocabulary, its unit, the ranges the domain itself defines) run before any person looks at it. They do not make a value true. They make an impossible value impossible, and they do it the same way every time, which a person reviewing the value can rely on.

Enforcement options, from weakest to strongest

What each enforcement mechanism stops, and what it does not
MechanismStopsDoes not stop
Type separationAccidental promotion in code that type-checksCasts, dynamic typing, reflection
Runtime schema validationMalformed or over-claiming repliesA well-formed value that is wrong
Architecture test on importsThe probabilistic module importing record-writing codeImports made by name at run time; data paths that are not imports
Database grants per componentA component writing the authoritative storeComponents that share credentials
Separate deployment and network policyA separately deployed component reaching the store at allAnything inside one process; clusters whose network plugin does not enforce the policy

Most systems want the first three always, and the last two when the probabilistic component is deployed on its own. The Python and FastAPI profile implements the first three; the Cloud-Native profile adds the last two.

Failure modes

  1. Model output written straight to authoritative storage

    The reply is parsed into the entity the rest of the system reads as fact, because the fields matched. No single line is wrong. The boundary simply does not exist.

  2. Proposals indistinguishable from verified data

    One table, one type, and a flag that says which is which. The flag defaults to the convenient value, or the model's own JSON can set it.

  3. Provenance lost on the way out

    A mapper, a response model or an export omits the method and the source. Frameworks that filter output to a declared schema do this without a sound: FastAPI filters a response to its response model, and Fastify's serialiser leaves out properties a response schema does not list unless the schema allows additional properties.

  4. Validation only in the user interface

    The form validates. The batch import, the administration script and the second client do not.

  5. Downstream systems cannot tell inferred from verified

    The export format has no field for the method, so the next system receives a value and nothing else, and every control it has is blind to the difference.

  6. The raw reply trusted without runtime validation

    A cast in TypeScript, a dictionary in Python, a lenient mapper in Java: the contract exists in the code's types and nowhere in its behaviour. TypeScript's type annotations are erased at compile time, and its standard typings declare the result of JSON.parse as any.

  7. Coercion hides the model's error

    Lax parsing turns "12" into 12 and "true" into True. The number looks right and was never a number. Pydantic's strict mode refuses that coercion; Fastify's default validator configuration enables type coercion. Know which one you are running.

  8. Silent repair

    The reply fails validation, so the call is retried until a reply passes, and only the last one is kept. The failures were evidence about the model, and they are gone.

  9. Validation bypassed for speed

    An optimisation that constructs objects without validation becomes the easiest path, and then the bypass. Pydantic's model_construct creates a model without validating it, exactly as documented.

Verification

  • Unit test

    Passes when: Each malformed reply is rejected: an undeclared field, a coercible type, a missing provenance, an attribute nobody asked for.

    Proof of teeth: Delete one constraint in a scratch copy (for instance the rule that rejects undeclared fields): the matching test must fail.

  • Architecture test

    Passes when: The probabilistic module has no import path to the code that writes authoritative records.

    Proof of teeth: Add the forbidden import in a scratch copy: the contract fails and the build stops.

  • Contract test

    Passes when: Producer and consumer agree on the proposal schema, with the provenance fields required.

    Proof of teeth: Remove a provenance field from the producer's schema: the consumer's contract test fails.

  • Integration test

    Passes when: When the probabilistic component is deployed on its own, its credentials cannot write the authoritative store.

    Proof of teeth: Attempt the write with those credentials: the database refuses it.

  • End-to-end test

    Passes when: An output whose attribute came from a proposal that nobody verified cannot be published.

    Proof of teeth: Plant an unverified proposal and request publication: refused, and the refusal is in the audit trail.

Alternative realizations

  • Suggestion-only interfaces. Model output is shown to a person as a suggestion and never stored as a value. Simple and strong; it gives up the traceability of what was suggested unless suggestions are recorded as well.
  • A shared, language-neutral contract (JSON Schema, Protocol Buffers) instead of language-native models. Better across languages; it moves the strictness question into the schema, where additional properties and formats have to be decided explicitly.
  • Structured-output modes of model APIs. They reduce malformed replies at the producer. They do not relieve the consumer of validating, because the consumer cannot verify how the producer was configured.
  • Separate storage for proposals and records, two tables or two stores rather than one table with a status. Heavier, and it makes the separation visible to every query anybody writes.

Limitations

  • The boundary controls where model output can go. It does not make model output correct, and a well-formed wrong value passes every check in this pattern.
  • Type separation stops accidents, not intent. A developer with write access to the domain can construct an authoritative object by hand; code review and the audit trail are what make that visible.
  • This pattern does not say when a proposal needs a person, or how confidence is expressed. Those belong to P-2 and P-3, which COADF publishes as principles only.
  • Validation is only as good as the contract. A permissive schema, validated strictly, is still permissive.

Sources

COADF Engineering Companion 1.0 · non-normative · maps to COADF Core 2.2

Publication rights reserved. No public licence is granted for the COADF Engineering Companion 1.0 or its reference examples at this time.

IP and publication status