Skip to content

fix: a verb that moves a record repoints every link that named it - #703

Merged
REPPL merged 6 commits into
mainfrom
fix/spec-close-repoints-links
Sep 25, 2026
Merged

REPPL merged 6 commits into
mainfrom
fix/spec-close-repoints-links

Conversation

@REPPL

@REPPL REPPL commented Sep 25, 2026

Copy link
Copy Markdown
Collaborator

A verb that moves a record now repoints every link that named it. Before this, each spec close, intent plan, capture resolve and capture wontfix left links to the old path. record-lint's links_resolve then refused them, and they were repaired by hand.

  • New leaf package internal/core/relink: Repoint walks every markdown file in the tree. It rewrites inline links and link-reference definitions that resolved to a moved path, including the moved record's own links written from the folder it left. It leaves alone any link that never resolved, and it is idempotent.
  • It is wired into intent.Reconcile (spec close), intent.Plan (drafts to planned) and the ledger's resolve and wontfix, the last under the ledger lock. The results list each rewrite (relinked in --json). A repoint failure is a warning on stderr, and the verb still succeeds.
  • A re-run repoints the links other files still hold. It reads a record's own links from the folder it left only when that same run moved the record, because a record an earlier run moved may have been edited where it is now. The docs describe that boundary.

Review: Fable 5.1. The first round asked for the re-run's own-link handling to be fixed, and the fix round was verified. The verification round's three stale sentences were fixed in 320ea7c. Reading-corpus change: the window eval passed.

Resolves: iss-2608311127491949
Resolves: iss-2609091732329046
Resolves: iss-2609250846525896
Assisted-by: Claude:claude-opus-5-5

… record

capture resolve, capture wontfix and intent plan rename a record between
status folders and leave every relative link that named its old path
dead, the gap spec close has too. Captured before the fix that closes it.

Refs: iss-2609250846525896
Refs: iss-2609091732329046

Assisted-by: Claude:claude-opus-5-5
A record's folder is its status, so spec close (open/ -> closed/, and
planned/ -> shipped/ on the close that ships), intent plan
(drafts/ -> planned/), capture resolve and capture wontfix are all
renames, and each left every relative link that named the old path
dead. record-lint's links_resolve then refused the tree the next command
ran against, and every intent lane of run A repointed links by hand.

core/relink is the one link-repoint primitive the four verbs share. It
takes the moves a verb made, walks the working tree's markdown and
rewrites every inline link and link-reference definition that resolved
to an old path, including a moved record's own links written from the
folder it left, and reports each rewrite (file, line, from, to). Three
link classes, one rule: a spec already closed that names
../open/<the closing spec>, ADRs, plans and drafts naming an intent's
planned/ path, and the closing spec's bare links to siblings still in
open/. A link that never resolved stays as written. The walk stays out
of .git, the local tier, nested checkouts and the two append-only logs
whose gates refuse an in-place edit (DECISIONS.md, DA002; reviews/,
RD002).

spec close derives its moves from where the records are now, so a
re-run finishes a repoint an earlier attempt left. A repoint failure is
a warning on stderr, not a failed verb: the move stands. The results
carry `relinked` in --json and the text renders list each rewrite. The
plugin pages and the intent and capture surface chapters say so.

Refs: iss-2608311127491949
Refs: iss-2609091732329046
Refs: iss-2609250846525896

Assisted-by: Claude:claude-opus-5-5
The fix makes spec close, intent plan, capture resolve and capture
wontfix repoint every link that named the moved record, through
core/relink. Resolving iss-2609091732329046 exercised it: the resolve
repointed the one ADR line (adr-2609151513118583) that linked the
record in open/.

Resolves: iss-2608311127491949
Resolves: iss-2609091732329046
Resolves: iss-2609250846525896

Assisted-by: Claude:claude-opus-5-5
A re-run of `spec close` derives its moves from where the records are now,
and relink re-read every moved record's own links from the folder it left.
A bare link written into the closed spec after its close, such as
`[the closed index](README.md)`, therefore resolved against open/ and was
rewritten to `../open/README.md`, a different file.

relink.Move carries MovedNow: the caller made this rename in the same
operation. Only such a move re-relativises the moved file's own links;
every move still repoints other files' links to the old path, so a re-run
finishes that class of an interrupted repoint. Reconcile sets it from what
the call moved (the spec open at entry; res.IntentMoved). Plan and the
capture transition always move, so they always set it. The zero value is
the conservative reading.

The fixtures gain a link to an existing other file with a moved record's
basename and a dead one with the same basename; both stay as written, so a
basename-only matcher now fails the tests.

Refs: iss-2608311127491949
Assisted-by: Claude:claude-opus-5-5
Review 2 of the lane found the spec close warning, the RelinkError
comment and the two docs still promising that a re-run finishes the
repoint. After the MovedNow change a re-run repoints the links other
files hold and leaves the moved records' own links for links_resolve,
and that holds for an attempt that failed before the repoint as well
as during it.

Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
@REPPL
REPPL enabled auto-merge September 25, 2026 13:46
@REPPL
REPPL added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit 36b0e86 Sep 25, 2026
12 checks passed
@REPPL
REPPL deleted the fix/spec-close-repoints-links branch September 25, 2026 14:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant