Skip to content

fix(ci): make the markdownlint job lint files again (#4526) - #4584

Open
SurefireStudios wants to merge 3 commits into
github:mainfrom
SurefireStudios:fix/4526-markdownlint-glob
Open

SurefireStudios wants to merge 3 commits into
github:mainfrom
SurefireStudios:fix/4526-markdownlint-glob

Conversation

@SurefireStudios

@SurefireStudios SurefireStudios commented Sep 14, 2026

Copy link
Copy Markdown

Description

Fixes #4526.

.github/workflows/lint.yml passed globs: '**/*.md' !extensions/**/*.md with the quotes inside the YAML block scalar, so markdownlint-cli2 received them as literal characters and matched nothing.

The Lint run on main logs Finding: '**/*.md' ... then Linting: 0 files — the job has been green because it lints nothing.

Scope

Per @mnriem's review, the globs are now an explicit documentation allowlist rather than everything in the repository.

Commands, skills, prompt templates, AGENTS.md and .github/ content stay out: they are inputs to coding agents rather than prose, and markdownlint's fixes rewrite their syntax.

That matters concretely — an unattended --fix pass turned __init__.py into **init**.py and __SPECKIT_COMMAND_*__ into **SPECKIT_COMMAND***_, because markdownlint reads __ as bold where we mean an identifier.

The allowlist lives in a job-level DOC_GLOBS variable and covers docs/**, the root project docs, and the top-level docs under integrations/, presets/ and workflows/57 files.

The formatting edits outside that set are reverted, taking this from 33 changed files to 16: the workflow plus the documentation corrections the allowlist actually covers.

The regression guard

A glob matching nothing makes markdownlint-cli2 exit 0, so the job passes having checked no files — which is the whole of #4526.

A guard step expands DOC_GLOBS and fails if any glob matches nothing, naming it.

It checks each glob rather than the total, because one stale entry among several still leaves that part of the documentation unlinted.

One suppression

docs/index.md pillar headings stay at h3 with an MD001 disable, because docs/template/public/main.css styles .pillar-card h3 including the per-card accent colours, so promoting them would break the landing page.

Note

@prateekraawat1 commented "take" on the duplicate #4527; I had already built this before noticing, so happy to close in their favour.

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable)

Validated with markdownlint-cli2 0.23.2, the version the pinned action bundles — I had first checked against 0.18.1, which would have passed locally and failed in CI.

The allowlist reports Linting: 57 files / Summary: 0 issues, and the guard independently counts the same 57.

Reverting the documentation corrections reproduces 24 issues across the 9 files they touch, so every retained edit is load-bearing rather than churn.

Guard behaviour, checked directly: the real list passes at 57; '**/*.md' — the original #4526 glob — reports 0 and fails; and a list with one stale entry among several still matches 40 files but fails and names the stale glob.

specify --help and the sample-project path aren't exercised, because this changes markdown content and one workflow file, and touches no CLI code.

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

Per CONTRIBUTING and AGENTS.md: made with AI assistance (Claude), working from my direction. Every claim above was verified by running the command named rather than asserted — including the token-level diff that caught the __init__.py rewrite, and the guard's failure cases.

The globs were written inside a YAML block scalar, so the quotes around
`'**/*.md'` were passed through to markdownlint-cli2 verbatim. It looked
for paths beginning with a literal quote, matched nothing, and exited 0.
The job has reported success without reading a file since it was added.

Unquoting the glob alone turns the job red: it then finds 116 files with
277 violations. So this also clears every one of them.

Most were mechanical (blank lines around fences, lists and headings) and
came from markdownlint's own --fix. Three groups needed judgment:

- Identifiers that markdown reads as emphasis. `__init__.py`,
  `__SPECKIT_COMMAND_*__` and friends were being rendered as bold in
  CHANGELOG.md. Running --fix over them rewrites the text itself
  (`**init**.py`), so they are wrapped in code spans instead, matching how
  the same tokens are already written elsewhere in the repo.
- Fenced blocks without a language. Tagged from their actual content:
  `markdown` for the blocks that are markdown output, `text` for
  directory trees, commit messages and log excerpts.
- The pillar headings on the docs landing page. They must stay at h3
  because main.css styles `.pillar-card h3`, so MD001 is suppressed there
  with a comment saying why. It is the only suppression added.

No prose changed. Verified against markdownlint-cli2 0.23.2, the version
the pinned action actually runs.

Assisted-by: Claude (model: claude-opus-5, autonomous)
Copilot AI balanced review requested due to automatic review settings September 14, 2026 18:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@mnriem mnriem added the triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review label Sep 15, 2026
@mnriem
mnriem requested a balanced review from Copilot September 15, 2026 22:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The workflow fix lacks a regression test preventing the silent zero-match glob from returning.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 32/33 changed files
  • Comments generated: 1
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

Comment thread .github/workflows/lint.yml Outdated
with:
globs: |
'**/*.md'
**/*.md
@mnriem

mnriem commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

Thanks for identifying and investigating the zero-file lint problem. The fix needs a narrower scope: Markdown linting is intended for documentation only, not every Markdown file in the repository.

Commands, skills, prompt templates, agent instructions such as AGENTS.md, and .github/ content must remain outside the lint/formatting target set. These files should not be reformatted as part of documentation cleanup, even when the wording appears unchanged.

Please rescope the lint configuration to an explicit documentation-only allowlist and remove the formatting edits outside that scope. Retain only the documentation corrections needed for those targets, then verify that the job checks the intended files.

Drafted for @mnriem with assistance from GitHub Copilot (model: GPT-6 Astra; interactive comment drafting).

@mnriem mnriem added author-needs-rescope Sprawling or batched diff — split into one focused, single-concern PR author-awaiting Waiting on author response labels Sep 15, 2026
Addresses review feedback: markdown linting is for documentation, so
commands, skills, prompt templates, agent instructions (AGENTS.md) and
.github/ content must stay outside the lint target set.

The globs input is now an explicit documentation allowlist held in a
job-level DOC_GLOBS variable: docs/**, the root project docs, and the
top-level docs under integrations/, presets/ and workflows/. It matches
57 files. The formatting edits made outside that scope in the first pass
are reverted, taking this from 33 changed files to 16 -- the workflow
plus the documentation corrections the allowlist actually covers.

Adds a guard step that expands the same DOC_GLOBS and fails when it
matches nothing. That is the regression test for github#4526: the original
'**/*.md' was quoted inside a YAML block scalar, so the quotes became
part of the pattern, it matched zero files, and the job passed while
linting nothing. Verified the guard reports 57 for the allowlist and 0
(job fails) for the original quoted glob.

Also merges main and resolves the docs/index.md conflict in favour of
main's rewritten hero paragraph; the MD049 fix this branch made there no
longer applies to that text.
Copilot AI review requested due to automatic review settings September 15, 2026 23:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@SurefireStudios

Copy link
Copy Markdown
Author

Thanks — rescoped as asked. The branch now carries the workflow fix plus documentation corrections only, down from 33 changed files to 16 (+111/−61).

Explicit documentation-only allowlist. The globs input is now a job-level DOC_GLOBS list rather than **/*.md:

docs/**/*.md
README.md  README.zh-CN.md  CHANGELOG.md  CODE_OF_CONDUCT.md
CONTRIBUTING.md  DEVELOPMENT.md  SECURITY.md  SUPPORT.md  spec-driven.md
integrations/*.md
presets/*.md
workflows/*.md

That matches 57 files, 0 errors. Everything you named is outside it: AGENTS.md, all of .github/ (skills and workflow docs included), templates/** (commands and prompt templates), and the */commands/ and */templates/ trees under presets/. The single-level presets/*.md and workflows/*.md patterns pick up the area docs without reaching preset content.

Formatting edits outside that scope are reverted. All 17 out-of-scope files are byte-identical to main again — verified per file, not just by eye. For scale, those excluded paths currently hold 94 files with 190 markdownlint findings; linting them is exactly the reformatting you did not want, and that number is a good argument for the allowlist staying narrow.

Verifying the job checks the intended files. Added a guard step that expands the same DOC_GLOBS and fails the job when it matches nothing:

documentation files matched: 57      # allowlist
documentation files matched: 0       # original '**/*.md' -> job now fails

This is the regression test for the underlying bug and for the point the Copilot reviewer raised. The root cause was that '**/*.md' sat quoted inside a YAML block scalar, so the quote characters became part of the pattern, it matched zero files, and the job passed while linting nothing. A silent zero-match can no longer pass.

Also merged main — the PR was conflicted. The conflict was in docs/index.md, where main rewrote the hero paragraph; I took main's version, since the MD049 _what_*what* fix this branch made no longer applies to that text.

One judgement call worth confirming: nested preset READMEs (presets/lean/README.md, presets/scaffold/README.md, presets/constitution-sync/README.md) are currently out of scope, on the reading that anything inside a preset directory is preset content rather than documentation. Happy to pull them in if you would rather they were linted.

The check summed matches across every glob and only failed at zero, so one
stale entry among several still passed while leaving that part of the
documentation unlinted -- the same silent narrowing as github#4526, just partial.

Each glob is now checked on its own and every empty one is reported.

The unmatched globs are collected in an array rather than a string: nullglob
is on for this step, so re-expanding an unquoted list of globs that match
nothing erases the list before it can be printed.
Copilot AI review requested due to automatic review settings September 16, 2026 20:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@SurefireStudios

Copy link
Copy Markdown
Author

One more push: the glob check now fails per glob instead of on the total.

As written it summed matches across every glob and only failed at zero, so one stale entry among several would still pass while leaving that part of the docs unlinted — the same silent narrowing as #4526, just partial. A list with a typo'd presetz/*.md still matched 40 files and went green; it now fails and names the glob.

(It collects the unmatched globs in an array rather than a string, because nullglob is on for that step and re-expanding an unquoted list of globs that match nothing erases it before it can be printed — which is exactly what happened the first time I wrote it.)

Body updated to match the rescoped branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author-awaiting Waiting on author response author-needs-rescope Sprawling or batched diff — split into one focused, single-concern PR triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: markdownlint CI job lints 0 files — glob quoting makes lint.yml a no-op

3 participants