Skip to content

Independent R&D project · Cologne

Technology Notes

Short corrections of common category errors.

Non-normative

Companion version
1.0
Maps to COADF Core
2.2
Status
Current
Last reviewed

Each note corrects a category error: two things that look alike and promise different things.

OpenTelemetry is not an audit trail

OpenTelemetry records and propagates execution context: which calls a request made, how long they took, where they failed. It is designed to be sampled, filtered and transformed on the way to a backend, and a trace that is not sampled is not exported; the Collector's filter processor drops matching telemetry by configuration. Its identity is one execution, carried in the W3C traceparent header. An audit trail answers a different question about a different unit: what happened to one business transaction, who acted and on what evidence, completely and without later edits.

  • Never sample, filter or route audit entries through a telemetry pipeline.
  • Correlate the two: record the audit trace_id on spans as an attribute. Do not reuse a distributed trace identifier as the audit identity.
  • Classify what you correlate with. A span attribute leaves the audit store for exporters, vendors and a retention of its own: an opaque reference, never personal data or a secret.
  • Expect one business transaction to span several distributed traces: the intake request, an asynchronous job, a decision made days later.

OPA is a policy engine, not a regulatory authority

Open Policy Agent evaluates rules somebody wrote against input somebody supplied. It decouples the decision from its enforcement, which is what makes rules manageable as data. It does not know what a regulation requires, and a rule written in Rego is exactly as correct as the reading of the text it encodes. The engine's answer is evidence that a rule was applied, never evidence that the rule was right.

  • Every rule needs an owner, a source and a review, like any other interpretation of a text.
  • Record the revision with every decision, so a later correction of the rule can be told apart from the decisions taken under the old one.
  • A passing test suite for a policy proves that the rule behaves as its author intended, and nothing about whether the author read the text correctly.

Kubernetes admission policies do not replace application-level validation

Admission control intercepts requests to the Kubernetes API server after authentication and authorisation, before the object is persisted. It sees Deployments, Pods and ConfigMaps, and requests to read them bypass it entirely. It never sees the HTTP requests a service handles, the messages it consumes or the replies a model returns. It judges requests as they arrive, which Kubernetes spells out for one admission plugin: when a LimitRange is added, the pods that already exist continue unchanged.

  • Use admission for properties of workloads: images pinned by digest, revisions named, credentials absent where they must be absent.
  • Keep boundary validation in the application, on every entry point it has.
  • Audit existing objects separately, as Gatekeeper's audit does; admission only ever sees changes.

Event sourcing is not required for append-only evidence

Event sourcing makes an append-only log of events the system of record and derives state from it. That yields a complete history by construction, at a considerable price: every read model is a projection, and every change to an event's shape is a migration of history. An append-only audit trail beside ordinary state gives what COADF P-4 asks for (a history that is appended and never rewritten, reconstructable in one query) without changing how the rest of the system keeps its state. Per-operation privileges and refusal triggers are enough to build one in PostgreSQL.

  • Choose event sourcing for the domain's own reasons, not in order to obtain an audit trail.
  • An append-only table with an insert-only role, refusal triggers and idempotent writes realises append-only evidence without event sourcing, within the database's own trust boundary.
  • Either way, the entry is written in the same transaction as the change it records.

Microservices are not required for probabilistic isolation

The probabilistic boundary is a property of code paths: no path lets model output become an authoritative object without an explicit, recorded step. A module boundary that the build enforces keeps that property inside one process, with import contracts in Python or architecture rules as unit tests in Java. A network boundary adds infrastructure enforcement, and with it contract versioning, partial failure, retries and context propagation across hops, which are new places for the property to be lost.

  • Deploy the probabilistic component separately when scaling, isolating a vendor library or releasing independently calls for it, not because a principle does.
  • Enforce the module boundary with an architecture test in either case.
  • When the boundary is a network, validate again on the receiving side.

Static typing does not replace runtime validation at external boundaries

A type system checks the code against itself. At an external boundary the data comes from outside the code: a model, a client, a queue. TypeScript's type annotations are erased before the program runs and JSON.parse is typed as returning any; the Python runtime does not enforce type annotations; and a Java type describes what a deserialiser was asked to produce, not what the sender sent. The type is a promise the boundary has to keep, at run time, with a schema.

  • Derive the static type from the runtime schema wherever the language allows it.
  • Validate on every receiving side, not only at the web entry point.
  • Keep casts out of boundary code: a cast is where the type system stops checking.

A green CI pipeline does not prove a control is architecturally sufficient

A green pipeline proves that the checks it ran passed. It says nothing about checks that were skipped and reported as successful, selections that matched no test, fences placed on the wrong path, or properties nobody wrote a check for. COADF's conformance model states the same rule from the other side: a control is reported as enforced only when its evidence ran in the identified run and passed.

  • Record which checks ran, and how many assertions executed, for every run.
  • Prove each fence's teeth on its real path, and prove it again when the path changes.
  • Review what is not checked as seriously as what is.

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