Context
Two commands write sources, and nothing says which write goes in which.
luria repair (ADR-068) writes every mechanical source repair: a bare
code linked (ADR-005), created: filled from a journal entry’s path,
number: from a filename, a status note moved into status_note: and
superseded_by:, a retired alias recorded in formerly:, an
already-concretized spelling upgraded. Its contract is in its docstring:
every repair is one the lint reports with repair as the remedy, and a
second run finds nothing to do. The generate action runs it on every pull
request and commits the result onto the branch, and runs it again on the
default branch after luria concretize. ADR-119 drew its one boundary: a
write that needs a judgement, such as an acknowledgement’s reason, cannot
meet that contract and stays out.
luria link --fix runs only where somebody types it. It writes the links
(the same linkify_files that repair calls), rewrites <a name=> anchors
that something links to, writes relations stated in prose into frontmatter
(annotations.complete), and completes declared converse pairs
(relations.complete, ADR-084).
The split was never stated, and its cost is measurable. Converse completion
lives only in link --fix. Nucleation’s own guidance tells contributors not
to run repairs locally because CI does them. So the one repair
CI does not do never ran, and the record held 812 one-sided pairs. luria relate had been telling users that luria repair writes the converse, which
was never true.
Decision
A write belongs in luria repair when its answer is a function of the
committed sources and the configuration alone. Concretely:
- any checkout of the same commit computes the same edits, so CI on the pull request, CI on the default branch and an author’s machine agree;
- a second run computes none (ADR-068’s idempotence, which the generate job relies on when it runs again on the commit it pushed);
- there is one right answer, so the lint can report the state and name
repairas the remedy without a person choosing between readings.
A write belongs only in luria link --fix when its answer needs something a
checkout does not have. Today that means one thing: the author’s
uncommitted change against HEAD. ADR-084’s completion decides whether a
one-sided pair is a fresh write or a stale deletion by comparing the working
tree with HEAD. In CI, HEAD is the tree. Every edge reads as “nothing
changed” and is written to both sides, so a deletion the author committed
is written back. That command cannot run where repairs run without changing
what it means.
A judgement belongs in neither (ADR-119). Its home is a command that asks
for the judgement, as luria ack asks for the reason.
link --fix may also run repairs, but no repair waits on it. It already
runs the linking repair runs, for an author who wants the result before
pushing. The reverse does not hold: nothing CI should converge on is allowed
to depend on someone having run link --fix.
The rule comes from the commands’ existing contracts. ADR-068 says a repair is committed on the branch by the job, so it must mean the same thing on any checkout. ADR-119 says a repair has one right answer. ADR-084 is the one writer whose answer moves with the working tree. Whatever is not HEAD-relative and not a judgement is a repair (DP-004: one implementation, run where it converges).
Applied
- A directed converse pair’s normalization (ADR-137) is a repair. It
reads the sources and the configuration’s
derived:marks, and nothing else. It moves or drops an entry filed on the derived side, and a second run finds nothing. - Converse completion for a symmetric pair or an undirected one stays in
link --fix, because it reads HEAD. - Two writes appear to qualify and are not moved here: the anchor rewrite
(
fix_anchors) and the prose-to-frontmatter relation write (annotations.complete, whichunrecorded-relationsnameslink --fixfor). Each reads only sources as far as this decision checked. Moving either is its own change, to be checked against its own edge cases first, rather than a side effect of this one.
Alternatives considered
- Everything mechanical goes in
repair. This is the obvious reading of “repair writes mechanical fixes”, and it is wrong by one case. ADR-084’s completion is mechanical given a baseline, and the baseline is the author’s working tree against HEAD. Run in CI, it writes back every deletion that reached a commit. The test is not “mechanical” but “the same answer on every checkout”. - Split by how often a write is needed. Rare cleanups in one command and everyday ones in the other. Frequency has nothing to do with whether CI can compute the answer, and Nucleation’s pairs show that a write left to “whoever runs it” piles up regardless.
- A third command for relation writes. Another command nobody’s CI runs. It reproduces the gap it would close.
- Status quo: leave the boundary implicit. This produced the 812 pending
pairs and the false sentence in
luria relate.
Consequences
The question “where does this new write go?” now has a test someone can apply:
would CI on a fresh checkout compute the same edits? If yes, it goes in
repair, the lint names repair, and it converges on every pull request
without anyone remembering to run anything.
link --fix shrinks over time towards the HEAD-relative completion and the
local convenience of running the linking early. If ADR-137’s directed
pairs replace undirected ones everywhere, only symmetric relations keep it
busy.
The two candidates named above are follow-up work, recorded here so they are not found again from scratch.