Before anything else, read the design principles in full. They are short, they are specific to this project, and the rest of this file assumes you hold them.
This is an anthology of current ML practice: what to do, and the published
work that says why. Organized by the kind of claim, not by the domain a
technique was discovered in (ADR-026, superseding ADR-020). The topics are
an axis, not a scope: if something the anthology wants cannot be placed on
it, that is a finding about the axis — add the topic, never decline the
document (ADR-059). The bias toward language-model training is
a bias, not a boundary, and since ADR-026 the practice registry and the
reading list share one topic vocabulary — the two schemes differ in what a
document is, not in what it may be about. Its memory is a Luria record — scaffolded,
generated and linted by the luria CLI. This file is a map, not a copy: when
it disagrees with luria --help or with the record, this file is wrong.
Where things are
record/is where you file.practices.d/holds one document per recommendation,theory.d/one per explanation,literature.d/one note per paper, plus the decisions, principles, changelog fragments and curation journal.docs/is where a reader browses. Everything in it is generated — see README.md. Never edit an assembled page; edit theREADME.stubbeside the sources and runluria index.data/is the pre-migration YAML, frozen. Nothing reads it at build time; it is the import’s provenance, and keepssrc/scripts/migration/to_record.pyre-runnable. See ADR-008 anddata/README.md.
The three schemes, and why there are three
A practice (SOTA) is a claim about what you should do. A theory
(THEORY) is a claim about why it works. A note (LIT) is a paper’s
standing in the anthology. They have separate statuses and are allowed to
disagree: a foundational paper can carry advice that has moved on, a paper in
the attic can be the source of something everybody still does, and a
technique everybody uses can have been published with an explanation that was
later refuted. Collapsing the first and the third is what the old schema did,
and ADR-002 is why it stopped; splitting the
second out of the first is ADR-031.
The test when filing: if it tells the reader what to do it is a practice,
and if it says what is true it is a theory. Rejected does not mean the
same thing in the two schemes — on a practice it means do not do this, on a
theory it means the reason is wrong, and the thing it explained may still
work perfectly well.
Rules that are actually enforced
- Every practice and every theory names a
source:. A recommendation with no paper behind it fails the lint, and so does an explanation. If the paper is not in the record,luria new litfirst. - Every note names a source. At least one of
arxiv:,doi:,url:, in that order of preference — the first two resolve through a remote, a URL is a string nothing can check (ADR-009). Two papers reached the old corpus with no identifier at all; that is now impossible. - The first tag is the primary topic, and a document may carry more than
one. The twenty-eight live in the
topicsvocabulary inluria.yaml— one table, named by the practice registry and the reading list alike, glosses included. List the topic the document is most about first:primary_topicderives{tags[0]}, so tag order is what the indexes read. Tag the document’s subject, liberally — more than one topic is normal and three is fine. The test is whether a tag is justifiably appropriate: would someone browsing that topic be right to expect this document? Not whether it is the single best word, and not why the record went and got the thing (ADR-046). - An unbound relation is a defect, and “somebody looked at it” is not an
answer.
chainsdeclareinvariant: tags, so a relation the report calls unbound has exactly two readings — the invariant is missing, or the relation is wrong — and never a third (ADR-049, which took 22 unbound relations and 10 unbound lines to zero and rejected an acknowledgement directive for the purpose). So the report is where you find documents that are not saying what they are about, and answering one by adding a true topic is the intended response. The narrow thing that stays forbidden is inventing a label to satisfy the check (ADR-035§4) — impossible onSOTA,LITandTHEORYanyway, where the vocabulary is closed. If the honest tags will not bind, say so and fix it: either the relation is wrong, or the vocabulary is short a word and the next bullet is what to do about it. - The tag vocabulary is closed, and that is an invitation. A tag not in
topicsfails the lint onSOTA,LITandTHEORY. That is there so every tag is one somebody chose and blurbed — not because the list is finished. If a document wants a word the vocabulary cannot say, the intended move is to add it, with a label and a blurb and a decision saying why, exactly asrepresentation-and-encodingandanalysis-and-evaluationwere added. Reaching for the nearest wrong tag because the right one is absent is the failure this is meant to prevent, and the lint’s message does not yet say so (LU-#273).
- Never hand-write a link target. Write the bare code —
LIT-041,ADR-002,ARXIV-1412.6980— and runluria link --fix. Prose renders into several directories and only the fixer knows which frame a target resolves from. - Retire by changing status, never by deleting.
Rejectedis the attic;Supersedednames its successor. The body stays. - Some relations must be explained where they are held
(ADR-063). A practice’s or theory’s
source, a practice’sintroduced_by, a theory’sexplains, everycorrects,contested_by,rivals,extendsandcompared_against: each code is cited in the body, in visible prose that says what the relation means (explain: cited). Noref::statement is needed beside the citation; the sentence is the explanation. The## Sourceline does not count: a reference entry names the paper and says nothing about it, so the code has to appear again where the body says what the paper showed. A code in backticks is a mention and explains nothing either. The lint reports each one asunexplained-relations, a warning, not a failure, with the line of the entry it found. Clear one by reading: the paper’s note, its close reading if there is one, the paper itself if neither says enough. Then write what it showed. A sentence that names the paper and says nothing it showed passes the check and defeats the rule.
Working
luria new sota --title "..." # or: theory, lit, adr, dp, changelog
luria repair # created:, status notes, stale config refs
luria link --fix # spell the targets, complete the relations
luria index # regenerate every view
luria lint # the only command that can fail
Or make ready, which runs those four and discards the views (ADR-054).
You need both repair and link --fix, and neither contains the other.
repair populates a journal entry’s created: from the path luria new
chose, moves a note out of status:, and retires a stale config reference.
link --fix writes the converse of a declared relation, which repair
does not — measured, not assumed: repair reported nothing to do on a tree
where link --fix then wrote two back-references.
Run all of them before pushing — then do not commit what luria index
regenerated. Views land on main only: CI regenerates and commits them on
the push, and a pull request writes none (ADR-018). Run index locally
anyway, because the lint checks the views against the sources; then
git checkout -- docs/ before you commit. (Since luria 0.33 the lint lists
every site of a retired or unresolved citation itself, so the reports are no
longer the only place to find them.) A branch carrying views is not more up to date, it is a conflict with
every other branch. Run make hooks once per clone and the tracked
pre-commit hook refuses them for you.
Temporary codes land on main and are renamed a commit later, so wait for
that commit before you branch. luria concretize runs only where merges
serialize — the push job on main — because that is the only place “the next
free number” is a fact rather than a race, and a PR branch carrying
LIT-tmpxxxxx is therefore correct, not a mistake. The consequence is that
main’s tip is briefly inconsistent: the merge commit still holds the temp
codes and the bot’s next commit renames them. Measured on #367, that window
was 62 seconds, and CI serialises runs, so a queue makes it minutes. Branch
inside it and cite anything the merged PR filed, and your next rebase conflicts
on the renames. Before git checkout -B:
git ls-tree -r --name-only origin/main record/ | grep -c tmp
Zero means main has caught up. It has to be git ls-tree origin/main, not
ls on your checkout — a working tree descended from the merge commit still
has the temp files, so the local check answers the wrong question and answers
it reassuringly; that is how the trap was walked into three times in one
session. luria concretize --check cannot help here either: it reads the
working tree, and the question is about a ref. LU-#325 asks the CLI to own
this, so that the configured temp shape and the set of merge-allocated schemes
are what gets checked rather than the substring tmp; delete this paragraph’s
grep when it ships.
luria lint is warn-first: warnings are real findings, not noise, and the
ones about retired citations are the check this project adopted the record to
get. Acknowledge a deliberate one with an inactive-ok: comment at the
citing site — and write it from the lint’s own report, after running it,
never from memory of a document’s status. A directive naming no code vouches
for nothing, and one vouching for an Active document is itself a finding.
Work goes to a branch and a pull request. File the fragment in the same contribution as the work — a fact written while the context is loaded costs a paragraph, and re-derived cold it costs a session.