chore(docs): clear the markdownlint backlog - #260
Merged
StefanSteiner merged 7 commits intoSep 6, 2026
Conversation
…wnlint Two path exclusions, dropping 33 of the 126 findings without touching a document. Both configs get the entry because markdownlint-cli2 reads only .markdownlint-cli2.jsonc and the editor extension reads only .markdownlintignore; letting them drift means the editor flags what CI-adjacent tooling ignores, or worse, the reverse. Root CHANGELOG.md (7 findings) is release-please output -- it is the sole changelog-path in release-please-config.json, so AGENTS.md forbids hand-editing it and the next release would clobber any fix anyway. Its findings are exactly that generator's shape: four MD012 double-blank-lines between release sections and three MD013 over-long generated commit lines. The exclusion is deliberately the bare path, not **/CHANGELOG.md, because the nine per-crate changelogs are hand-maintained and must stay linted. In .markdownlintignore the leading slash is what buys that, since it reads gitignore patterns where an unanchored CHANGELOG.md matches at every level; the cli2 list is globs, so it needs none. Verified with the `ignore` package the extension uses: root ignored, all nine per-crate changelogs still linted. docs/superpowers/** (26 findings) are point-in-time planning artifacts. AGENTS.md describes them as a spec and plan written before a feature and reviewed alongside the change that implements it; nothing maintains them after. The findings are dominated by prose shape rather than defects -- 13 MD013 lines of 500-1549 characters and 8 MD046 indented blocks inside a 1100-line plan -- so fixing them means a large reflow diff through settled records, which is also where the risk of mangling a code block is highest and the payoff lowest. Excluded specs alongside plans: same artifact class, and it keeps the question from being relitigated the first time a spec trips a rule. Not excluded for lack of a reader: excluded for lack of a maintainer.
Clears MD040 to zero across 20 files. 61 blocks take `text`, per the repo
convention for command output, ASCII diagrams, error messages and templates:
architecture and data-flow diagrams, source-tree listings, hyperd/CLI --help
output, stress-test result summaries, rustc error text, commit-message
templates, and the MCP tool-call transcripts in the hyperdb-mcp README,
SMOKE_TESTS and ROADMAP. Those transcripts read like a function call but match
no real grammar -- `kv_set store=smoke key=k value=v -> {...}` is neither
Python nor JS -- so `text` is the honest tag rather than borrowing a highlighter
that would mis-colour it. Two blocks got a real language: a `cargo run`
invocation in ROW_MAPPING (bash) and a table schema with an SQL comment in
BENCHMARK_GUIDE (sql).
Fixed by line number, never by pattern. A naive bulk-fixer corrupted 176 fences
here once, because tagging an opener stops it matching a bare-fence test, so the
CLOSER matches instead and becomes a spurious opener. The tagger is instead
handed opener line numbers from a CommonMark state machine and asserts, per
fence, that the line is both a bare fence and classified as an opener; anything
else aborts. The state machine independently reproduced markdownlint exactly --
68/68 MD040 line numbers and 9/9 MD046 -- before it was trusted.
Structural proof, all 69 in-scope files: block count and a SHA of every block's
content are unchanged; only info strings differ. Independently, the diff is
63 insertions and 63 deletions with every changed line a fence line, so no
content line entered or left a block. The one 3-space-indented fence kept its
indent. Nothing was added or removed, which also leaves hyperdb-mcp's
README-coupled tests intact: doctor_readme_contract keys off a line window
around exact `hyperdb-mcp doctor` lines (still at 286/287) and doctor_tests
splits on `## CLI Reference` then does substring checks, none of which a fence
info string can perturb.
…24/046) Clears every remaining non-MD013 rule: 11 MD025, 2 MD036, 2 MD024, and one each of MD001, MD041 and MD046. 93 findings down to 12. CONTRIBUTING.md had 12 H1s, one per top-level section, so every section claimed to be the document title. Demoted the 11 that are not the title to H2 and their H2 children to H3. The three H3s under "Issues, requests & ideas" deliberately stayed H3: they were the MD001 finding, an H1 -> H3 skip, and bringing their parent down to H2 makes them correctly incremented where they already are. Anchors are unaffected, which is worth stating because re-levelling is usually where anchors break: a GitHub slug derives from heading text only -- the hash count picks the h1..h6 tag, not the id. Verified rather than assumed, by running github-slugger over the file before and after: 22 anchors, identical sequence, and all six inbound links still resolve (#release-process, #commit-message-format, #contribution-checklist from AGENTS.md, hyperdb-api-node/DEVELOPMENT.md and docs/GITHUB_OPERATIONS.md; #what-contributors-do; plus intra-document #creating-a-pull-request and #commit-types-and-version-impact). No link needed updating. hyperdb-mcp/CHANGELOG.md carried "### Changed" and "### Fixed" twice under one "## [Unreleased]", the classic case of appending a second section instead of merging. Merged them and restored Keep a Changelog order (Added, Changed, Fixed), keeping each source block's internal order. That order is load-bearing here because two bullets cross-reference their own position: "supersedes the shorthand in the Added notes above" stays true since Added now sorts first, and "supersedes the older Unreleased note below" is intra-section -- both it and the note it supersedes are in the same Fixed block, untouched. Proved lossless by comparing the multiset of non-heading lines in the section: identical, with the two duplicate headings the only lines removed. BENCHMARK_GUIDE.md used a bold "**Hardware / software**" label as a heading in all four platform sections. Two were flagged; the other two escaped only because trailing italic placeholder text meant the line was not pure emphasis. Converted all four to the "#### Hardware / software" they were imitating, so the platform sections render alike. The placeholder notes became italic sentences ending in a period, matching the file's existing placeholder style -- a bare "*(placeholder)*" on its own line would have been a fresh MD036, since that rule exempts emphasis ending in punctuation and ")" does not qualify. SECURITY.md opened at H2 with no H1. Promoted it; same text, so the slug is unchanged, and nothing links to the file anyway. README.md's RHEL install snippet was indented rather than fenced -- now a bash fence. Structural proof over all 69 in-scope files: block count and per-block content SHAs unchanged. The README conversion shows as "1 indented->fenced, content identical", since the auditor hashes indented and fenced blocks alike, so the dedent is provably lossless. hyperdb-mcp/CHANGELOG.md holds no code blocks, so the section merge could not disturb one.
Takes the count to zero. All 12 were single unwrapped paragraphs or changelog bullets of 529-1104 characters, in files whose median prose line is 68-79, so each was an outlier against its own file rather than something inherently unwrappable. Wrapped at 79. No inline disable was needed anywhere, and MD013 stays enabled globally. The rule's own configuration is why the set is this small and this clean: line_length is 500 with tables and code_blocks exempt, so long table rows and code never appear, and none of the 12 lines contains a link or a bare URL -- checked before wrapping, since a break inside a link destination is exactly the corruption that MD060 was disabled over. Wrapped by a tokenizer that treats code spans as atomic, so no break can land inside one, and that indents list continuations to the bullet's content column so the text stays in its list item. Every line is asserted to round trip: stripping the continuation indent and rejoining with single spaces has to reproduce the original line exactly, or the wrap aborts. Verified again independently afterwards, whole-file this time -- whitespace-normalized text is identical to the previous commit for all five files, so no word, code span or punctuation mark moved. hyperdb-mcp/README.md is the one file whose tests key off line positions, and the wrap shifted them by seven. Re-checked by re-implementing doctor_readme_contract's window logic against the edited file: the exact `hyperdb-mcp doctor` and `doctor --json` lines are still found, and the -12/+21 window around them still contains the "side-effect-free" and "does not start" phrases the test requires. The doctor_tests `## CLI Reference` extraction and its four substring checks also still pass, as does the `daemon ` foreground line. Static simulation, not an executed cargo run -- this is a docs-only change and no test was run.
Replaces the blanket docs/superpowers/** exclusion from 0b442c5 with a directory-scoped relaxation of the two rules that would force a reflow. The argument against excluding won: that tree is not a static archive. AGENTS.md mandates a spec and plan for every non-trivial feature, so new files land there regularly, and an exclusion leaves the editor silent exactly while one is being authored. The rules worth having then -- untagged fences, heading structure -- are precisely the ones an exclusion would suppress. A relaxation keeps them and drops only MD013 (plan prose runs past 1500 characters per line) and MD046 (plans mix indented and fenced blocks), which are the two that would demand rewriting a settled record. The root CHANGELOG.md exclusion is untouched; that one is generated, which is a different argument entirely. The mechanism is a nested docs/superpowers/.markdownlint.json, so one file governs both tools: markdownlint-cli2 resolves configuration per directory, and the extension's documented precedence is a ".markdownlint.{jsonc,json,...} file in the same or parent directory", so it walks up from whatever file is open. Confirmed both rather than assumed. The CLI now lints 68 files instead of 56, reports 0 issues, and the 1_88_uplift subdirectory two levels below the config went from 8 baseline findings to 0, which shows the config governs recursively and not just its own directory. The extension side is documented behaviour plus its own guidance that a CLI-first setup needs no further change to behave the same in the editor. .markdownlintignore loses its docs/superpowers/ entry, and the `ignore` package the extension uses agrees: the tree is linted at every depth, root CHANGELOG.md still ignored, all nine per-crate changelogs still in scope. The "extends" line is load-bearing and nearly went in as decoration. A nested config REPLACES ancestor configuration rather than merging with it -- measured, after a first attempt to measure it drew the opposite conclusion off a bad probe (a no-spaces long line, which MD013 never flags in its default non-strict mode). Dropping just the extends from this file takes the repo from 5 findings to 92: 70 MD060 and 17 MD010. MD060 is the rule this project disabled because a formatter satisfying it stripped the README's badge links, so a naive nested config would have quietly reintroduced it across the plan files. Extending the root config inherits all of it and overrides only the two rules named above.
Takes the repo to zero findings with docs/superpowers now linted. These are the 5 that 5185ad7 left behind because the tree was excluded at the time. Two blocks in the kv-store-m2 plan take `markdown`: both are Markdown intended to be pasted elsewhere -- a "### Key-value store (scratchpad)" section destined for readme.rs, and two changelog bullets for hyperdb-mcp's Unreleased section. The three in the LLM-ergonomics plan take `text`: each is a prose fragment to be appended to a #[tool(description = ...)] string, and two of them open with a deliberate leading space for that concatenation, which is preserved untouched since only the fence line is rewritten. Same tagger and same proof as 5185ad7, which matters more here than anywhere else: these are the longest files in the repo and the ones nobody re-reads, so a cascade would sit undetected. Checked first that no target block contains a fence line of its own -- the markdown block was the real risk, since a snippet documenting Markdown is how nesting shows up -- and the tagger still asserts per fence that the line is both a bare fence and classified as an opener by the state machine. Structural proof over all 69 files, against the branch base: 554 code blocks before and 554 after, every block's content SHA identical, no unclosed fence. Untagged fenced blocks are now 0 repo-wide, down from 68 at baseline. Independently, the diff is 5 insertions and 5 deletions with every changed line a fence line, so no content line entered or left a block.
…merges Adds a fourth trap to the markdownlint reminder. It belongs with the other three for the reason the section exists: markdownlint is not a CI gate, so a headless agent gets no feedback at all, and an agent adding a nested config elsewhere in the repo would have no reason to open docs/superpowers/.markdownlint.json and discover this. The full rationale stays in that file's comments; the reminder just names the trap and the fix. The failure mode is what makes it worth a bullet. Omitting `extends` does not make the document wrong, it makes the linter wrong -- it reports fewer or different findings while looking like it works, and here it would silently re-enable MD060, the one rule this repo has already been burned by when a formatter satisfying it stripped the README's badge links. Placed last so it sits directly above the paragraph explaining why MD060 is disabled. Mirrored the neighbouring bullets exactly rather than trusting the rendered view, which normalizes whitespace: on this list the `-` marker sits at column 0 and continuations at one space, so the bullets are a sibling top-level list rather than nested under item 3. Indenting a new bullet even one space makes it a badly-indented nested list and trips MD007, which has happened here before. Verified on both engines -- `markdownlint-cli2` latest and the 0.23.2 the installed extension (DavidAnson.vscode-markdownlint 0.62.1) declares -- 68 files, 0 issues, exit 0 on each. Latest currently resolves to 0.23.2, so there is no version skew between editor and CLI at all right now.
StefanSteiner
force-pushed
the
chore/markdownlint-backlog
branch
from
September 6, 2026 07:09
b339b31 to
a388db8
Compare
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.
No issue — this clears accumulated lint debt.
Takes the repo from 126 markdownlint findings to 0:
What is excluded, and why
The root
CHANGELOG.mdis excluded rather than fixed: it is release-please-generated, so hand edits get clobbered on the next release.docs/superpowers/**Gets a nested
.markdownlint.jsonthat disables only MD013 and MD046. Specs and plans still get fence and heading feedback, while settled prose isn't reflowed.extendsis load-bearing there, because a nested config replaces ancestor configuration rather than merging into it. Omittingextendstakes the repo from 5 findings to 92, including 70 MD060 — the rule this project deliberately disabled after a Markdown formatter stripped the README's badge links.AGENTS.mdgains a fourth trap in its markdownlint reminder recording that replace-not-merge behaviour, so the next person doesn't have to rediscover it.Verification
0 issues in 0 filesacross 68 linted files.Rebase note
This branch was based on
fix/watchdog-flake-and-mb-units, which has since merged as #256. It has been rebased ontomain, and the diff is now its own seven commits only — the two commits inherited from #256 are gone. The rebase was clean, and the replayed content is byte-identical to the pre-rebase diff (only hunk offsets moved).Review status
Important
This branch has not had adversarial code review either, unlike #257 and #258 — though it carries unusually strong self-verification, as above.