Decision records, ten of ten. One architecture decision per piece, from a governed AI-agent platform I designed and built as a prototype for Dutch local government.
The situation
This one I found while building, not by review, which is the point of including it.
Every identity source in the platform resolved a principal, and every one of them hard-coded the principal type to “user”. A caller that came in through a service credential, with no human behind it, was resolved, authenticated and recorded as a human. The record was not wrong about who held the credential. It was wrong about what kind of thing that was.
The consequence was not abstract. A component that needed to resolve data across tenants had no human who could lawfully be the principal for that call, so there was no “user” to resolve. Rather than fix the identity model, the earlier version of the design had pushed that component into a different host where identity worked differently. In that host, its sessions skipped receipts, skipped budget checks, and skipped the approval gate. The debt was recorded in a code comment. Not in the architecture, not in the risk register, in a comment.
That is what an identity gap does. It does not announce itself as a security problem. It presents as a component that needs to live somewhere else, and the somewhere else has fewer controls.
Kafka’s Josef K. never learned who accused him. Our logs had the opposite problem: they knew exactly who did everything, and it was always “user”.
The decision
A workload may hold and act under its own non-human principal. Agents and services are principals, the same category as users, and the record treats them as such. Four conditions.
Distinguishable in the record, not merely annotated. The principal type is a field every control reads, not a tag someone can filter on later. Policy, approval, budget and evidence all see “this is a machine” as a first-class fact.
Revocable independently of any human account. Revoking the workload principal stops the workload. It does not stop, and is not stopped by, any human’s access.
Never a permanent credential. Workload principals hold short-lived, issued credentials bound to the workload’s identity. There is no long-lived key.
Refusal as the default when no principal resolves. If a caller presents and nothing resolves, human or machine, the answer is no. Not “user”, not “anonymous”, no.
What I rejected, and why
On-behalf-of only. Every machine call carries a human principal it is acting for, and the machine itself has no identity. This is the common pattern and it is right for most calls. It fails for the cross-tenant case, because some resolutions may have no lawful human path at all: there is no single person who may see both sides. Under on-behalf-of only, that component stays in the ungoverned host forever. The bypass becomes permanent, by design.
A scoped workload credential without a principal. Give the workload a credential with a narrow scope, but do not model it as an actor. That is authority without identity. It has the same cost as a full principal, you still issue, rotate and revoke it, and it gives you none of the record. The evidence ledger would show a scope and not an actor.
What it costs
A new authority surface. Machine principals can be granted things, and the set of things they can be granted is a new policy domain with its own review. And a confused-deputy risk: a workload principal with its own authority can be induced, by a caller with less authority, to act on that caller’s behalf with the workload’s rights. That has to be bounded, by making the workload’s policy evaluate the originating principal as well as its own, and the prototype bounds it for the tool-call path and not yet for the retrieval path.
A data-protection question becomes live. Once a machine actor processes citizen data under its own identity, the question of who is controller for that processing is no longer answered by “the human who clicked”. For a municipality that is a real question with a real answer required, and the prototype raises it without settling it.
What it does not do
Auditors only gain the distinction once records actually vary. Modelling machine principals in the schema does nothing until there are records with both types in them, and controls that behave differently on each. Until the first machine principal is issued and acts, the field is a promise.
The identity model was changed and the hard-coded type removed. The component that had been pushed to the other host was not yet moved back when the prototype paused. The comment is still there, now pointing at a decision record instead of at nothing.
If you take one thing
Search your identity code for the place that sets the principal type. If it is a constant, you have a caller somewhere that no human authenticated and your records say otherwise. Find that caller before you find the comment.
Our identity layer said “user” to everything that knocked. Computer says yes, it turns out, is the far worse sketch.
References
The allusions and quotations in this piece, with their origin:
- Franz Kafka, The Trial (1925): Josef K., arrested without ever learning the charge.
- Little Britain (BBC, 2003-2006): “Computer says no”, Carol Beer at the desk.
- #Decision records
- #AI governance
- #Architecture

Rutger Hemrika
AI strategy and governance for vertical-market software. Writes from building, not from slides; every claim carries an evidence grade.