Skip to content

Urd Ledger

Frank Yglesias Bertheau edited this page Jul 7, 2026 · 1 revision
<h1>ᚾ&nbsp;NornGate — Urd Ledger</h1>

Urd is the system's memory of what was: every gate decision and every committed outcome is written here, once, in order. Named for Urðr, the Norn who keeps the past, the ledger is the audit record, the replay source, and the billing basis — the same three jobs, one log.


ᛈ Overview

Urd is a centralized, append-only, tamper-evident ledger — a single authoritative, operator-run log. It is deliberately not distributed-consensus or on-chain: centralization buys low write latency and simple operations, and the integrity properties are supplied cryptographically rather than by a quorum.

Two kinds of record land here:

  • Decision records — one per gate verdict (allow / deny / timeout), for every gate a request touches.
  • Outcome records — written at G4 commit; these carry billable: true and anchor per-outcome billing.

ᚨ The record

Every record is small, structured, and free of raw personal data in the chained portion. Anything human-readable that could contain PII (a denial reason, a payload) is stored by reference, not inline.

{
  "id": "audit_7f3a2b",
  "kind": "decision",
  "gate": "policy",
  "decision": "deny",
  "reason_ref": "payload:9f2c",
  "requestId": "req_abc123",
  "trace": "9f3c2a",
  "snapshot": { "policy": "pol_20260706_01", "state": "st_88f2", "config": "gatecfg_v14" },
  "prev_hash": "sha256:6a1e",
  "sig": "ed25519:3b9f",
  "timestamp": "2026-07-06T10:32:00Z"
}

The snapshot IDs are what make a record replayable — load the same pinned inputs, re-run the gate, get the same verdict (Deterministic Execution). The reason_ref points into the erasable payload store (see GDPR).


ᛉ Integrity

Two mechanisms make the log tamper-evident:

  • Hash chain — each record carries prev_hash = sha256(previous_record). Any insert, delete, or edit breaks the chain from that point forward.
  • Ed25519 signatures — each record (and each checkpoint) is signed. The signing key lives in an HSM in Asgard, in a trust domain distinct from workers, so a compromised Midgard or Jotunheim node can produce records but cannot sign them.

Tamper-evident is not tamper-proof. A centralized ledger is only as trustworthy as its signing key — that is exactly why the key is off the worker path and in hardware. If you later need non-repudiation against NornGate-the-operator, publishing the signed chain-head to an external anchor is an additive step, not a redesign.

Verification walks the chain from a signed checkpoint, not from genesis:

verify(record R, pubkey K, checkpoint C):
  assert ed25519_verify(K, R.sig, canonical(R without sig))
  assert R.prev_hash == sha256(canonical(R.previous))
  ... walk back to C ...
  assert ed25519_verify(K, C.sig, canonical(C))   # trusted chain-head

Periodic signed checkpoints (the current chain-head hash) double as the recovery seed for the Ragnarök drill — recovery restores to a checkpoint and validates the chain forward before resuming.


ᚷ Verifiable receipts

Each G4-verified outcome emits a signed receipt the tenant can verify independently against Urd's public key — without trusting NornGate's word, and without NornGate trusting theirs.

{
  "id": "audit_9a2f",
  "kind": "outcome",
  "gate": "arbitration",
  "decision": "commit",
  "requestId": "req_abc123",
  "resource": "user-record:4471",
  "idempotencyKey": "idem_abc123",
  "billable": true,
  "prev_hash": "sha256:7c4d",
  "sig": "ed25519:a12e",
  "timestamp": "2026-07-06T10:32:02Z"
}

Why it matters: the invoice basis is the set of billable outcome records for a tenant over a period. Because each is signed and chained, the customer can reconcile the bill against receipts they verified themselves — per-outcome billing becomes auditable by both sides, which is the point of charging per verified outcome rather than per token. Integrity bar: Kaman's signed, hash-chained action records.


ᛚ Storage and retention

  • Hot — an append-only Kafka log, partitioned per realm, for recent records.
  • Cold — durable backup in S3 / Niflheim, long retention, immutable after write.
  • Tiered — records age from hot to cold; checkpoints bridge the two.

Write access is Asgard-only; the signing HSM is the sole issuer of valid signatures. This is one authoritative ledger, not a replicated quorum — the trust model is cryptographic, and the storage is ordinary durable infrastructure.


ᚲ Query

Urd is queryable over GET /v1/audit, filtered by gate, decision, request, tenant, and time window.

GET /v1/audit?gate=policy&decision=deny&from=2026-07-06T00:00:00Z&to=2026-07-06T23:59:59Z

The response is an array of records (payloads returned by reference, resolved through the payload store only for authorized readers). Reading the audit log is itself an audited action — there is no unobserved read of the record of record.


ᚺ GDPR — immutable chain, erasable payload

An append-only ledger and the right to erasure (GDPR Art. 17) only conflict if the same store holds both proof and personal data. Urd splits them:

  • Chain store — hashes, gate, decision, timestamps, snapshot IDs. No personal data. Immutable.
  • Payload store — PII-bearing fields (the reason, request bodies), encrypted per data-subject with a data-encryption key (DEK) wrapped by a KMS key.

The chain commits to the ciphertext (its hash), never the plaintext — so erasing the plaintext does not break verification, and the hash is not a plaintext oracle.

erase(subject S):
  delete DEK(S) in KMS          # crypto-shred: S's payloads are now unrecoverable
  # chain untouched: it commits to ciphertext, not plaintext
  # records still verify; reason_ref resolves to a tombstone

So Urd is immutable as a proof structure and erasable as a data store — the two claims describe different layers, not a contradiction. See Security & Fail-closed.


ᚱ Next steps


Iconography

Section glyphs are Elder Futhark runes (Unicode Runic block, U+16A0–U+16FF) — semantic, not emoji. Full set on Home:

Rune Name Gloss Marks
Nauðiz need, constraint the platform mark
Perthro the well of Urd, the record of fate overview
Ansuz the word, the written record the record
Algiz protection, warding integrity
Gebo the proof of exchange verifiable receipts
Laguz water, the deep, cold storage storage & retention
Kenaz the torch, looking into the record query
Hagalaz hail, controlled destruction GDPR erasure
Raidō the ride, the road next steps

References. Ed25519 / RFC 8032 (signatures); Certificate Transparency / RFC 6962 (signed append-only log with Merkle checkpoints — the design lineage); GDPR Art. 17 (right to erasure) via crypto-shredding; Kafka (append log); KMS envelope encryption. Signed, hash-chained records — Kaman. Naming doctrine: Prose Edda / Poetic Edda, per Norse Cosmology & Platform Design.

ᚾ NornGate — Urd Ledger

Urd is the system's memory of what was: every gate decision and every committed outcome is written here, once, in order. Named for Urðr, the Norn who keeps the past, the ledger is the audit record, the replay source, and the billing basis — the same three jobs, one log.


ᛈ Overview

Urd is a centralized, append-only, tamper-evident ledger — a single authoritative, operator-run log. It is deliberately not distributed-consensus or on-chain: centralization buys low write latency and simple operations, and the integrity properties are supplied cryptographically rather than by a quorum.

Two kinds of record land here:

  • Decision records — one per gate verdict (allow / deny / timeout), for every gate a request touches.
  • Outcome records — written at G4 commit; these carry billable: true and anchor per-outcome billing.

ᚨ The record

Every record is small, structured, and free of raw personal data in the chained portion. Anything human-readable that could contain PII (a denial reason, a payload) is stored by reference, not inline.

{
  "id": "audit_7f3a2b",
  "kind": "decision",
  "gate": "policy",
  "decision": "deny",
  "reason_ref": "payload:9f2c",
  "requestId": "req_abc123",
  "trace": "9f3c2a",
  "snapshot": { "policy": "pol_20260706_01", "state": "st_88f2", "config": "gatecfg_v14" },
  "prev_hash": "sha256:6a1e",
  "sig": "ed25519:3b9f",
  "timestamp": "2026-07-06T10:32:00Z"
}

The snapshot IDs are what make a record replayable — load the same pinned inputs, re-run the gate, get the same verdict ([Deterministic Execution](Deterministic-Execution)). The reason_ref points into the erasable payload store (see GDPR).


ᛉ Integrity

Two mechanisms make the log tamper-evident:

  • Hash chain — each record carries prev_hash = sha256(previous_record). Any insert, delete, or edit breaks the chain from that point forward.
  • Ed25519 signatures — each record (and each checkpoint) is signed. The signing key lives in an HSM in Asgard, in a trust domain distinct from workers, so a compromised Midgard or Jotunheim node can produce records but cannot sign them.

Tamper-evident is not tamper-proof. A centralized ledger is only as trustworthy as its signing key — that is exactly why the key is off the worker path and in hardware. If you later need non-repudiation against NornGate-the-operator, publishing the signed chain-head to an external anchor is an additive step, not a redesign.

Verification walks the chain from a signed checkpoint, not from genesis:

verify(record R, pubkey K, checkpoint C):
  assert ed25519_verify(K, R.sig, canonical(R without sig))
  assert R.prev_hash == sha256(canonical(R.previous))
  ... walk back to C ...
  assert ed25519_verify(K, C.sig, canonical(C))   # trusted chain-head

Periodic signed checkpoints (the current chain-head hash) double as the recovery seed for the Ragnarök drill — recovery restores to a checkpoint and validates the chain forward before resuming.


ᚷ Verifiable receipts

Each G4-verified outcome emits a signed receipt the tenant can verify independently against Urd's public key — without trusting NornGate's word, and without NornGate trusting theirs.

{
  "id": "audit_9a2f",
  "kind": "outcome",
  "gate": "arbitration",
  "decision": "commit",
  "requestId": "req_abc123",
  "resource": "user-record:4471",
  "idempotencyKey": "idem_abc123",
  "billable": true,
  "prev_hash": "sha256:7c4d",
  "sig": "ed25519:a12e",
  "timestamp": "2026-07-06T10:32:02Z"
}

Why it matters: the invoice basis is the set of billable outcome records for a tenant over a period. Because each is signed and chained, the customer can reconcile the bill against receipts they verified themselves — per-outcome billing becomes auditable by both sides, which is the point of charging per verified outcome rather than per token. Integrity bar: Kaman's signed, hash-chained action records.


ᛚ Storage and retention

  • Hot — an append-only Kafka log, partitioned per realm, for recent records.
  • Cold — durable backup in S3 / Niflheim, long retention, immutable after write.
  • Tiered — records age from hot to cold; checkpoints bridge the two.

Write access is Asgard-only; the signing HSM is the sole issuer of valid signatures. This is one authoritative ledger, not a replicated quorum — the trust model is cryptographic, and the storage is ordinary durable infrastructure.


ᚲ Query

Urd is queryable over GET /v1/audit, filtered by gate, decision, request, tenant, and time window.

GET /v1/audit?gate=policy&decision=deny&from=2026-07-06T00:00:00Z&to=2026-07-06T23:59:59Z

The response is an array of records (payloads returned by reference, resolved through the payload store only for authorized readers). Reading the audit log is itself an audited action — there is no unobserved read of the record of record.


ᚺ GDPR — immutable chain, erasable payload

An append-only ledger and the right to erasure (GDPR Art. 17) only conflict if the same store holds both proof and personal data. Urd splits them:

  • Chain store — hashes, gate, decision, timestamps, snapshot IDs. No personal data. Immutable.
  • Payload store — PII-bearing fields (the reason, request bodies), encrypted per data-subject with a data-encryption key (DEK) wrapped by a KMS key.

The chain commits to the ciphertext (its hash), never the plaintext — so erasing the plaintext does not break verification, and the hash is not a plaintext oracle.

erase(subject S):
  delete DEK(S) in KMS          # crypto-shred: S's payloads are now unrecoverable
  # chain untouched: it commits to ciphertext, not plaintext
  # records still verify; reason_ref resolves to a tombstone

So Urd is immutable as a proof structure and erasable as a data store — the two claims describe different layers, not a contradiction. See [Security & Fail-closed](Security-and-Fail-Closed).


ᚱ Next steps


Iconography

Section glyphs are Elder Futhark runes (Unicode Runic block, U+16A0–U+16FF) — semantic, not emoji. Full set on [Home](Home#iconography):

Rune Name Gloss Marks
Nauðiz need, constraint the platform mark
Perthro the well of Urd, the record of fate overview
Ansuz the word, the written record the record
Algiz protection, warding integrity
Gebo the proof of exchange verifiable receipts
Laguz water, the deep, cold storage storage & retention
Kenaz the torch, looking into the record query
Hagalaz hail, controlled destruction GDPR erasure
Raidō the ride, the road next steps

References. [Ed25519 / RFC 8032](https://www.rfc-editor.org/rfc/rfc8032) (signatures); [Certificate Transparency / RFC 6962](https://www.rfc-editor.org/rfc/rfc6962) (signed append-only log with Merkle checkpoints — the design lineage); [GDPR Art. 17](https://gdpr-info.eu/art-17-gdpr/) (right to erasure) via crypto-shredding; Kafka (append log); KMS envelope encryption. Signed, hash-chained records — Kaman. Naming doctrine: Prose Edda / Poetic Edda, per [Norse Cosmology & Platform Design](Norse-Cosmology-and-Platform-Design).

Clone this wiki locally