Skip to main content

Audit trail

Every quote, policy check, approval and order appends a plain-language entry. Chain: hash = SHA-256(prevHash + RFC8785(entry)).

gateway.db · audithash = sha256(prevHash ‖ canonical_json(entry − hash))aud_0412quoteagent:hotel-auroraThe agent asked for 20 productsfor Tue 17 Nov. The gatewayreturned 20 signed offers.prevHash00000000…hash (stored)5eb42780…recomputed5eb42780… ✓aud_0413policy_checkagent:hotel-auroraDry run: 20 lines auto; €161.84is under the €500 limit.prevHash5eb42780…hash (stored)ac8ad643…recomputedf6c4f2f5… ✗aud_0414approvalapprover:head-chefHead chef approved the orderand 3 lines.prevHashac8ad643…hash (stored)759b97ce…recomputed759b97ce… ✓after a broken linkaud_0415order_placedgatewayOrder ord_5531 placed: 20 lines,€561.84 net, deliveryTue 17 Nov.prevHash759b97ce…hash (stored)4bac73ba…recomputed4bac73ba… ✓after a broken linkGET /v1/audit → chain: { valid: false } first bad entry: aud_0413
8/8Verify again. The edited entry's recomputed hash (f6c4f2f5) no longer matches, so the chain breaks there and everything after it is suspect: chain.valid: false.
  • Kitchen reads its own entries via slip; Valio operator sees the full chain in demo mode
  • Confirmations carry auditEntryId; carts share traceId with OpenTelemetry
  • Oversized cancel text → invalid_reason (no log stuffing)