The evidence spine
Enforcement happens on chain. What happens next — the record a supervisor reads, the case a firm keeps, the anchor a regulator can check — is this. Its property is not that it is tamper-proof, but that tampering is detectable by someone who does not trust the firm.
Three layers, and what each is for
| Layer | Holds | Who can change it |
|---|---|---|
| Chain events | IntentRecorded before the pass/fail branch, ActionHeld, Executed, HoldResolved |
Nobody. This is the authority |
| PostgreSQL | The indexed record, case files, findings, disclosure requests | The firm — which is exactly why the third layer exists |
| HCS topic | An ordered, consensus-timestamped commitment per intent | Nobody. Append-only, and the firm cannot rewrite what it published |
The database is rebuildable from chain: npm run -w @amw/intent-log index
reconstructs it from events. A firm that loses its spine loses nothing but time, and a firm that
edits its spine fails verification against the topic.
The commitment
Each intent is hashed into one digest. The field list is deliberately the whole of what a case file later relies on — anything omitted could not be proven unchanged:
keccak256(abi.encode(
actionId, // uint256
mandateHash, // bytes32
amountIn, // uint256
venueClass, // uint8 — 1 primary, 2 secondary
breachFlags, // uint256 — the flag word
occurredAt // uint64 — block timestamp, seconds
))
What the topic publishes
A bare digest is an anchor nobody can interpret. Each message is a self-describing envelope, so a reader who finds the topic without finding this repository can still tell what it is, which system produced it, and exactly how to check a record they are later shown:
{
"v": 1,
"type": "amw.intent.commitment",
"network": { "chain": 296, "guard": "0.0.10308333", "registry": "0.0.10308330" },
"mandate": "0x2cb3ea1e…7a2b",
"action": "50",
"outcome": { "state": "held", "flags": "0x140", "clauses": ["3.4", "3.7"] },
"digest": {
"alg": "keccak256",
"encoding": "abi",
"fields": ["actionId", "mandateHash", "amountIn", "venueClass", "breachFlags", "occurredAt"],
"value": "0x…"
},
"occurredAt": "2026-08-31T13:18:26Z"
}
The line between published and withheld
This is a deliberate boundary, not an accident of implementation, and it is the reason a firm can run this without publishing its book:
| Published on the topic | Kept in firm custody |
|---|---|
| That an intent existed, and its order | The notional |
| Its consensus timestamp | The counterparty and the venue address |
| Which mandate governed it | The agent's calldata |
| Whether the guard held it, and which clause class | The case file and its findings |
| The digest, and how to reproduce it | Everything a competitor would want |
A reader learns that supervision happened and can prove that a record they are shown is the record that was anchored. They learn nothing about the firm's positions. The detail reaches a supervisor through a disclosure request — and the request for evidence is itself evidence, written to an audit row before the record is released.
Verifying a disclosed record
Three steps, none of which require trusting the firm or us:
- Read the message at the sequence number cited (
hcs:0.0.10309023/9) from the mirror node, and take itsdigest.value. - Re-encode the six disclosed fields in the order the envelope names, and hash them.
- Compare. Equal means the record is the one anchored at that consensus timestamp; different means it changed after publication.
npm run -w @amw/intent-log gate3 # does exactly this, and prints each step
Or without installing anything: /console/verify takes the record you were shown, reads the message straight from Hedera's mirror node, recomputes the digest in your browser and puts the two hashes beside each other. Nothing on that page asks AMW. A console that was switched off, a server that lied and a firm that stopped answering would each leave the answer unchanged — which is the property that makes it a supervisor's tool rather than a firm's.
Older messages on a topic may be a bare 0x digest, written before the envelope
existed. They are still valid anchors and still verify; the reader accepts both formats and
says which it found.
Append-only, at the grant level
case_steps takes INSERT and nothing else — no UPDATE, no
DELETE — enforced by PostgreSQL grants and a trigger rather than by application
code that could be bypassed. A worker writes its step and cannot revise it. The trail of a
halted investigation survives the halt, because a stopped case that erased itself would be
indistinguishable from one that never ran.