From 83fe4c3799c74688ab1ac2d42959d4003aae804e Mon Sep 17 00:00:00 2001 From: Bryan Fawcett Date: Sat, 12 Sep 2026 02:51:16 +0800 Subject: [PATCH 1/3] fix(lint): exempt generated lockfiles from yamllint, add merge_group to the caller Two defects found by rolling this gate out across seven orgs. Both are the same shape as the JSONC one: the check was wrong, not the repo. yamllint was reading pnpm-lock.yaml. The canonical .yamllint.yaml ignored only node_modules/, so the 140-char line-length rule fired on generated lockfiles - zti-app's pnpm-lock.yaml:5210 is an npm deprecation notice pnpm copied verbatim from the registry. No developer wrote it, and it cannot be rewrapped without invalidating the lockfile. .prettierignore has exempted lockfiles all along under "Lockfiles, generated output"; yamllint not doing the same was an oversight that stayed hidden only because this repo has no lockfile. Every pnpm repo in the estate would have hit it, and the only local fixes available were editing a generated file or diverging from the canonical config - which is how the drift starts. The caller now includes merge_group. A repo whose ruleset uses a merge queue needs required checks to report on the gh-readonly-queue/** ref, and only merge_group produces that; without it a queued PR stalls for the full check_response_timeout and nothing can ever land. nhimbe needed exactly this and had to deviate from the canonical caller by one line to land at all. The point of this file is that no repo has to do that, so the trigger belongs here. It is harmless where there is no queue. ADOPTING-LINT.md now records both, plus why pull_request must NOT carry a branches: filter - that filter matches the PR's BASE branch, so adding one silently stops the gate emitting in shamwari-core, shamwari-gateway, shamwari-web (default branch `scaffold`) and siafudb-kuzu (`master`). Co-Authored-By: Claude Opus 5 (1M context) --- .yamllint.yaml | 12 ++++++++++++ ADOPTING-LINT.md | 15 +++++++++++++++ workflow-templates/lint.yml | 6 ++++++ 3 files changed, 33 insertions(+) diff --git a/.yamllint.yaml b/.yamllint.yaml index a280c3e..dc117fc 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -11,6 +11,18 @@ extends: default ignore: | node_modules/ + # Lockfiles are generated, not authored. .prettierignore already + # exempts them under "Lockfiles, generated output"; yamllint not doing + # the same was an oversight that only stayed hidden because this repo + # has no lockfile. pnpm writes registry deprecation notices verbatim + # into pnpm-lock.yaml, which routinely exceeds the 140-char limit and + # cannot be rewrapped without invalidating the lockfile. + pnpm-lock.yaml + package-lock.json + yarn.lock + **/pnpm-lock.yaml + **/package-lock.json + **/yarn.lock rules: # 140-char limit. Workflow files have legitimately long shell URLs diff --git a/ADOPTING-LINT.md b/ADOPTING-LINT.md index e636c0b..5eb5c88 100644 --- a/ADOPTING-LINT.md +++ b/ADOPTING-LINT.md @@ -31,6 +31,7 @@ on: pull_request: push: branches: [main] + merge_group: workflow_dispatch: concurrency: @@ -45,6 +46,20 @@ jobs: uses: nyuchi/.github/.github/workflows/reusable-lint.yml@main ``` +Two things in that trigger list are load-bearing and must not be edited +per repo: + +- **`pull_request:` carries no `branches:` filter.** That filter matches + the PR's _base_ branch, so adding one silently stops the gate emitting + in any repo whose default branch is not `main` - `shamwari-core`, + `shamwari-gateway`, `shamwari-web` (`scaffold`) and `siafudb-kuzu` + (`master`). +- **`merge_group:`** is what makes the gate work in a repo whose ruleset + uses a merge queue. Required checks must report on the + `gh-readonly-queue/**` ref and only `merge_group` produces that; + without it a queued PR stalls for the full `check_response_timeout` + and nothing can land. Harmless where there is no queue. + It is also offered in the GitHub UI under **Actions -> New workflow -> Org lint gate**, from `workflow-templates/lint.yml`. diff --git a/workflow-templates/lint.yml b/workflow-templates/lint.yml index f766bb6..6292f77 100644 --- a/workflow-templates/lint.yml +++ b/workflow-templates/lint.yml @@ -24,6 +24,12 @@ on: pull_request: push: branches: [main] + # Required for repos whose ruleset uses a MERGE QUEUE: required checks + # must report on the gh-readonly-queue/** ref, and only merge_group + # produces that. Without it a queued PR stalls for the full + # check_response_timeout and nothing can ever land. Harmless where + # there is no queue, so it stays in the one identical caller. + merge_group: workflow_dispatch: concurrency: From 90ff8ebdc0f57c4b34115426e9601f18b437c274 Mon Sep 17 00:00:00 2001 From: Bryan Fawcett Date: Sat, 12 Sep 2026 02:53:30 +0800 Subject: [PATCH 2/3] docs(adopting-lint): record the two traps that bite during adoption prettier 3.9.4's mdx parser rewrites a multi-line {/* ... */} comment into {/_ ... _/} - it reads the * as markdown emphasis and emits invalid MDX, so `prettier --write` actively breaks the file. The check is right and the formatter has the bug, so the gate is unchanged; what is needed is that the next person mid-adoption, reaching for --write, knows to diff the result. And markdownlint-cli2 --fix cannot fix MD036, because emphasis-as-heading needs a judgement call: a bold line introducing a subsection should become a real heading, while an italic sign-off is not a heading at all and should become a blockquote. Converting the second kind into a heading gives you a happy linter and a wrong document. Co-Authored-By: Claude Opus 5 (1M context) --- ADOPTING-LINT.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ADOPTING-LINT.md b/ADOPTING-LINT.md index 5eb5c88..37a2eaf 100644 --- a/ADOPTING-LINT.md +++ b/ADOPTING-LINT.md @@ -138,6 +138,23 @@ Two traps this gate has already been bitten by, both now fixed here: file that applies, and it prints any tracked file `.gitignore` would have hidden. +## Fixing violations: two things that will bite you + +**Never run `prettier --write` blind on `.mdx`.** Prettier 3.9.4's mdx +parser rewrites a multi-line `{/* ... */}` comment into `{/_ ... _/}` - +it reads the `*` as markdown emphasis and emits invalid MDX. The +formatter actively breaks the file. Single-line comments round-trip +fine, so rewrite an affected comment as a run of single-line +`{/* ... */}` comments: same text, valid MDX, prettier leaves it alone. +Always diff an `.mdx` file after `--write`. + +**`markdownlint-cli2 --fix` will not fix MD036.** Emphasis used as a +heading needs a judgement call, not a rewrite. A bold line introducing a +subsection should become a real heading one level below its parent; a +sign-off or attribution in italics is not a heading at all and should +become a blockquote. Converting the second kind into a heading produces +a correct linter and a wrong document. + ## Language-specific CI This gate is the shared baseline that every repository can satisfy. From 7f3304f8be7652cc49b969eb2dfeb8392b2cba79 Mon Sep 17 00:00:00 2001 From: Bryan Fawcett Date: Sat, 12 Sep 2026 02:59:38 +0800 Subject: [PATCH 3/3] fix(lint): fire the caller on every default-branch name in the estate The caller's push trigger was `branches: [main]`, but three repos default to `scaffold` (shamwari-core, shamwari-gateway, shamwari-web) and one to `master` (siafudb-kuzu). Merging into those repos' default branch fired nothing, so the five contexts never appeared on the default-branch head. The shamwari agent had to run `gh workflow run lint.yml --ref scaffold` by hand to get evidence, and future merges there would have gone unwatched. That matters beyond bookkeeping: a push-triggered run on the default branch is what makes a broken main visible. bundu-labs/.github sat with `lint / prettier` red from 2026-05-02 and nobody noticed, because nothing required the contexts there. Losing the signal entirely in four repos is worse. Now `branches: [main, master, scaffold]` - a list rather than a bare `push:`, because unfiltered push would run the gate on every feature-branch push across 74 repos and bill it twice for every PR. Also records the MDX-in-.md trap in ADOPTING-LINT.md. A Mintlify starter leaves `{/* ... */}` in AGENTS.md; Mintlify parses that file as MDX where an HTML comment is a parse error, while markdownlint and Prettier read it as Markdown where the asterisks are emphasis. No spelling satisfies both, and `markdownlint-cli2 --fix` pairs asterisks across adjacent comment lines to produce something that is neither valid MDX nor intended. Co-Authored-By: Claude Opus 5 (1M context) --- ADOPTING-LINT.md | 21 ++++++++++++++++++++- workflow-templates/lint.yml | 12 +++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ADOPTING-LINT.md b/ADOPTING-LINT.md index 37a2eaf..10a6f2b 100644 --- a/ADOPTING-LINT.md +++ b/ADOPTING-LINT.md @@ -30,7 +30,7 @@ name: Lint on: pull_request: push: - branches: [main] + branches: [main, master, scaffold] merge_group: workflow_dispatch: @@ -54,6 +54,13 @@ per repo: in any repo whose default branch is not `main` - `shamwari-core`, `shamwari-gateway`, `shamwari-web` (`scaffold`) and `siafudb-kuzu` (`master`). +- **The `push:` branch list names every default branch in the estate.** + 68 repos use `main`, `siafudb-kuzu` uses `master`, and + `shamwari-core`/`-gateway`/`-web` use `scaffold`. Drop a name and + merging to that repo's default branch fires nothing, so the contexts + never land on the default-branch head. It is a list rather than a bare + `push:` because unfiltered push would run the gate on every + feature-branch push in 74 repos and bill it twice per PR. - **`merge_group:`** is what makes the gate work in a repo whose ruleset uses a merge queue. Required checks must report on the `gh-readonly-queue/**` ref and only `merge_group` produces that; @@ -148,6 +155,18 @@ fine, so rewrite an affected comment as a run of single-line `{/* ... */}` comments: same text, valid MDX, prettier leaves it alone. Always diff an `.mdx` file after `--write`. +**A `.md` file containing MDX comments cannot satisfy both toolchains, +and `--fix` will corrupt it.** Mintlify starters leave `{/* ... */}` in a +file named `AGENTS.md`. Mintlify parses that file as MDX, where an HTML +comment is a parse error; markdownlint and Prettier read the same file as +Markdown, where the asterisks are emphasis - MD037 fires and Prettier +rewrites the marker to `_`. No spelling satisfies both. Worse, +`markdownlint-cli2 --fix` pairs the asterisks across adjacent comment +lines and emits `{/*Add product-specific terms and preferred usage _/}`, +which is neither valid MDX nor what anyone wrote. Decide which toolchain +owns the file: add it to `.mintignore` and use ordinary HTML comments, or +rename it to `.mdx`. + **`markdownlint-cli2 --fix` will not fix MD036.** Emphasis used as a heading needs a judgement call, not a rewrite. A bold line introducing a subsection should become a real heading one level below its parent; a diff --git a/workflow-templates/lint.yml b/workflow-templates/lint.yml index 6292f77..5e71cb6 100644 --- a/workflow-templates/lint.yml +++ b/workflow-templates/lint.yml @@ -23,7 +23,17 @@ name: Lint on: pull_request: push: - branches: [main] + # Every default-branch name in the estate: `main` covers 68 repos, + # `master` covers siafudb-kuzu, `scaffold` covers shamwari-core, + # shamwari-gateway and shamwari-web. Drop a name and merging to that + # repo's default branch fires nothing, so the five contexts never + # land on the default-branch head - which is how `lint / prettier` + # stayed red in bundu-labs/.github from 2026-05-02 unnoticed. + # + # A list rather than a bare `push:`, because unfiltered push would + # run the gate on every feature-branch push in 74 repos and bill it + # twice per PR. Add a name here if a repo ever adopts a fourth. + branches: [main, master, scaffold] # Required for repos whose ruleset uses a MERGE QUEUE: required checks # must report on the gh-readonly-queue/** ref, and only merge_group # produces that. Without it a queued PR stalls for the full