Article the fifth
Explainable by construction
Some months after a loan was refused, the applicant asks why. A regulator asks the same thing about a thousand loans at once. The bank has a model, a log, a ticket and a team who remember something. What it needs is a way to say, for this loan, what the system knew, what it was allowed to do, who chose, and under which rules, and to say it in a way someone else can check.
Two kinds of explanation
There are, roughly, two ways to explain an automated decision.
The first is post hoc. After the decision, a second process estimates which inputs mattered, or asks the model to say why. Tools like feature-attribution methods and "explain your answer" prompts are of this kind. They can be useful, and they have a well-known weakness: they are a model of the model. A fluent paragraph of reasons may have nothing to do with how the answer was actually produced, and it was written after the fact by something that wanted to sound reasonable.
The second is by construction. The system is built so that, at every consequential step, what happened is a matter of record: the state it was in, the choices open to it, who or what took one, and the rules in force. An explanation then is not generated. It is read back.
Vertep is built for the second kind. It does not replace the first: if you want attribution scores for a credit model, you still need them. But it gives you something they cannot, which is a faithful account of the process around the model.
Five questions a record must answer
- What state was the process in? Not "what did the transcript say", but which state of which chart, with which data.
- What was it allowed to do? Which moves were enabled at that moment, and which were not.
- Who or what chose, and what did they say? A model, a rule or a person, and their stated reason.
- Under which version of the rules? Exactly which chart, identified in a way that cannot be quietly changed.
- What happened next? The transition taken, and every effect it caused.
In Vertep each one is a property of how the system runs, not a feature added to it. A chart's version is the hash of its canonical form, so it names the rules and cannot be edited without being a different version. At a decide state the core computes the enabled events and offers only those. The answer comes back as an event, is written to the journal and is then applied. And the journal is read before anything is done, so the order of the record is the order of causes.
Reading a record
The credit-decision example decides three loan applications, then opens the journal with no model bound. This is the second application, a loan of 80 000 at a debt-to-income ratio of 38%, above the 50 000 ceiling in the chart:
https://example.org/loans/1002 amount 80000, ratio 38%
underwriter asked in `underwriting`: offered ["decline", "refer"] -> approve
officer asked in `officer_review`: offered ["approve", "decline"] -> approve
https://example.org/loans/1002 final ["approved"]
1 start
2 event apply
3 decision approve, rationale "strong credit history"
4 decision approve, rationale "verified employment by phone; collateral accepted"
as of entry 2: ["underwriting"]
as of entry 3: ["officer_review"]
as of entry 4: ["approved"]
https://example.org/loans/1003 final ["declined"]
1 start
2 event apply
Read it as an auditor would. The process was in underwriting after entry 2. The underwriter was offered decline and refer: the chart never offered approve, because the amount exceeds the ceiling. The underwriter answered approve anyway, with a rationale. That answer was refused, because it was not on the offer, and the chart sent the case to an officer, who approved it with their own recorded reason.
Three things in this record would be hard to get from a log. First, the refused answer is there: the model's attempt to approve is part of the history and not erased by the rule that stopped it. Second, approve in entry 3 did not approve anything. The state as of entry 3 is officer_review, and the record says so. Third, the third application, at 62%, has no decision at all, because the chart declined it by rule and never asked anyone. An empty space where a decision would be is itself an answer.
Replay is the audit
The auditor in the example opens the same journal in a second host with no decider bound, and the process replays: nine entries, zero decider calls, the same states. This matters in a way that is easy to miss. The thing being examined, the model, is not needed to examine its decision. The record is complete enough to stand without it, so it can be checked years later after the model has been retired, retrained or switched off.
Replay also gives time travel: state_at shows the process as of any entry. And because a chart is versioned by its hash, one can ask a question that logs cannot answer: what would this applicant's journey have been under next quarter's policy? Fork from the journal at the application, run it under a new chart version and compare. The original record is untouched. For a regulated lender changing a threshold, that is the difference between hoping the change is safe and having run it on last year's cases.
The model's reason is a claim
A rationale a language model writes is stored in the journal as the decider's annotation, next to its decision. That is deliberate. The record says "the underwriter said this was because of stable income", and not "this was because of stable income". The first is a fact about what was recorded. The second would be a claim about the model that Vertep cannot verify and does not make.
This is a useful discipline for the people reading the record too. What can be checked, whether a move was legal, whether a person decided, which rules applied, is kept apart from what can only be reported. An examiner can trust the first without trusting the second, and can ask for the second to be sampled and reviewed.
What this does not give you
- It does not explain the model. If a regulator asks why a model scored an applicant at 0.72, the journal records the score and the move that followed, not what is in the weights.
- It cannot make a bad policy good. A chart can encode an unfair threshold exactly and then record every use of it faithfully. What it adds is that the threshold is explicit, versioned, testable and replayable on past cases, which is where a fairness review can begin.
- A plain journal is not tamper-evident today. Durable objects in Vertep have hash-chained, signed journals. Extending that to every agent journal, with an exportable explanation bundle a third party can verify, is specified as a draft,
m12-decision-records, and is not built. - Personal data and an append-only record pull against each other. Under rules like the GDPR's right to erasure, you cannot simply rewrite history. Until the specified per-subject encryption lands, the safe practice is to keep personal data out of events and journal references to it.
- It is 0.1.x software. The example above is a scripted decider on an in-memory journal. It shows the shape of the record, not a production deployment.
Why bother
Most explainability effort goes into making the model's answer more understandable. That matters. But a decision is also a process with a time, an authority and a rule, and in a regulated setting those are what someone is held to. A system that records the process as it runs turns "we think it was because" into "here is the entry". The model remains a model, as opaque as it was. It simply no longer has to be the only witness.