§ 03 · Tier specification
The timed-ledger spectrum.
One micro-ledger primitive runs at every horizon. Each of the eight named tiers is a triple of (retention, anchoring, signature) — or supply any duration directly. Changing the tuple changes the use-case, not the codebase.
Ephemeral
CPU cache
Session
RAM / DA blob
Operational
SSD
Daily
SSD
Weekly
HDD
Monthly
cold storage
Compliance
archival storage
Eternal
tape / permaweb
§ 03.01
TTL — the underlying primitive.
The eight tiers above are named presets; the wire format accepts any duration
through the ttl field.
Supply a preset name ("T5"),
a duration string ("90d",
"5m",
"2h30m"),
the sentinel "forever",
or canonical seconds as an integer.
The receipt always records the resolved canonical seconds so any verifier
can check retention without knowing which form the caller used.
{ "ttl": "T5" } // 2 592 000 s — Monthly preset
{ "ttl": "90d" } // 7 776 000 s — ninety days
{ "ttl": "5m" } // 300 s — five minutes
{ "ttl": "2h30m" } // 9 000 s — compound duration
{ "ttl": "forever" } // 0 — unbounded (equivalent to T7)
{ "ttl": 7776000 } // 90 days as canonical seconds § 03.02
Promotion. Demotion. Crypto-shred.
Three transitions are first-class. Promotion takes a short-lived ledger and durably persists it; demotion truncates retention; crypto-shred destroys per-record keys so personal data goes dark while the Merkle path remains verifiable.
// Take the head of a T2 operational ledger, re-sign every entry with Falcon-1024,
// and emit a permanent T6 anchor. Existing T2 Ed25519 signatures remain
// valid for offline replay; the durable copy uses post-quantum cryptography.
fn promote_t2_to_t6(src: LedgerHandle, dst_spec: TierSpec) -> Result[Promotion, Error] {
assert(dst_spec.sig_scheme == Falcon1024);
let head = src.head();
let checkpoint = build_checkpoint(src, head);
let dst = open_ledger(dst_spec);
dst.append_attested(checkpoint, hatp_host_key());
anchor_now(dst, AnchorPolicy::MerklePermanent);
Ok(Promotion { src_head: head, dst_head: dst.head() })
} // Destroy the per-record AES key in the vault. The header (with its hash
// chain & signature) survives; the payload becomes unrecoverable bytes.
fn shred_entry(handle: LedgerHandle, cid: bytes32) -> Result[ShredReceipt, Error] {
let entry_key = vault_key_for(cid);
vault_destroy(entry_key);
handle.mark_shredded(cid, ts_now());
Ok(ShredReceipt { cid, ts_ms: ts_now(), proof: handle.head_attestation() })
} § 03.03
Where the tiers meet the law.
T6 · DORA
ICT incident audit logs.
EU regulation 2022/2554 mandates append-only, cryptographically-signed audit logs with multi-year retention and TEE/HSM signing. T6 (one-year, Falcon-1024) is the named implementation.
T5 / T6 · EU AI Act Art. 50
AI provenance records.
From 2026-08-02, tamper-evident records for AI-generated content with multi-year retention. Per-record crypto-shred preserves erasure rights at scale.
T1 · GDPR Art. 25
Data-minimisation by default.
Session state that auto-expires is state you are not retaining. Privacy-by-design is the storage policy, not a process annotation.
T0 · GDPR Art. 17
Right to erasure, structurally.
T0 ledgers are destroyed by elapsed time. There is nothing to erase because nothing was kept.
§ 03.04
Reference implementation.
The Go reference implementation ships in
pkg/ttlspec
(parser + preset table) and
pkg/retention
(expiry index). Feature-gated under
EPH_TTL_V2=1;
the v1 code path is byte-identical when the flag is absent.
// Parse accepts a preset name, duration string, "forever", or raw ms integer.
// Returns the canonical TTLSpec with resolved TTLMs.
spec, err := ttlspec.Parse("T5")
// → TTLSpec{ TTLMs: 2_592_000_000, Preset: &Preset{Name:"t5"}, SourceStr:"T5" }
spec, err = ttlspec.Parse("90d")
// → TTLSpec{ TTLMs: 7_776_000_000, SourceStr:"90d" }
spec, err = ttlspec.Parse("forever")
// → TTLSpec{ TTLMs: 0, SourceStr:"forever" } // unbounded
// Auto-bucket to nearest policy triple (RFC-EPH-TTL-001 §4)
policy := ttlspec.DeriveTierPolicyV2(spec.TTLMs)
// → AnchorPolicy, SigScheme, StoreClass derived from resolved TTL // ExpiryHeap is a thread-safe min-heap over (expiresAtMs, ledgerID).
// O(1) peek, O(K log N) for K expired ledgers per tick.
h := retention.NewExpiryHeap()
h.Push(ledgerHex, expiresAtMs)
// Garbage-collection tick — called by the scheduler
expired := h.PopExpired(time.Now().UnixMilli())
for _, e := range expired {
engine.GC(e.LedgerHex)
}
Migration from the pre-v2 four-tier model is handled by
ttlspec.LegacyPresetForTier(n),
which maps old tier integers 0–4 to their canonical v2 TTL specs.
Existing T0–T4 ledgers are unaffected; no data migration is required.