From 4d4d2575e4b24f4509cc4d0708c68192a476fa23 Mon Sep 17 00:00:00 2001 From: Nick Vigilante Date: Sat, 18 Jul 2026 13:41:27 -0400 Subject: [PATCH] fix: exempt docs/.style/ prose from Vale's own Coder rules (#27192) ## Problem The repo-root `.vale.ini` lints all of `docs/**/*.md`, including the style guide under `docs/.style/style-guide/`. The guide deliberately contains the constructs the Coder rules ban: - Don't examples in blockquotes and in the Don't column of Do/Don't tables. - Banned terms named in prose and headings (a rule about "Next steps" must write "Next steps"). `Coder.BrandNames` already fired on the Brand names table's Don't column (`Hashicorp`, `HASHICORP`), and each future `Coder.*` rule would fire on its matching section's examples. Vale runs advisory, so these surface as non-blocking annotations, exactly the standing backlog the README warns against, and they break the documented "zero baseline findings" doctrine. ## Change Option B, narrowed after review to the style-guide subtree: - `.vale.ini`: clear `BasedOnStyles` for `docs/.style/style-guide/**` (the guide subpages only). The annotation demo and the rest of `docs/.style/` stay linted; the demo keeps firing its `Coder.Demo*` rules by inheriting `Coder` from `[*.md]`, with no re-include. Also corrects the `error`-tier doctrine line to reflect advisory-only Vale. - `docs/.style/README.md`: "What still runs" / "What does not run" describe the narrowed exemption, and record that it holds only for paths that resolve to `docs/.style/style-guide/...` (repo-root-relative), not absolute or subdirectory-relative invocations. - `docs/.style/style-guide/README.md`: exemption note scoped to `docs/.style/style-guide/**`. - `docs/.style/styles/Coder/BrandNames.yml`, `docs/.style/styles/Coder/README.md`: fix the remaining dead `style-guide.md` links (the `BrandNames.yml` one was a live 404 surfaced in Vale annotations). ## Validation - `make lint/prose` reports only the 3 intended `Coder.Demo*` findings across the corpus; the guide's `BrandNames` findings are gone. - `content-guidelines.md`, the landing `README.md`, and `styles/Coder/README.md` are now linted and clean (0). Injecting a miscased `Hashicorp` into `content-guidelines.md` fires `Coder.BrandNames`; reverted. - The guide subpages stay exempt (0); the annotation demo still fires its 3 findings via `[*.md]`. - Invocation-path behavior verified against `docs/.style/style-guide/word-choice.md`: repo-root-relative `docs/...` is exempt (0), while `docs/`-relative and absolute-path invocations still fire 2 `Coder.BrandNames` errors. - `markdownlint-cli2` clean on the changed READMEs. ## Decision log Considered three options from the issue: - **A. Surgical in-file suppression** (`vale off`/`vale on` comment blocks, backticking banned terms). Rejected as primary: noisy in source, repeated per example, bare-term headings still fire, and every new rule can re-break the guide. It is path-independent, so it would have covered the editor case noted in Option B's limitation. - **B. Config-level subtree exemption** (chosen; narrowed to the guide subtree after round-2 review). One place, zero source noise, future-proof for the guide subpages. - **Scope.** The clear applies to `docs/.style/style-guide/**` only. Round-2 review (three reviewers converged, verified end-to-end) showed the original directory-wide clear over-reached: `content-guidelines.md` and the landing `README.md` are ordinary contributor prose that lints clean today (`content-guidelines.md` uses `HashiCorp` correctly), so they should stay linted. Narrowing to the guide subtree preserves the exact 3-finding baseline, relints those two pages, removes the last-match-wins ordering hazard, and drops the whole-package demo re-include. The demo sits at the `.style/` root and keeps firing via `[*.md]`. - **Tradeoff.** The guide's own prose under `style-guide/` is no longer auto-linted by Vale. Acceptable because the guide must contain banned terms by design, one-sentence-per-line is enforced by markdownlint, and human review covers the rest. - **Limitation.** The exemption holds only for invocations whose path resolves to `docs/.style/style-guide/...` (repo-root-relative `docs/...`, what `make lint/prose` and CI pass). Absolute paths (editors/LSP) and subdirectory-relative paths still flag the guide. Recorded in `docs/.style/README.md`. - **C. Restructure examples into fenced code blocks.** Rejected: changes the guide's rendered format and doesn't cover Do/Don't tables or headings. ## Notes - `.vale.ini` is outside `docs/`, so this PR modifies repo-wide lint config; the clear is scoped to `docs/.style/style-guide/` only. - Linear: DOCS-543. --- Opened via Coder Agents on behalf of @nickvigilante. --- .vale.ini | 19 ++++++++++-- docs/.style/README.md | 39 ++++++++++++++++++++----- docs/.style/style-guide/README.md | 2 ++ docs/.style/styles/Coder/BrandNames.yml | 2 +- docs/.style/styles/Coder/README.md | 4 +-- 5 files changed, 52 insertions(+), 14 deletions(-) diff --git a/.vale.ini b/.vale.ini index 37643143f1..29455e0f6b 100644 --- a/.vale.ini +++ b/.vale.ini @@ -1,10 +1,12 @@ # Vale configuration for Coder documentation. # # Rule rollout doctrine. Every rule listed below ships clean: zero -# baseline findings across `docs/` at enable time. Severity is a -# deliberate per-rule choice: +# baseline findings across `docs/` (excluding `docs/.style/style-guide/`, +# which is exempt by design; see docs/.style/README.md) at enable time. +# Severity is a deliberate per-rule choice: # -# - `error` hard policy; CI blocks merge on violations. +# - `error` top annotation tier; surfaces a GitHub `error`. Vale +# runs advisory, so it does not block merge today. # - `warning` strong guidance; surfaces annotations without # failing CI. # - `suggestion` soft guidance; surfaces `notice` annotations. @@ -27,3 +29,14 @@ MinAlertLevel = suggestion [*.md] BasedOnStyles = Coder + +# The style guide under docs/.style/style-guide/ deliberately demonstrates the +# violations the Coder rules ban (Don't examples in blockquotes and Do/Don't +# tables, banned terms named in headings and prose). Linting it would surface a +# standing backlog of intentional findings, which erodes trust in the annotation +# channel and breaks the zero-baseline doctrine. The rest of docs/.style/ (the +# landing page, content-guidelines.md, the annotation demo, and the Coder rule +# docs) is ordinary prose and stays linted; the annotation demo keeps firing its +# Coder.Demo* rules with no re-include. See docs/.style/README.md. +[docs/.style/style-guide/**] +BasedOnStyles = diff --git a/docs/.style/README.md b/docs/.style/README.md index e9649ff9f8..69a4e931c3 100644 --- a/docs/.style/README.md +++ b/docs/.style/README.md @@ -9,14 +9,14 @@ Nothing under this directory is published to | Path | Purpose | |-------------------------|---------------------------------------------------------------------| | `content-guidelines.md` | Canonical content rules: what belongs in `docs/`, what doesn't, why | -| `style-guide.md` | Canonical prose style guide for `docs/` | +| `style-guide/` | Canonical prose style guide for `docs/` | | `styles/Coder/` | Custom Vale rules specific to Coder (product voice, terms) | See [`content-guidelines.md`](content-guidelines.md) for the canonical rules on what content belongs in `docs/` and what should be routed elsewhere (blog, changelog, Support KB, etc.). -See [`style-guide.md`](style-guide.md) for the prose style guide. The +See [`style-guide/`](style-guide/README.md) for the prose style guide. The `styles/Coder/` directory holds the custom Vale rules that enforce parts of the guide; Vale's `StylesPath` in the repo-root `.vale.ini` points at `docs/.style/styles/`. @@ -25,8 +25,10 @@ of the guide; Vale's `StylesPath` in the repo-root `.vale.ini` points at The leading dot mirrors the `.github/`, `.vscode/`, and `.claude/` convention already used in this repo for tooling-internal directories. -Vale and the structural Markdown linters still pick it up; coder.com's -docs site does not. +The structural Markdown linters and Vale still pick it up (except the style +guide's own prose under `style-guide/`, which is exempt); coder.com's docs +site does not. Refer to "What does not run against this directory" below for +that exemption. ## How exclusion from coder.com works @@ -56,9 +58,12 @@ directory from the surgical-reindex payload on mixed commits. `markdownlint-cli2 --fix $(find docs -name '*.md')`. - `make fmt/markdown` (markdown-table-formatter) reflows tables here for the same reason. -- Vale lints the entire `docs/**/*.md` set, including `docs/.style/style-guide/`. - Refer to the repo-root `.vale.ini` for the active configuration. - Run `make lint/prose` locally to reproduce. +- Vale (`make lint/prose`) lints everything here except the style guide's own + prose under `style-guide/`: the landing page, `content-guidelines.md`, the + annotation demo (whose `Coder.Demo*` rules are meant to fire), and the Coder + rule docs. Refer to the repo-root `.vale.ini` for the active configuration, + and to "What does not run against this directory" below for the one + exemption. ## What does not run against this directory @@ -71,6 +76,22 @@ directory from the surgical-reindex payload on mixed commits. so `.style`-only PRs produce no preview comment. The selection logic also skips `.style` files when picking the preview target on mixed PRs. See `.github/workflows/docs-preview.yaml`. +- Vale's `Coder` rules on the style guide's own prose under + `docs/.style/style-guide/`. The guide deliberately contains the constructs + the rules ban, such as Don't examples and banned terms named in headings and + prose, so the repo-root `.vale.ini` clears `BasedOnStyles` for + `docs/.style/style-guide/**`. Nothing else under `docs/.style/` is exempt: + the landing page, `content-guidelines.md`, the annotation demo, and the Coder + rule docs are all linted. Zero-baseline is therefore measured over `docs/` + excluding `docs/.style/style-guide/`. + The exemption applies only when the path resolves to + `docs/.style/style-guide/...` from the working directory, which is what + `make lint/prose` and CI pass (repo-root-relative `docs/...`). Other + invocation forms bypass the glob and still flag the guide's intentional + examples: absolute paths (what editors and LSP integrations pass) and + subdirectory-relative paths (for example `vale .style/style-guide/...` run + from `docs/`). Treat those in-editor and subdirectory findings on the guide + as expected. ## Editing the content guidelines @@ -86,7 +107,9 @@ Follow-up PRs add each rule and the matching style-guide section together. ## Adding a Vale rule Each rule in the repo-root `.vale.ini` ships clean: zero baseline -findings against the current `docs/` corpus. +findings against the current `docs/` corpus, excluding +`docs/.style/style-guide/`, which is exempt because the style guide +demonstrates the violations the rules ban. The PR that adds a rule is the rule's complete unit: 1. **Cleanup commit**: fix every existing-content violation of the new diff --git a/docs/.style/style-guide/README.md b/docs/.style/style-guide/README.md index f32d938cab..21b934106b 100644 --- a/docs/.style/style-guide/README.md +++ b/docs/.style/style-guide/README.md @@ -87,6 +87,8 @@ Severity is a deliberate per-rule choice from the three-tier ladder: Use for soft guidance where the right fix is contextual. The full doctrine, including the false-positive policy, lives in [`README.md`](../README.md). +This guide is itself exempt from the Coder rules: it demonstrates the violations those rules ban, so the repo-root `.vale.ini` clears `BasedOnStyles` for `docs/.style/style-guide/**`. +Zero baseline is measured over `docs/` excluding `docs/.style/style-guide/`. Run `make lint/prose` to reproduce the baseline locally. ## Relationship to `docs/about/contributing/documentation.md` diff --git a/docs/.style/styles/Coder/BrandNames.yml b/docs/.style/styles/Coder/BrandNames.yml index a5a73f61bb..a9112898f2 100644 --- a/docs/.style/styles/Coder/BrandNames.yml +++ b/docs/.style/styles/Coder/BrandNames.yml @@ -17,7 +17,7 @@ # unchanged; the `%s` token interpolates the matched (wrong) text. extends: substitution message: "Use '%s' instead of '%s' (brand-name casing)." -link: https://github.com/coder/coder/blob/main/docs/.style/style-guide.md#brand-names +link: https://github.com/coder/coder/blob/main/docs/.style/style-guide/word-choice.md#brand-names level: error ignorecase: false nonword: false diff --git a/docs/.style/styles/Coder/README.md b/docs/.style/styles/Coder/README.md index 05d50605b4..4a267d4acb 100644 --- a/docs/.style/styles/Coder/README.md +++ b/docs/.style/styles/Coder/README.md @@ -4,7 +4,7 @@ Custom Vale rules specific to Coder live here. Each rule is a YAML file that Vale loads through the `BasedOnStyles = Coder` setting in the repo-root `.vale.ini`. Active rules ship as YAML files in this directory. -See the matching sections in `docs/.style/style-guide.md` for the user-facing policy each rule enforces. +See the matching sections in `docs/.style/style-guide/` for the user-facing policy each rule enforces. Follow-up PRs add rules incrementally. Planned coverage: @@ -28,7 +28,7 @@ Planned coverage: - The rule is objectively correct (typo, brand-name casing, banned substitution). - The existing-content violation count for the rule reaches zero. -4. A follow-up PR adds a parity CI check that verifies every rule here has a matching section in `style-guide.md`. +4. A follow-up PR adds a parity CI check that verifies every rule here has a matching section in `style-guide/`. Add the section in the same PR as the rule. ## Reference