ADR-010: QNTX Identity System — Vanity Subjects and Attestation System Unique IDs

Date: 2026-03-06 Status: Completed, except Vanity ID generation, which is won't-do.

Context

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.

Decision

QNTX's identity system has three orthogonal layers, each with distinct properties:

LayerPurposeUniquenessMutabilityExample
Vanity IDHuman-readable subject handleSemi-unique (context disambiguates)Immutable once assignedSARAH, SBVH, ACME
ASUIDAttestation identityUnique (random suffix)Generated once per attestationAS-SARAH-AUTHOR-GITHUB-7K4M
Node DIDSigner identityGlobally unique (ed25519 keypair)Generated once per nodedid: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

Vanity IDs are human-readable handles for subjects only. They are names, not keys.

Vanity IDs do not apply to predicates, contexts, or actors.

ASUIDs (Attestation System Unique IDs)

ASUIDs are unique identifiers for attestations with readable SPC segments for log scanning.

Structure:

AS-SARAH-AUTHOR-GITHUB-7K4M3B9X
╰prefix╯╰─S──╯╰──P──╯╰──C──╯╰──suffix──╯

Randomness is caller-provided:

Implementation: Rust crate ats-id

Both 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.

Consequences

Positive

Negative

Neutral

References