The lint’s warning classes are judgement calls: a citation of a superseded decision might be exactly right (history, or a rejection worth pointing at), and only a human can say so. Directives are how a judgement, once made, is written down where the finding is — so the check stops asking, the reason survives, and the report still counts what was acknowledged.

Shape

A directive lives in a comment — HTML comments in markdown, # comments in a record document’s YAML frontmatter, #, //, /* */ or -- comments in code — and reads:

<!-- inactive-ok: ADR-012 — the rejection is the point being made -->

That is: a name, optional scope suffix, a colon, arguments (codes, paths, or keywords, separated by spaces or commas), and after an em-dash, the reason. The reason is prose for the next reader; write one.

Giving one a deadline

An acknowledgement is a promise about the future — this reference to a Proposed decision is deliberate. Some of those promises are permanent (this page is that history) and some are not (circle back after the release). The ones that are not go stale silently, which is the exact failure directives exist to prevent, one level up.

So a directive can carry an expiry:

<!-- inactive-ok: ADR-028 until 2026-10-01 — revisit when the API settles -->

After that date luria behaves as if the directive were never written: the check it silenced starts reporting again. The date is inclusive — good on the 1st, gone on the 2nd — because somebody writing until 2026-10-01 means the last day it holds, not the first day it does not.

until <date> works on every directive, not just inactive-ok; it is part of the shape, like the scope suffix (ADR-095). An ISO date and nothing else — a duration (“two weeks”) would need an anchor the file does not carry, and the date is that anchor, written down.

Two things it does not do quietly:

  • An expired directive is reported. luria lint names the file, the directive, the date and the author’s own reason, under expired-directives. Silently dropping it would leave a check failing again with the acknowledgement still sitting above it, which is a puzzle rather than a report.
  • A date it cannot read is reported, and the directive stays live. until nextweek is a typo, and dropping a suppression over a typo breaks a build for a reason the failure message would not explain. The report is the correction.

Scope is how much text the directive governs:

spellinggoverns
name:its own line and the next line
name-block:the paragraph (blank-line-delimited block) it sits in, or the following block when the comment stands alone
name-file:the whole file

A blank-line-delimited block is a guess at where a block ends, and every language has a construct that holds a blank line — a Python docstring, a YAML mapping, a function body. Install the optional extra:

pip install luria[syntax]

and -block reads the real one from a tree-sitter grammar instead: the smallest syntactic unit that starts where the block’s content starts and holds the whole block. It is the same rule in every language the grammar pack supports, and it can only extend what the blank-line block already governed — a directive that works without the extra works the same with it. Without the extra nothing changes, and LURIA_TREE_SITTER=0 turns it off without uninstalling it.

So this reaches a citation in a docstring’s third paragraph, which the blank-line rule cannot:

# inactive-ok-block: ADR-012 — the decision this function replaced
def apply(...):
    """First paragraph.
 
    A later paragraph citing ADR-012."""

With a grammar the extra also stops reading a comment marker inside a string literal as a comment — echo 'see # this' in a shell script is one string, not a directive site.

A citation site can be a frontmatter field: superseded_by: naming a document that was itself later retired is reported at that line like any sentence. The line-scoped form answers it in place, as a YAML comment directly above the field:

# inactive-ok: ADR-012 — the successor was itself later rejected; the chain is deliberate
superseded_by: ADR-012

Only a whole-line # comment inside the frontmatter counts; a # inside a value is data, and a # in the body is a heading.

A directive that no longer matches anything — the document went Active again, the hand-written URL was fixed, the argument has a typo — is itself reported under stale-directives, so acknowledgements cannot quietly outlive what they excuse.

The vocabulary

directiveacknowledgesargument
inactive-ok:a citation of a document that is not in force (retired-citations)the code(s)
unresolved-ok:a code that resolves to no document, kept deliberately (unresolved-codes)the code(s)
mention-ok:a code that is named, not cited — the text makes no claim about the document’s state, so this covers both findings above and does not retire when that state changes (ADR-105)the code(s)
url-ok:a remote code linked to a hand-written URL instead of the constructed one (hand-written-urls)the code(s)
target-ok:a relative link target that resolves to nothing from where the prose renders (broken-targets)the exact target
source-ok:an identifier whose upstream title is not the one recorded (source-mismatch) — a preferred nickname, a trimmed subtitle, a title that changed between versionsthe identifier(s)
broad-ok:a term flagged by narrow-titles, used in a legitimately broad sensethe term(s)
unlinted-file:opts the entire file out of reference checking — the blunt tool for fixture-heavy or vendored pages. File-scoped by design; counted in the report rather than hidden—
unexempt:the reverse of an exemption: makes the linker treat code regions as prose again, for pages about the reference syntaxcodeblock, inline-code
pin:not an acknowledgement — a registration: marks a cited URL for content pinning, so luria remotes --pin endorses its bytes and the lint reports when they change (remote-drift)the URL(s)

Each acknowledgement covers findings at its own site only — that locality is the point. Vouching for one citation of a retired decision says nothing about the next one, which gets its own look and its own reason.

One warning class is acknowledged without a directive on purpose: remote-drift (a pinned document whose content changed upstream) is cleared by re-endorsing — luria remotes --pin CODE after reviewing the change — because the judgement lives in the lockfile, not in prose at a citation site.

pin: runs the other way from every acknowledgement: it arms a check rather than quieting one. Flag a URL where it is cited —

<!-- pin: https://spec.example/v1.html — the spec this implements -->
We follow [the spec](https://spec.example/v1.html).

— and luria remotes --pin endorses its content by hash; from then on the lint reports when the bytes change. The URL must appear in text the directive governs (its own comment doesn’t count), so a flag whose citation was deleted reports itself under stale-directives like any other directive. Deleting the flag retires the pin — the next bare luria remotes --pin prunes it — so a pin that fires too often costs one removed comment, and the URL goes back to being an ordinary, unwatched link. Foreign codes need no flag: luria remotes --pin LU-ADR-013 already covers them.

Mentioning a code without citing it

Backticks are the lighter tool and usually the right one: a code inside ` inline code ` or a fenced block is masked from the reference machinery entirely — not linked, not counted, not checked. That is how documentation (including this page) shows codes as syntax. A directive is for the cases where the code should stay bare prose and still be excused.

Fixture codes

A mention is not a citation. Some references name a code without asserting anything about it — a specimen quoted as evidence, prose about a code’s literal spelling, a demonstration of what a moved address looks like. mention-ok: is the word for those, and the reason it exists is that the others retire on a change it should survive: unresolved-ok claims the code resolves to nothing, which stops being true the day somebody allocates that number, and the annotation then goes stale for a reason that has nothing to do with why it was written.

It is used while the code it names is cited in its scope, whatever the document’s state, and reported stale the one way that is still about the annotation: when nothing in scope names the code any more.

Prefer the FX prefix below where you control the spelling — it needs no acknowledgement at all. Reach for mention-ok: when the spelling is the point, as in prose about a code that a regex once failed to match.

Documentation and tests need example codes that look real but deliberately resolve to nothing in this record. Rather than sprinkle unresolved-ok: everywhere, this project reserves the FX remote prefix for them: a code like FX-ADR-001 is declared, resolves by a fixed URL template (to this section), and reads unambiguously as “an example, not a citation”. Any project can adopt the same convention with a one-table remote:

remotes:
  FX:
    name: fixtures
    url: https://github.com/dmarx/luria/blob/main/docs/directives.md#fixture-codes

That covers a fixture code that should resolve somewhere harmless. A test suite usually wants the opposite: a code belonging to a scheme it declares itself, in a tmp_path project, which the project running the suite has never heard of. So the whole FX prefix is a reserved namespace, and no project declares a scheme whose prefix begins with it:

  • FXL is the local fixture scheme by convention.
  • FXM is the second one, for a fixture that needs two prefixes at once — a rename_scheme migration, say.
  • Any other FX… name is available for the same purpose. AFX is not reserved: the match is on the leading prefix, not a substring.

luria lint refuses a declared scheme in the namespace, at the config rather than at each citation, so the guarantee cannot be taken away by accident. See ADR-093.

Design notes

  • Directives are found by tokenising real comment syntax per file type, so a string that merely looks like a directive in running prose does not fire.
  • Arguments are validated: a directive naming an unknown code, an unknown region keyword, or nothing at all is reported rather than silently inert.
  • The reports remain a complete account. Every acknowledgement is counted next to what it silenced — the bargain is quiet checks, never hidden findings.