fix(decision-records): carry a promotion through the whole tree - #9
Merged
Merged
Conversation
Promoting a draft changes its ID and its directory, and the tool only ever acted on the ID. Five corrections were then made by hand on every promotion; the last five in a downstream repo each needed all of them. The H1 kept the mnemonic while every accepted sibling reads `# NNNN — <title>`, so promote now rewrites it (and rename-draft-id does the same). A record moves one directory deeper, so every hand-authored relative link was left short: they are re-pathed by path math against the new location, which covers the glossary, research memos and repo-root scripts alike rather than the subset check_links happened to flag. A link labelled with its own path moves label and target together, and promote now exits non-zero if anything is still broken instead of reporting and returning 0. Only linked mnemonics were converted in referring records, leaving bare prose beside a fresh counter link in the same sentence, and the promoted record still called itself by its mnemonic. The sweep now covers bare prose in the body and in front-matter prose such as summary, plus a spelled-out path to the draft file. It stays out of fenced blocks, inline code spans and link targets, and out of everything above docs/ — a four-letter mnemonic doubles as a plausible identifier, and renaming one is not what promoting a record means. What it leaves behind is listed for a human instead. rewrite_reference wrote `supersedes: ` with a trailing space onto every record it round-tripped, dirtying tens of unrelated files that the trailing-whitespace hook then stripped back. --deref inverted the front-matter edge but read body references with a pattern blind to markdown links, so after the first `build --relink` it saw none and promoted into a breach that check caught afterwards. Both call sites now share one helper and it refuses up front. Verified by replaying five real promotions from the commit before each: the output matches the hand-corrected result byte for byte after mdformat, except one self-reference this fixes that had needed a follow-up commit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
promotechanges a draft's ID and its directory, but only ever acted on the ID. The gap was five corrections made by hand on every promotion — the five most recent ones downstream (AUTH→0035, MEET→0036, VIEW→0037, CORR→0038, TMPL→0039) each needed all of them.What the tool now does
# CONF — <title>→# 0016 — <title>, the shape every accepted record already has. Handles a backticked ID, an H1 that doesn't lead with the mnemonic (prefixes and warns), and a missing one (builds it from the front-matter title, rendering the title's own em-dash as a colon).rename-draft-iddoes the same.check_linkshappened to flag. A link labelled with its own path moves label and target together. Anchors, URLs and absolute paths are untouched.docs/. Previously only linked mnemonics converted, leaving bare prose beside a fresh counter link in the same sentence, and the promoted record still calling itselfCONF. The sweep now covers bare prose in the body and in front-matter prose such assummary, plus a spelled-out path to the draft file (docs/decisions/drafts/CONF-x.md).promoteexits non-zero if a link is still broken, rather than printing and returning 0.Two deliberate limits
A four-letter mnemonic doubles as a plausible identifier —
AUTH = "auth"in an enum,MEET = "https://…"as a scope constant,VIEW = "view"in a vendored, lint-excluded file where a bad rename is a syntax error that passes lint silently. So the sweep stays out of fenced blocks, inline code spans and link targets, and edits nothing abovedocs/. What it leaves behind is listed after the run for a human to work through.The
--derefbug--derefinverted the front-matter edge correctly but detected body references with a pattern whose lookbehind is blind to[CONF](…). Sincebuild --relinkturns every bare ref into a link, the blocking check went blind after the first build and--derefpromoted straight into a breach thatcheckreported afterwards. Both call sites now share onebody_ref_idshelper, so it refuses up front. Also fixesrewrite_referencewritingsupersedes:with a trailing space onto every record it round-trips — tens of unrelated files dirtied per promotion, which thetrailing-whitespacehook then stripped back.Verification
Replayed all five real promotions from the commit before each, ran
mdformat, and diffed against the hand-corrected commits: VIEW, CORR and TMPL are byte-for-byte identical; AUTH differs only by a factual content edit the author made by hand; MEET differs only where this is more correct — it fixes the self-reference that had needed a follow-up commit downstream.16 new tests (82 total, up from 66), covering each fix and both exclusions.
validate_skills.py, the skill's pytest suite, andpre-commit run --all-filesare clean.