Skip to content

Add markdownlint CI job and fix broken doc links#123

Merged
sir-sigurd merged 15 commits into
mainfrom
add-markdownlint-ci
Jun 10, 2026
Merged

Add markdownlint CI job and fix broken doc links#123
sir-sigurd merged 15 commits into
mainfrom
add-markdownlint-ci

Conversation

@sir-sigurd

@sir-sigurd sir-sigurd commented Jun 9, 2026

Copy link
Copy Markdown
Member

Description

Adds a markdownlint job to CI that lints all Markdown docs with markdownlint-cli2, and fixes the existing violations to establish a green baseline.

CI + config

  • New markdownlint job in ci.yml: npm ci against a committed package.json + package-lock.json (markdownlint-cli2 0.22.1), then npx --no-install markdownlint-cli2, on the runner's preinstalled Node. Runs on PRs and pushes to main. (The lockfile freezes the whole dependency tree and makes the pin visible to update tooling — a moving action tag would auto-adopt new releases that can add/tighten rules and break CI with no repo change, and a bare npx <pkg>@<version> would still resolve transitive deps fresh on every run.)
  • Rules and scope live in .markdownlint-cli2.yaml so local markdownlint-cli2 runs match CI:
    • Disabled MD013 (line-length), MD036 (bold-as-heading), MD060 (table-column-style) — stylistic and noisy on these docs.
    • MD024 set to siblings_only — the CHANGELOG repeats Added/Changed/Fixed per release (Keep a Changelog convention).
    • globs: **/*.{md,markdown} (recursive) — every Markdown file in the repo, so future nested docs (module READMEs, etc.) are covered automatically. Both local and CI runs invoke the tool with no glob args, so the config is the single source of truth. The PR template's lone MD041 (no H1, it's a fragment) is skipped file-wide in that file.
    • ignores for .terraform/ and node_modules/ — markdownlint-cli2 has no default exclusions, and a local terraform init vendors registry modules whose READMEs would otherwise fail local runs.

Doc fixes for a green baseline

  • README: demoted three stray H1s to H2 with their subsections bumped one level (anchors are text-derived, so internal links still resolve), added languages to bare code fences, normalized list markers (*-), and dropped a double space in one demoted heading.
  • OPERATIONS: fixed cross-reference anchors that didn't match their target headings — mostly a missing (N minutes) suffix; the cost-review link is repointed to #cost-optimization-recommendations.
  • README, VARIABLES, CHANGELOG: normalized blank lines around headings, fences, and lists (the CHANGELOG change is a single pre-existing blank-line fix; no release note added).

Deferred

  • README table of contents (last half of TOC references in readme are broken #95): the last half of the TOC links point to sections that don't exist in the README. Two entries (Troubleshooting, Terraform Commands Reference) had unambiguous in-README targets and were retargeted; the remaining five need cross-doc decisions, so they are kept verbatim and suppressed with per-line markdownlint-disable-next-line comments + a TODO referencing last half of TOC references in readme are broken #95. Deciding which sections belong (and the cross-doc links) is left to a focused follow-up PR tracked by last half of TOC references in readme are broken #95. The suppression comments are indented under the preceding list item so the rendered lists stay whole.
  • OPERATIONS checklist links (#capacity-monitoring, #security-audit): point to sections that don't exist yet. Left in place with an inline markdownlint-disable and a TODO, rather than repointed to an unrelated section — a follow-up should add those sections or drop the links.

TODO

  • No CHANGELOG entry — CI/docs-tooling change does not warrant a release note

🤖 Generated with Claude Code

Greptile Summary

This PR adds a markdownlint CI job using version-pinned npx markdownlint-cli2@0.22.1 and fixes all existing violations across the docs to establish a green baseline.

  • CI + config: New markdownlint job in ci.yml driven entirely by .markdownlint-cli2.yaml, which disables noisy stylistic rules (line-length, bold-as-heading, table-column-style), relaxes duplicate-heading to siblings_only for Keep-a-Changelog convention, and recursively globs all *.{md,markdown} files.
  • Doc fixes: OPERATIONS anchor links updated to include parenthetical time suffixes that match actual heading text; README H1s demoted to H2 and bare code fences language-tagged; blank lines normalized across README, VARIABLES, and CHANGELOG.
  • Deferred dead links: Two OPERATIONS checklist links and several README TOC entries pointing to non-existent sections are suppressed with markdownlint-disable + TODO(#95) rather than restructured here.

Confidence Score: 5/5

Safe to merge — adds a docs linting job and normalises existing Markdown without touching any Terraform or infrastructure logic.

All changes are confined to documentation, CI config, and the new markdownlint config file. The linter version is pinned so the job is reproducible, the config is the single source of truth for both local and CI runs, and the anchor fixes in OPERATIONS.md have been verified against the actual heading text. Dead links are properly suppressed with TODO markers rather than silently ignored.

No files require special attention.

Important Files Changed

Filename Overview
.github/workflows/ci.yml Adds a version-pinned npx markdownlint-cli2@0.22.1 job; no glob args so the config file is the single source of truth; consistent with the existing job structure.
.markdownlint-cli2.yaml New config file disabling MD013/MD036/table-column-style and relaxing MD024 to siblings_only; globs covers all .md/.markdown files recursively.
OPERATIONS.md Anchor links updated to include parenthetical time suffixes matching actual headings; two dead links left intentionally with markdownlint-disable and TODO(#95) markers.
README.md Three stray H1s demoted to H2 with subsections bumped one level; bare code fences language-tagged; blank lines normalized; dead TOC links wrapped in markdownlint-disable with TODO(#95).
CHANGELOG.md Single blank-line fix before a list; no functional content changes.
VARIABLES.md Blank lines added around headings and code fences to satisfy MD022/MD031; no content changes.
.github/pull_request_template.md File-wide markdownlint-disable-file first-line-heading directive added because the template intentionally starts with an H2 fragment rather than an H1.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    trigger["PR / push to main"] --> fmt & markdownlint & validate & test

    fmt["fmt job\nactions/checkout@v6\nhashicorp/setup-terraform@v4\nterraform fmt -check -recursive -diff"]

    markdownlint["markdownlint job\nactions/checkout@v6\nnpx markdownlint-cli2@0.22.1"]
    markdownlint --> config[".markdownlint-cli2.yaml\n• globs: **/*.{md,markdown}\n• MD013 off\n• MD036 off\n• table-column-style off\n• MD024 siblings_only"]

    validate["validate job (matrix)\nterraform validate\n5 modules"]

    test["test job (matrix)\nterraform test\n2 modules"]
Loading

Reviews (2): Last reviewed commit: "Lint Markdown via pinned npx instead of ..." | Re-trigger Greptile

Add a markdownlint job to CI that lints the top-level Markdown docs with
markdownlint-cli2, configured via .markdownlint-cli2.yaml. The config
disables noisy/stylistic rules (line-length, bold-as-heading,
table-pipe-spacing), sets MD024 to siblings-only for the CHANGELOG, and
globs *.{md,markdown} (non-recursive) so spec/ working notes and .github/
are excluded.

Fix the existing violations to establish a green baseline:
- README: repair the stale table of contents (drop entries with no
  in-doc target, add the real sections), demote stray H1s to H2 with
  subsections bumped one level, add languages to bare code fences.
- OPERATIONS: fix cross-reference anchors that omitted the heading's
  "(N minutes)" suffix.
- Normalize blank lines around headings, fences, and lists.

Two OPERATIONS checklist links (#capacity-monitoring, #security-audit)
point to sections that do not exist yet; they are left in place with an
inline markdownlint-disable and a TODO referencing the issue.

Fixes #95

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread CHANGELOG.md Outdated
sir-sigurd and others added 5 commits June 9, 2026 22:11
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reference rules by their readable names (line-length, no-emphasis-as-heading,
table-column-style, no-duplicate-heading) instead of MD0xx IDs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A CI/docs-tooling change does not warrant a release note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reference link-fragments instead of MD051 in the markdownlint-disable
comments, matching the config style.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pre-existing MD032 violation surfaced by the new markdownlint baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sir-sigurd

Copy link
Copy Markdown
Member Author

@greptileai the [#PR] placeholder finding is resolved — rather than fill in the number, I dropped the CHANGELOG entry entirely, since a CI/docs-tooling change doesn't warrant a release note. The CHANGELOG now only carries a one-line blank-spacing fix (pre-existing MD032 surfaced by the new lint baseline).

Also switched the markdownlint config and inline disable directives to rule-name aliases (line-length, link-fragments, etc.) instead of MD0xx IDs for readability.

@greptile-apps

greptile-apps Bot commented Jun 9, 2026

Copy link
Copy Markdown

Both resolutions make sense. Dropping the CHANGELOG entry is the right call for a tooling-only change, and using rule-name aliases (line-length, link-fragments, etc.) makes the config and inline disables much more readable than the numeric IDs. No further concerns on this thread.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@sir-sigurd sir-sigurd left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the markdownlint CI job and the doc fixes — no blockers. The CI job and config are correct: the rule aliases all resolve in the markdownlint version the action bundles (v23 → markdownlint 0.40), siblings_only is the right parameter for MD024, and the config's non-recursive glob is honored by the action rather than overridden, so a local markdownlint-cli2 run and CI lint the same files. The OPERATIONS anchor fixes and the README table-of-contents repair all resolve to real headings, and the H1→H2 demotions keep the text-derived slugs, so existing internal links still work.

Greptile's [#PR] placeholder flag is already resolved — the changelog entry was dropped in a later commit, so there's no broken link to ship.

Design: limited substantive surface — a CI lint job plus mechanical doc fixes, with one coherent goal (a green lint baseline). Everything below is optional polish and PR-description tidy-ups.

Nits / optional

  • (reshape) Lint scope is top-level-only as a side effect, not by intent. The config comment frames the non-recursive *.{md,markdown} glob as deliberately excluding spec/, but it equally (and silently) excludes any nested markdown — modules/*/README.md, examples/*.md. None exist today so nothing is missed now, but the next contributor who adds a module README gets no linting and no signal.
    Alternatives: would globs: ["**/*.md"] with an explicit ignores: ["spec/**", ".github/**"] match the stated intent better and auto-cover future files?
  • (reshape) Config comment mislabels the disabled table rule. table-column-style is MD060 (column-style/padding consistency); the comment calls it "Table pipe spacing," which is MD055 (table-pipe-style), a different rule. The disabled rule is the right one — only the comment (and the PR body) name the wrong one.

PR description tidy-ups

  • The doc-edits list names README and OPERATIONS, but VARIABLES.md (and a one-line CHANGELOG blank-line fix) also changed. Same goal — just an incomplete file inventory.
  • The TODO still shows [x] CHANGELOG entry, but the entry was dropped and the shipping diff carries no release note. The recent CI/test PRs (#114, #116) carried no changelog entry either, so skipping it is consistent — uncheck the box so the description matches what shipped.

The two deferred OPERATIONS links (#capacity-monitoring, #security-audit) are suppressed with a TODO referencing #95 rather than re-pointed to an unrelated section — fine to leave to that follow-up.

Reviewed against 597c87b

table-column-style (MD060) governs table cell padding consistency; the
previous comment described it as "table pipe spacing," which is MD055.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sir-sigurd

Copy link
Copy Markdown
Member Author

Thanks for the review. Addressed:

  • MD060 comment mislabel — fixed in eba32f4: table-column-style (MD060) is cell-padding consistency, not "table pipe spacing" (MD055). Corrected the PR-body label too.
  • PR description inventory — now names VARIABLES.md and the one-line CHANGELOG blank-line fix; TODO already reflects that no release note shipped.

Deferred / planned:

  • Lint scope (nit: top-level-only is a side effect) — agreed, and this is the "lint everything" expansion we're holding for. Once Remove PR #88 review scratch docs #122 removes spec/, I'll switch the glob to recursive (**/*.{md,markdown}), which auto-covers future modules/*/README.md / examples/*.md and directly fixes the "next contributor gets no linting" gap. The PR template's lone MD041 will be skipped inline in that file.
  • Deferred OPERATIONS links (#capacity-monitoring, #security-audit) — leaving to the last half of TOC references in readme are broken #95 follow-up as noted.

Holding this PR until #122 lands, then I'll do the recursive switch in one more commit.

sir-sigurd and others added 5 commits June 9, 2026 22:51
Restore the original table-of-contents entries verbatim and suppress the
broken in-doc anchors with a markdownlint-disable block plus a TODO
referencing #95, rather than deciding the TOC restructure here. The
navigation/content decision (which sections belong, cross-doc links)
belongs in a focused PR; this one stays scoped to the lint baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With spec/ removed (#122), there's no working-notes directory left to
avoid, so widen the glob from top-level *.{md,markdown} to recursive
**/*.{md,markdown} in both the config and the CI action (the action's
default glob is non-recursive and overrides the config, so it's set
explicitly). This auto-covers future nested docs like module READMEs.

The only newly-linted file, .github/pull_request_template.md, opens with
a section heading rather than an H1; skip first-line-heading inline since
it's a template fragment, not a standalone document.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MD041 is about the file's first line, so the exemption belongs to the
whole file, not one line. disable-line was positional and would silently
stop working if the template gained a line above the heading.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace DavidAnson/markdownlint-cli2-action@v23 with a pinned
`npx markdownlint-cli2@0.22.1` run.

A moving major action tag auto-adopts new releases that can add or
tighten rules and break CI with no repo change; a pinned npm version is
content-immutable, so the linter is reproducible. It also matches the
local invocation, and lets the config's globs drive file selection
without duplicating them in the workflow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sir-sigurd sir-sigurd requested a review from Copilot June 9, 2026 18:06
@sir-sigurd

Copy link
Copy Markdown
Member Author

@greptileai please re-review — the CI mechanism changed substantially since the last pass: the markdownlint job now runs a version-pinned npx markdownlint-cli2@0.22.1 instead of markdownlint-cli2-action@v23 (reproducibility — a moving action tag can adopt new rules and break CI silently), lints recursively (**/*.{md,markdown}) now that #122 removed spec/, and the README TOC / OPERATIONS dead links are suppressed with TODO(#95) rather than restructured here.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds repository-wide Markdown linting in CI (via markdownlint-cli2) and updates existing documentation files to conform to the lint rules, establishing a clean baseline for future doc changes.

Changes:

  • Added a markdownlint GitHub Actions job and a repo-level .markdownlint-cli2.yaml to centrally define rules and lint scope.
  • Normalized/cleaned up Markdown formatting across key docs (blank lines, heading levels, code fence languages) and fixed/annotated link fragments.
  • Updated the PR template to opt out of the “first line must be a heading” rule.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
.github/workflows/ci.yml Adds markdownlint job running npx markdownlint-cli2@0.22.1 in CI.
.markdownlint-cli2.yaml Introduces markdownlint-cli2 configuration (rule toggles + repo-wide Markdown globs).
.github/pull_request_template.md Disables first-line-heading lint rule for the PR template.
README.md Markdown normalization, adds fenced-code languages, and suppresses known-broken TOC fragments with TODO notes.
OPERATIONS.md Fixes anchor fragments to match headings; suppresses known-missing sections with TODO notes.
VARIABLES.md Adds blank lines to satisfy linting around headings/lists/fences.
CHANGELOG.md Minor formatting normalization (blank line for list separation).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

sir-sigurd and others added 3 commits June 9, 2026 23:42
- Retarget Troubleshooting and Terraform Commands Reference to the real
  sections; only the five entries needing cross-doc decisions (#95) stay.
- Switch the README disable block to per-line disables so a TOC entry
  added later still gets dead-anchor checking.
- Reword the TODO: #95 tracks the broken links themselves, not a
  restructure.
- Indent the suppression comments under the preceding list item so the
  TOC and checklists render as single lists (an unindented HTML comment
  between bullets splits the list).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Move the markdownlint-cli2 pin into package.json + package-lock.json
  and run `npm ci` in CI: a bare `npx <pkg>@<version>` still resolves
  deep transitive deps fresh on every run, while the lockfile freezes
  the whole tree and makes the pin visible to update tooling.
- Add `ignores` for .terraform/ and node_modules/: markdownlint-cli2
  has no default exclusions, and `terraform init` vendors registry
  modules whose READMEs would fail local runs.
- Ignore node_modules in .gitignore.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sir-sigurd sir-sigurd merged commit a4392c4 into main Jun 10, 2026
9 checks passed
@sir-sigurd sir-sigurd deleted the add-markdownlint-ci branch June 10, 2026 03:37
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.

2 participants