Context
Journals and schemes disagreed about where identity lives, and neither said
why. A journal entry’s path derives from its created: frontmatter, and
luria lint checks the two agree — stated in check_journals as: “the
ordering the whole scheme rests on says one thing and the frontmatter says
another.” A scheme document had no such field. Its number was parsed out of
the filename, so the name on disk was the identity.
That is what blocked expressive filenames and derived aliases. Any
information a filename carries becomes load-bearing the moment the filename
is the identity, so a slug cannot be added without making the slug part of
what a citation resolves through. The consuming record had paid this: its
pre-migration identifiers (MLR-2014-Kingma001-0001, plus a topic_id
slug) were readable without a lookup, and became SOTA-001 and nothing.
Decision
A scheme document carries number:, an integer, and the filename is a
projection of it.
Scheme.number_of()reads the field, falling back to the filename.luria lintreports a document whose field and filename disagree.luria repairwrites the field from the path where it is absent.luria newwrites it for a scheme that allocates on filing;luria concretizewrites it for a merge-allocated one, at the moment it assigns a number at all (ADR-049).
The fallback is what makes this introducible without a migration anyone has
to run: a record written before the field existed reads exactly as it did,
and acquires the field the next time luria repair runs.
A counter, not a UUID. The number carries the order documents were filed — the scaffold says so in as many words — and a UUID would discard that to buy merge-safety that temporary codes already provide.
Alternatives considered
- Leave identity in the filename. The status quo, and the thing that makes every downstream ask impossible: a filename that carries meaning and also carries identity cannot have the meaning corrected.
- A UUID or URI per document. Genuinely more robust against collision, and it discards ordering to solve a problem ADR-049 closed. Rejected for paying information to buy nothing new.
- Derive the code from frontmatter at allocation — evaluate a template
once in
luria concretizeand freeze the result. Technically safe: identity never moves afterwards. Rejected because a seeded code looks derived and is not, so correcting an author leaves a code reading the old name forever, correctly-by-design, and every future reader has to be told. A number makes no claim that can rot. The rule this settles: a derived value may participate in identity only if it is recomputed, and it may only be recomputed if it is not identity. - Call the field
uid:. The first spelling, and wrong twice over. The “u” promises uniqueness across the record, and the value is unique only within its scheme — three schemes give three documents1. Anduidwas already taken: a remote declares one to mean an opaque foreign tail (ADR-024), so the same word would have named two unrelated things.numberis what the code already calls this value everywhere (number_of,Adr.number, the{number}template variable), promises nothing about scope, and leavesuidfree for a record-global identifier if one is ever wanted. - Rename the file automatically when the two disagree. Rejected: which of the two is right is a question only the author can answer, and renaming on a guess moves a document’s identity and orphans the links to it. An absent field is the mechanical case, and that one is repaired.
Consequences
Scheme.documents() goes from a directory glob to a glob plus a frontmatter
read. Cached on the file’s (mtime, size) rather than reset by hand, so a
writer that forgets to invalidate cannot serve a stale identity. That it is
one function to change at all is owed to DP-4: five copies of that glob had
accumulated and were consolidated for unrelated reasons.
A disagreement between field and filename is now a way to break reference
resolution that did not previously exist — documents() reads the field
while a link target is written from the code — which is why the check is a
violation rather than a report.
Verified on both records before landing: 436 documents in the consuming
anthology and 103 here acquired the field, luria lint held its exact
baseline in both, and every generated view was byte-identical except the
reference report, whose line numbers shift by one because the field adds one
line. The guard was fired on a real document too, not only a fixture.