Current build status — 10 August 2026
Counter-signing is not running in the current build. Receipts are committed, not counter-signed. Everything on this page below this notice describes completed runs — thirteen of them across 2026, totalling 5,794 receipts — which were counter-signed at the time and remain independently verifiable against the attester’s published key today. That is a property those runs have. It is not a claim about what happens if you send a write right now.
The headline above is written in the present tense and should be read as describing the corpus, not the live path. Rather than rewrite a page whose dated sections are the record, the status is stated here and the sections are left as published.
A production-signer verification run (synthetic inputs, real independent signer). Every governed decision produces a real cryptographic receipt issued via TBN Protocol — verifiable by anyone, server-side and offline, without trusting our servers. The v2 receipt attests the authorisation context, not just the decision: who authorised it, under which rules, and the policy state in force. Narrowed 11 Aug 2026 — what a receipt cannot establish ↓
tbn2_ v2 receipts · schema tbn-receipt/2.0 · key id tbnkey_d9d2b0c3ab2e8aa3 · fail-closed ON · verified 500/500 · reconciled with TBN byte-for-byte. See the run ↓A full production run across the ten use cases exercising the three-verdict path end-to-end. High-stakes actions are routed to human review (escalate) rather than bound — each decision sealed as a receipt independently signed by TBN.
tbn2_ v2 receipts · schema tbn-receipt/2.0
· key id tbnkey_d9d2b0c3ab2e8aa3 · fail-closed ON. Each escalate carries PENDING on
the constitutional-reasoning control; the authorisation envelope's resolution reflects it, so the receipt is
internally consistent.Merkle root (three-verdict run, 2026-07-14):
4382b9754dba673c0c5e0da2c70c37a0e8ebee62ea3aa3b0f576d50c96fd9c0a
Honest boundaries: enforcement holds for writes routed through the connector; writes outside it are not attested. HOLD is a designed, recoverable state and did not trigger here (the attester was healthy — 0 held is expected, not a gap). RFC 3161 trusted timestamps were not enabled — timestamps are TBN-self-asserted. No independent third-party red-team yet.
Every production run we've published, oldest to newest — synthetic inputs, a real independent signer, each root reconciled with TBN. The 1,000-decision run is the flagship: the largest, and still verifiable live against TBN's endpoint today.
/api/v1/verify (v1 tbn_vr_ IDs) — try a live verify ↗.56a848c8…, reconciled byte-for-byte with TBN.
receipt_id, attestation_id, agent_id, decision, decision_hash, timestamp, frameworks, version), node = SHA-256(left ‖ right) with no domain separation, duplicate-last on odd, in as-issued order. Preparing an independent audit we tried to recompute this root with the later runs’ construction, it did not match, and for a short time we did not know why. The attester re-ran it against live production data on 21 July and it reproduces byte-for-byte; recomputed independently on our side against the same published receipts, it also reproduces. The root was always correct — what was missing was a label saying which construction produced it. That label now ships in the signed receipt body for new runs (see the construction note below).580ad28a… · how it's constructed ↓.4382b975…, reconciled byte-for-byte.production_runs/20260718_gap_closure_final/ — three runs share 2026-07-18 and a 200-receipt count, so the date does not identify one. The directory does, and the root below resolves to it.9b462c03…, reconciled byte-for-byte with TBN and covered
by a TBN-signed, RFC-3161-anchored attestation (tbn2_1a37983c…, via freetsa.org).input_hash seals capability_id +
aggregate state). A real independent connector on a system of record is the next step.This heading is narrower than it reads, and was narrowed on 11 August 2026. What is sealed is the authorisation context the system held — an evidence-integrity property. It is not evidence sufficiency. Read this before the section ↓
Most "AI governance" can show you what an agent did. The harder question — the one auditors and the new agentic-AI governance frameworks ask first — is whether it was authorised, under which rules, and whether you can prove the authorisation itself, not just the action.
Every governed decision now seals — into the independently signed receipt — the full
authorisation context as it stood the moment the write bound: the constraints that evaluated and
their results, the policy state in force, the authorisation chain (who authorised, under which scope, bounded by a
human), and how any conflict resolved. It's committed via input_hash = SHA-256(canonical(envelope)),
so a reviewer can reconstruct "what was allowed, under whose authority, against which rules" — and check it without
trusting us. The published envelopes carry a real authoriser and a non-empty policy snapshot (not placeholders).
Narrowing — added 11 August 2026. Two sentences above claim more than the mechanism delivers.
They are left as published, and narrowed here. The distinction they fail is between two different questions, which this page had been treating as one.
Evidence integrity — can you prove this evidence belongs to this decision, was created with it, and has not since been altered? Evidence sufficiency — even if the record is completely authentic, does it give an examiner enough to determine whether the underlying decision was properly made? An authentic record can still document a decision made from incorrect information, under the wrong rule, without proper authority, or without a required exception or review.
“— and check it without trusting us.” True of the first question and
not the second. You can confirm, without trusting us, that the envelope hashes to the attested input_hash and that an independent
party signed it. You cannot confirm from the receipt that the decision was properly made — that still rests on our account of the inputs, the
rule and the authority. Confirming the signature confirms that the system is telling the truth about its own beliefs.
“the policy state in force.” What is sealed is the policy state the system held. That it was the state which governed is a different claim, and not one a receipt can carry. A receipt can perfectly establish that Rule X was applied; if an examiner cannot establish that Rule X was the applicable and authorised rule at that point in time, integrity does not resolve sufficiency.
This is not fixed, and no mechanism for it exists here. The applicable rule, the valid issuance of an authority, its currency at the moment of reliance, and a verified referent for the actor’s identity are each terms the calling chain cannot produce. Establishing them needs a source outside both the vendor and the operator. All four are carried open in our disagreement register — items 13, 21, 29 and 33 — and were recorded on 11 August 2026 as one category rather than four.
The distinction was drawn by an external reviewer — a banking and operations professional whose experience spans fraud prevention and investigation, BSA/AML, compliance and operational risk — in a first exchange, and is recorded in the register with their consent. They have inspected no implementation and this is not an endorsement of one. It is the third claim on this page narrowed this week and the first found by a counterparty rather than by us.
Independently attested. Each receipt was signed by TBN Protocol (the
independent authority). Every one verifies two ways: the RSA-PSS signature is valid against TBN's
published key, and the published authorisation envelope hashes to the attested input_hash
with matching controls[]. The authorisation chain
(authorized_by = team@shango.in, real permission_scope,
bounded_by_authorising_human = true) and the policy snapshot
(policy_snapshot_hash ≠ SHA-256("{}")) are populated for every receipt — not placeholder text.
Merkle root (v2 run, 2026-06-25):
580ad28ab3643faf5de73ba98e36df138d28138a41091bf9ac85eafc95dd5bfb
Construction (domain-separated dup-last Merkle (not RFC 6962)): leaf =
SHA-256(0x00 ‖ canonical signed body) (every field except signature,
sorted-keys / no-whitespace); internal node = SHA-256(0x01 ‖ left ‖ right); duplicate-last on odd
levels; hex of the final node. Receipts use schema tbn-receipt/2.0, key id
tbnkey_d9d2b0c3ab2e8aa3, verifiable offline against TBN's published key. Reproduce with
python proofs/mint_v2_direct.py --n 500 --out <dir> --fail-closed or verify the published
artefacts at production_runs/20260625_185419_v2/.
Correction, 21 July 2026 — this construction is not RFC 6962 and we should not have called it that. RFC 6962 splits at the largest power of two below n and promotes the lone node; this tree duplicates it. Duplicate-last admits the CVE-2012-2459 cross-n collision — root([a,b,c]) == root([a,b,c,c]) — so the raw root alone does not uniquely commit to the receipt list. We now also publish merkle_root_bound = SHA-256(0x02 ‖ n as uint64 big-endian ‖ raw root as 32 raw bytes), which closes it completely rather than merely making it hard to reach: for a fixed n the construction is injective, and the collision is inherently cross-n. Every raw root already published is unchanged and remains valid; nothing has been re-anchored. Found while preparing an independent audit and reproduced by the attester against their own implementation before either party compared numbers.
The published runs span three constructions, and we had not documented which was which. Both parties confirmed this independently: the 2026-06-20 run uses an 8-field-subset leaf with no domain separation; an early 500-receipt run uses a full-body leaf with no domain separation; the authorisation-context runs from 2026-06-25 onward use the domain-separated construction described here. All three reproduce from their published receipts. Going forward the construction identifier is carried in the signed receipt body so a verifier is never left to guess, new receipt chains use true RFC 6962, and the open-source verifier reads whichever construction a run declares.
Trust boundary, plainly: TBN attests what Shango
asserts — the receipt is an independent authority's signature over the decision and its sealed context, not
proof that an external write actually happened or was blocked. Enforcement holds for writes routed through the
connector; writes outside it are not attested. fail-closed was ON for this run: an ALLOW with no
TBN receipt is downgraded to BLOCK. RFC 3161 trusted timestamps are an opt-in flag
(TBN_RFC3161=1) and were not enabled for this run — timestamps are TBN-self-asserted.
These are real v2 receipts from the latest run. We don't ask you to trust us — we ask you to check.
Live endpoint gap, honestly: TBN's public /api/v1/verify currently accepts only v1 IDs (tbn_vr_…) and returns HTTP 400 "Invalid receipt_id format" for v2 IDs (tbn2_…). v2 verification is therefore offline-only against TBN's published RSA-PSS key (see "How verification works" below). v1 receipts remain live-verifiable; sample links at the bottom of this section.
Offline (v2 — the run featured on this page): 12 sample receipt IDs from the 2026-06-25 run. Run the reference verifier:
python proofs/verify_v2.py production_runs/20260625_185419_v2/receipts_v2.jsonl --key zenodo_deposit/tbn_public_key.pem
Offline (v2 — the 2026-07-14 three-verdict run): recompute the root and verify every signature:
python proofs/verify_v2.py production_runs/20260714_v3_clean/receipts_v2.jsonl --key zenodo_deposit/tbn_public_key.pem
Live (v1 — earlier run, still server-side verifiable):
production_runs/20260625_185419_v2/receipt_ids.txt; v1 list at zenodo_deposit/receipt_ids.txt.Server-side — any receipt ID checks against TBN Protocol's public endpoint:
GET https://tbn.hardinai.co.uk/api/v1/verify/tbn_vr_0011754392069005d53bef2e9c50963a
→ { "valid": true, "receipt": { ... } }
Swap the ID for any receipt above — each returns its own signed record. ({receipt_id} is just a placeholder for a real ID.)
Offline (v2 receipts) — verify the RSA-PSS signature yourself, without contacting anyone:
signature, JSON with sort_keys=true and no whitespace (separators=(",",":")).GET /api/signing/public-key. Derive key_id = "tbnkey_" + SHA-256(pem)[:16] and confirm it matches the receipt's key_id.RSA-PSS / SHA-256 / MGF1 / salt = max over the canonical bytes. Signature is hex-encoded.SHA-256(canonical(authorisation_envelope)) and confirm it equals the receipt's input_hash; confirm controls[] matches the envelope's constraints.leaf = SHA-256(0x00 ‖ canonical signed body); node = SHA-256(0x01 ‖ left ‖ right); duplicate-last on odd levels.Reference prover at proofs/mint_v2_direct.py; verifier at proofs/verify_v2.py and proofs/verify_auth_context.py. Published artefacts at production_runs/20260625_185419_v2/.
Each receipt is independently verifiable via TBN — server-side or offline, as above. What a receipt proves: an independent authority's signature over the governed decision and its sealed context, checkable by you against the published key without trusting us. It attests the decision Shango made and the context it was made in; enforcement holds for writes routed through the connector. ShangoVault is a separate append-only, hash-chained ledger; the hash-chained portion is linkage-verified, and full content-recompute is in progress (so we say linkage, not content-tamper-proof). Narrowed 11 Aug 2026 — what a receipt cannot establish ↓
We label every number. This is the whole audit trail, not a curated slice.
| Record set | Nature | Count |
|---|---|---|
| v2 three-verdict receipts (2026-07-14 run — allow/escalate/block, synthetic inputs, real signer) | independently signed (TBN) · reconciled byte-for-byte · fail-closed ON | 500 |
| v1 decision receipts (2026-06-20 run, synthetic inputs, real signer) | independently signed (TBN) · 495/500 — 5 read-timeouts reported as misses | 495 |
| v2 authorisation-context receipts (2026-06-25 run, synthetic inputs, real signer) | independently signed (TBN) · fail-closed ON · auth + policy populated | 500 |
| v1 decision receipts (2026-06-04 run, synthetic inputs, real signer) | independently signed (TBN) | 1,000 |
| ShangoVault audit entries (snapshot 2026-06-04) | append-only · hash-chained subset, linkage-verified | 225,574 |
| — of which carry hash-chain fields | linkage-verified; content-recompute in progress | 10,234 |
| — cryptographically attested (TBN test API) | test-API attested | 182,040 |
| — labelled local simulation | simulation | 43,534 |
Correction to the table above — added 9 August 2026
The June snapshot is left as published rather than edited, because a dated figure that is quietly changed stops being a dated figure. This note supersedes three of its rows. It was written after recounting the store, which happened because the attester's holdings could not be reconciled against this page.
182,040 was a subtraction, not a query. It is exactly
225,574 − 43,534. No field in the store returns it. Records actually carrying a tbn_valid flag
total 10,234 — the row above it — of which 10,030 are simulation agents. Non-simulation
records with that flag number 204, and every one is a tombstone event. The row said "test-API attested"
against a number that no attestation field supports.
43,534 does not reconcile either. Simulation records total 206,892 and non-simulation 23,377. Neither is 43,534.
The vault total is a May-2026 figure. Recounted on 9 August against the store as last written on 25 July 2026: 230,269 parseable records, plus one unparseable line. 225,574 of them were logged in May. It is an append-only local hash-chained trail, overwhelmingly a simulation corpus from a load exercise. It is not evidence of production governance and should not have been positioned as though it were.
The counter-signed corpus is separate, smaller, and the one that checks out. Thirteen dated runs totalling 5,794 receipts carry an independent signature; the four rows at the top of this table are four of the thirteen. 3,799 sit on a chain shared with the attester spanning indices 220–4184 of a declared 0–4184, reconciled from both sides on 1 August 2026 with nothing unaccounted. The remaining 1,995 use an earlier construction, are not on that chain, and are verified individually.
On latency, honestly: the governance decision is sub-millisecond, and the RSA-PSS signature itself is ~1 ms. The end-to-end time you measure is a round-trip to TBN's independent signer — and that hop is the point: a second party signs the receipt, not us, which is what makes it verifiable rather than self-asserted. Where high frequency matters, signing runs local/async. We optimise for proof you can check, not a number you take on faith.
What this page does not prove — added 30 July 2026
Every receipt here proves the decision was made against a stated, provable basis, and that an independent party signed it. None of them proves that basis was soundly established in the first place. Two people found the same gap on the same day and it is worth stating here rather than leaving on a comment thread.
Issuance is not gated on terms the chain cannot produce. The authorising principal, scope, approver and credential all arrive on the request. There is no external authority source to ask. A well-formed grant that was never issued would pass every check we run — fidelity holds, the binding holds, the record is contemporaneous, nothing has expired, and there is no signal at all. Found by Ahmad Abby (MTCP / ARCS) on 30 July 2026, measured across 32 models and 13 providers.
The same failure sits one level up. Where a control is not reached by a request it is recorded not applicable rather than failed — which in audit terms is a scope exclusion, not a soft failure: it leaves the tested population entirely. And what determines whether a control is reached is the shape of the request. Found by Brad Wolfe on 30 July 2026.
Attribution correction, 11 August 2026 — this credited one person with two findings, and one of them is ours. Brad Wolfe named the audit treatment: that not applicable is a scope exclusion rather than a soft failure — a failed control enters the exception population and gets remediated, an excluded one leaves the population entirely — and that if the system decides what is in scope, scope is chain-producible too. The sentence about the shape of the request is ours, not his. It is the mechanism we found when we checked his point against our own code, and the paragraph above compressed the two into one sentence and attributed the whole of it to him. Our internal record had the split right; the published summary lost it. Raised by Mr Wolfe on reading a draft that repeated the same compression. His name appears here at that level and no other: no title, no firm, no credential, and he is not a reviewer, adviser or examiner of this work. He has inspected no implementation of ours, and this is not an examination, endorsement or validation of one.
Three smaller consequences of the same root: the approver's credential is fingerprinted but never verified; a failed separation-of-duties check is recorded without blocking the write; and omission produces a cleaner record than a bad claim.
None of it is fixed. The direction is known and is not ours: an auditor does not ask the company for its cash balance, they ask the bank — so the issued grant set has to live with a party we cannot write to, and the check has to be a request we make rather than a computation we perform. We already have that relationship, for the receipt. We never applied it to the grant. Same pattern, wrong object.
A 15-minute demo on your own systems — then you verify the receipts yourself. No slides.