Date: 2026-03-06 Status: Completed, except Vanity ID generation, which is won't-do.
QNTX used teranos/vanity-id (Go, v0.3.0) for all ID generation — attestation IDs, subject names, job IDs. The library was imported in 25+ files. It worked, but it was a single Go module that couldn't run in the browser, and it conflated two fundamentally different concerns: human-readable names and unique attestation identity.
QNTX's identity system has three orthogonal layers, each with distinct properties:
| Layer | Purpose | Uniqueness | Mutability | Example |
|---|---|---|---|---|
| Vanity ID | Human-readable subject handle | Semi-unique (context disambiguates) | Immutable once assigned | SARAH, SBVH, ACME |
| ASUID | Attestation identity | Unique (random suffix) | Generated once per attestation | AS-SARAH-AUTHOR-GITHUB-7K4M |
| Node DID | Signer identity | Globally unique (ed25519 keypair) | Generated once per node | did:key:z6Mk... |
A node was a server when this table was written. Since ADR-012 it is also a
browser, and server/nodedid/ cannot reach one.
Of the three, only ASUID has a generator. Subjects carry names a human supplies,
checked by a write-time warning rather than derived. Node DID is minted in
server/nodedid/.
Node DIDs already exist (server/nodedid/). This ADR defines the first two layers and commits to implementing them in Rust.
The third layer is described here and decided nowhere. server/nodedid/store.go
holds one ed25519 keypair per node under id = 'self', and no ADR specifies it.
ADR-012 made that gap load-bearing by accepting the browser as a node.
Tracked in #840.
Vanity IDs are human-readable handles for subjects only. They are names, not keys.
SARAH subjects can coexist; the attestation graph disambiguatesVanity IDs do not apply to predicates, contexts, or actors.
ASUIDs are unique identifiers for attestations with readable SPC segments for log scanning.
Structure:
AS-SARAH-AUTHOR-GITHUB-7K4M3B9X
╰prefix╯╰─S──╯╰──P──╯╰──C──╯╰──suffix──╯
AS attestation, JB job, PX pulse execution)Randomness is caller-provided:
crypto/rand, browser uses crypto.getRandomValuesats-idBoth layers are implemented in the Rust crate ats-id, maintained in this repository. The Go dependency on teranos/vanity-id has been retired (#793).
Design principles:
Shipped in phases, each independently releasable, and all of it landed except one: Vanity ID generation was dropped — deriving a handle from a name is not needed, so subjects carry names a human supplies. The generator also covers non-attestation IDs (embedding IDs, run IDs), which is why it outgrew its name.
teranos/vanity-id v0.3.0 — prior artserver/nodedid/ — existing Node DID infrastructure