Expand description
The unique-ID registry — Phase 24.4.
A server-side record of every identifier this deployment has issued, so a
new one can be checked for uniqueness before it is handed out and a
presented one can be checked for provenance. Keyed hash only, never the
value: a database of every API key ever minted would be the best single
target an attacker could find, so what is stored is
HMAC-SHA256(pepper, normalise(value)) truncated to 16 bytes — enough to be
collision-free at any size this will reach, and useless if stolen.
Lives in its own SQLCipher file, registry.db, beside vault.db. Its key
and pepper are random 32-byte values held in the vault’s vault_meta
table: the registry only opens while the vault is unlocked, travels with
vault backups, and survives a master-password change without needing its
own KDF.
Storage shape and pragmas are exactly what was measured on 2026-09-14
(CLAUDE.md, Phase 24.4): WITHOUT ROWID, a date index, a 32 MB page
cache, and pruning in 10,000-row chunks rather than one statement — the
single-statement prune held the writer lock for 45.7s at 10M rows in that
benchmark, which would stall every mint and register behind it.
Structs§
Enums§
Functions§
- check
- Advisory only — “unique right now”. Never authoritative:
registeris the only operation that actually reserves a value. - ensure_
registry_ secrets - Reads the registry’s SQLCipher key and HMAC pepper from
vault_meta, generating and persisting both the first time the registry is used. Callers never see the values live anywhere but here and inside the open registry connection. - hash_
value HMAC-SHA256(pepper, normalise(value)), truncated to 16 bytes. The namespace is not part of the input — that is what “unique across everything” means: the same string minted under two namespaces is one collision, not two independent slots.- init_
schema - lookup
- One value → provenance the caller may see.
check/lookupare the enumeration oracle for a low-entropy namespace — the rate limiter is the control, not this function. - mint
- Generate-check-register in one call, retrying up to
max_attemptstimes on collision.generateis supplied by the caller (unv-server), which owns the id-shape decision this module has no opinion about. - normalise
- Decides what “the same ID” means. Getting this wrong makes two spellings of one identifier both look unique.
- open_
registry - Opens (creating if absent)
registry.dbatpathwith the measured pragmas. - prune
- Deletes rows older than
before_ts, optionally narrowed by namespace, generator or actor (all resolved throughuid_meta). Runs in chunks ofPRUNE_CHUNKrows in separate transactions, so registration and minting are never blocked behind one long-held writer lock — the measured reason a singleDELETEwas rejected (45.7s at 10M rows vs. a 0.38s worst chunk). - register
- Registers every value as one batch. Each is an
INSERTthat fails on the primary key — never a read-then-write — so two concurrent registrations of one value cannot both succeed; the loser is reported as a conflict, not an error. - register_
external - Registers an ID that was minted elsewhere — the provenance-recording
half, distinct from
mintwhich generates in-process. - stats