# Identifiers

Edition 2026-08-14. Describes GAVR record schema 1.0.

Two namespaces, one alphabet, deliberately different shapes.

```
GAVR-A7K2QXR8          central, opaque, allocated only by the registry
GAVLR-42-7-A7K2QX      local, self-issued, the path IS the delegation chain
```

## The identifier is the canonical reference, never a URL

`GAVR-A7K2QXR8` is what a citation quotes. Every host serving it is a
**resolver**: none is privileged, none is ever switched off, and a record may be
served by the registry, by any mirror, and by the issuing authority's own
infrastructure simultaneously. This is the DOI and OID model, and it is what
makes a future domain move a non-event. Nothing in this specification embeds a
host, and an implementation that stores a resolver URL as the record's identity
has stored something that will rot.

## No year

CVE's year is the _reservation_ year, not the disclosure year: CVE-1999-0145
describes a 1983 flaw. Practitioners report that year-based statistics over the
corpus cannot be trusted as a result. Copying it would have been copying a known
defect deliberately, and dropping it also keeps a local identifier readable at
delegation depth 3.

## Alphabet

Crockford base32 minus `I`, `L`, `O` and `U`:

```
0123456789ABCDEFGHJKMNPQRSTVWXYZ
```

`I`, `L` and `O` are excluded because they collide with `1`, `1` and `0` in most
typefaces and in OCR. `U` is excluded by Crockford to keep accidental obscenities
out of generated identifiers.

## Grammar

```abnf
record-id     = gavr-id / gavlr-id
gavr-id       = "GAVR-" tail
gavlr-id      = "GAVLR-" 1*3( segment "-" ) tail
tail          = 6*16 ALPHABET
segment       = "0" / ( %x31-39 *DIGIT )      ; no leading zeros
```

The published JSON Schema carries this as a `pattern` (rule **GAVR-R-008**),
together with a `maxLength` of 255.

**Tails are minted at 8 characters and accepted at 6 to 16.** Pinning the
validator to exactly 8 would freeze the length forever, because growing it later
would need a v2 format and would break every regex a consumer had deployed.
Accepting the range from day one lets the allocator move to 10 or 12 when volume
justifies it while every previously issued identifier stays valid, which is the
whole permanence promise.

**Segments carry no leading zeros.** `GAVLR-042-...` is refused rather than
silently treated as `42`: two spellings of one identifier is exactly the
ambiguity a permanent namespace cannot afford.

**A segment must be an exactly representable integer** (rule **GAVR-R-009**, a
companion rule). A regex accepts a decimal run of any length, so
`GAVLR-99999999999999999999-A7K2QX` matches the grammar and must still be
refused: parsed as a number by any implementation, it resolves to a _different_
registry than the one written down. Implementations without a 53-bit float
hazard should still refuse it, so that every implementation agrees on which
identifiers exist.

## Delegation and the depth cap

A local identifier's path is its delegation chain, root first. The central
registry assigned `42`; `42` assigned `7` to its own child. Uniqueness falls out
of the path with no global coordination, exactly as it does for a DNS name or an
OID arc.

The network maximum depth is **3**. A local registry may declare a _lower_ cap
for its own subtree and may never raise one: the cap bounds resolution cost, and
every hop is infrastructure the resolver does not control, so unbounded depth is
a denial-of-service vector rather than a feature. A subtree's own lower cap is
resolution policy and is therefore not in the published pattern, which expresses
the network maximum only.

## Normalisation

A human-supplied identifier is repaired before lookup: trimmed, uppercased, and
the Crockford confusables folded — `I` and `L` to `1`, `O` to `0`. `U` is _not_
folded, because it is excluded to avoid obscenity rather than because anything
is mistaken for it, so there is no correct target and a `U` in a tail is simply
wrong.

**The fold applies to the payload only, never to the prefix.** `GAVLR` contains
an `L`. Folding the whole string rewrites the namespace itself to `GAV1R` and
turns every local identifier into a parse failure. This is the single trap in
this section, and it is why the prefix is split off before folding.

Normalisation returns nothing when the result is still not well formed, so a
caller may treat any output as canonical.

## Permanence

An identifier is bound to one vulnerability permanently.

- **Never reused.** A cached record or a published citation must never come to
  mean something else.
- **Never reassigned.** Ownership of a record is mutable; the identifier is not.
- **Corrections use supersede**, never release-and-reissue. A mistaken record
  points at its replacement and stays resolvable.
- **An expired reservation is retired, not returned.** It is marked expired
  permanently, its row is never deleted, and the public placeholder stops
  advertising it. Deleting the row would make the identifier look
  never-allocated, and a later mint could draw it again.

## Resolution

Resolving a central identifier is a lookup at any resolver. Resolving a local
identifier walks the chain: the central registry resolves `42`, asks `42` to
resolve `7`, and fetches from there. Results may be cached briefly; a resolver
is a cache, not a mirror, and does not vouch for what it resolves.

A resolver answers one of five shapes: the record, a reservation placeholder, an
unclaimed-block placeholder, an expired-identifier statement, or 404 for never
allocated. **A malformed identifier answers 404, not 400** — to a resolver those
are the same answer, and a 400 tells a scanner something a 404 does not.

Local identifiers are **resolved, never promoted**: they do not appear in the
central database, search, listings or feeds. Central identifiers are accredited,
reviewed and indexed; local ones are self-issued and self-governed. Any surface
that can show both must make that difference unmissable, or the accredited
namespace is worth nothing.
