feat: wire Vale prose linter into docs CI#25467
Conversation
Adds a private contributor-tooling directory at docs/.style/ that holds: - README.md explaining the convention and the no-deploy guarantee - style-guide.md as a scaffold for the canonical prose style guide - styles/Coder/ as the home for custom Vale rules (filled by follow-ups) Defense-in-depth tweaks to .github/workflows/deploy-docs.yaml exclude docs/.style/** from the push trigger and from the surgical-reindex git diff. coder.com/docs route discovery is already manifest-driven, so nothing under docs/.style/ becomes a route or an Algolia record. Also: - .github/.linkspector.yml: skip external-link checks under docs/.style/ - AGENTS.md: point agents at the new style guide - .claude/docs/DOCS_STYLE_GUIDE.md: cross-link to the canonical prose guide; this file remains the structure/research companion The Vale configuration that consumes docs/.style/styles/ lands in a follow-up PR (DOCS-40). Closes DOCS-180.
Lands the Vale prose linter as a non-blocking docs CI step. Builds on the scaffold from DOCS-180 (#25466): - .vale.ini at the repo root configures Google + curated write-good + cherry-picked alex rules. Disables Google.Spacing (false positives on codersdk type names in the auto-generated API reference), Google.EmDash (conflicts with our em-dash ban), Google.Latin (i.e. and e.g. are fine), write-good.Passive and write-good.E-Prime (judgment-heavy). - mise.toml pins Vale 3.7.1 via aqua. - Makefile adds build/vale-$VERSION install, docs/.style/.vale-synced sentinel that runs 'vale sync' once per .vale.ini change, and a lint/prose target wrapped in '|| true' for v1 non-blocking severity. - .github/workflows/docs-ci.yaml adds a 'prose' step that lints only the changed Markdown files under docs/, with continue-on-error: true and a cache for the synced styles and binary. - .gitignore excludes the synced upstream styles and the sentinel. - .markdownlint-cli2.jsonc ignores the synced styles so local markdownlint runs do not lint upstream READMEs. - docs/.style/README.md and style-guide.md document how to run Vale locally and what the active rule set is. Severity policy (v1): every rule lands at 'warning'. CI is non-blocking through continue-on-error: true. A rule promotes to 'error' only when (a) it is objectively correct and (b) the existing-content violation count reaches zero. Judgment rules stay at 'suggestion'. Local run on the full docs corpus produces 0 blocking failures, 391 errors, 5202 warnings, 7682 suggestions across 458 files in ~20s. Refs DOCS-40.
Docs preview📖 View docs preview for |
|
/coder-agents-review This PR adds a new docs-ci.yaml step, a new Makefile target, and a new mise.toml pin, so it is squarely "CI changes in a meaningful way." Focus areas:
Base branch is Filed via Coder Agents on Nick's behalf. |
… filter The 'docs/**.md' glob in tj-actions/changed-files skips dot-prefixed directories by default, so the changed-md-docs filter silently dropped docs/.style/README.md and docs/.style/style-guide.md. The Vale prose step never fired on PR #25467 as a result. Drop the second changed-files step and post-filter the changed-md output in shell. grep '^docs/' keeps only docs paths; grep -v '^docs/.style/styles/' excludes the synced upstream packages. The early exit handles PRs that only touched non-docs markdown. Refs DOCS-40.
Vale's release archive places 'vale' at the archive root with no leading ./ (unlike typos), so 'tar -xzf - ./vale' matched nothing and produced 'tar: ./vale: Not found in archive' on CI. Switch to 'vale'. The local Makefile invocation worked before because build/vale-3.7.1 was already present from the spike artifacts. CI hit the cold path and exposed the bug.
There was a problem hiding this comment.
Well-structured linter integration. The inline comments in .vale.ini justifying each enable/disable decision set a high bar for configuration documentation. The Makefile patterns mirror lint/typos cleanly, the CI caching is thoughtful, and the decision log in the PR description is unusually thorough.
As Hisoka put it: "Two config points that look independent, secretly attached through Vale's exit-code semantics. Whoever follows the documented path gets a surprise."
Severity breakdown: 4 P2, 5 P3, 1 P4, 2 Nit.
The P2 findings cluster around two themes: (1) Vale's exit-code behavior is different from what the PR documents (only errors cause non-zero exit, not warnings/suggestions), which inverts the described promotion path; and (2) operational blind spots where continue-on-error swallows infrastructure failures alongside lint warnings.
The P3 findings are mostly documentation accuracy issues and a maintenance friction point (package names hardcoded in 4 files that could use wildcards).
🤖 This review was automatically generated with Coder Agents.
Resolves the 12 findings from review id 4314529409 on PR #25467. DEREM-1 (P2): fix `./build/vale-*/vale` glob in docs/.style/README.md; the binary is the file itself, not a directory. DEREM-2 (P3): drop the inaccurate `make lint` claim in style-guide.md; point readers at README's Running Vale section instead. DEREM-3 (P2): split the prose step into `Prepare Vale styles` (no continue-on-error) and `prose` (no continue-on-error; --no-exit), so the job fails on sync failures but lints non-blocking. DEREM-4 (P2): replace `|| true` with Vale's native --no-exit in the Makefile and rewrite the severity-policy comment to match the measured exit-code semantics (Vale exits non-zero only on error alerts, regardless of MinAlertLevel). DEREM-5 (P2): add `Coder` to BasedOnStyles so the empty starter style is loaded and ready to receive rule files. DEREM-6 (P3): replace hardcoded per-package paths in .gitignore and the workflow cache step with `styles/*` plus a `!styles/Coder` negation, reducing the places future packages need to be listed. DEREM-7 (P3): already addressed by c3e9e2f (prose filter matches docs/.style paths) and 6054d9e (tar layout). DEREM-8 (P3): remove the duplicate Running Vale block in style-guide.md and cross-reference README.md as the single source. DEREM-9 (P3): add .github/vale-problem-matcher.json and wire the prose step with `::add-matcher::`/`--output=line`/`::remove-matcher::` so alerts surface as inline PR annotations. DEREM-10 (P4): trim the Active rule set section in style-guide.md to a policy summary plus a pointer to .vale.ini. DEREM-11 (Nit): rephrase the Makefile sync-sentinel comment to describe Make's behavior instead of suggesting `touch`. DEREM-12 (Nit): swap "(Vale spike, 2026-05-18)" for the more neutral "(measured 2026-05-18)" in the Google.Spacing rationale. Two-layer defense on the cache step protects the hand-authored Coder rules: the negation excludes styles/Coder from the cached paths, and the cache key hashes styles/Coder/** so any rule change invalidates the cache even if the negation behavior ever regresses (actions/toolkit#713, actions/cache#494). Verification: - make lint/actions: clean (zizmor, actionlint). - make fmt/markdown: no changes. - make lint/markdown: 0 errors across 463 files. - make lint/prose: exit 0; baseline 391 errors / 5201 warnings / 7673 suggestions across 458 files (consistent with the pre-review run).
Review iteration: addressed all 12 findingsCommit
Verification
Follow-ups (out of scope for this PR)
Filed via Coder Agents on Nick's behalf. |
|
/coder-agents-review Filed via Coder Agents on Nick's behalf. |
There was a problem hiding this comment.
All 12 R1 findings addressed in e49b5cc. The fixes are thorough: the exit-code model is correct in .vale.ini, Makefile, and style-guide.md; the CI step split cleanly separates infra failures from lint warnings; the problem matcher surfaces annotations inline; the wildcard gitignore and cross-referenced docs eliminate maintenance coupling.
Two locations still carry the pre-correction --no-exit explanation (DEREM-14, DEREM-15), and the CI shell filter has a semantic gap (DEREM-13). Severity: 2 P3, 1 Nit.
As Kite noted: "The block comment explaining Vale's CI behavior is unusually thorough. It documents the split-step rationale, the --no-exit semantics, the problem matcher lifecycle, and the cache negation defense-in-depth strategy with specific issue citations."
Process note: the PR description still describes the removed || true and continue-on-error: true mechanisms. The code comments are all correct, but the description will persist as the merge commit summary. Consider updating the description to reflect the current --no-exit + step-split architecture before merge.
🤖 This review was automatically generated with Coder Agents.
Three follow-ups from review id 4320840969. DEREM-13 (P3): drop the redundant `grep -v '^docs/\.style/styles/'` filter from the prose step. Synced upstream packages are gitignored, so tj-actions/changed-files never lists them; the filter only ever rejects tracked Coder/**.md files, which is the opposite of what we want. The inline comment now documents why no second filter exists. DEREM-14 (P3): fix the README's --no-exit explanation. The DEREM-4 fix chain reached .vale.ini, the Makefile, and style-guide.md but missed docs/.style/README.md. The README now matches the rest: --no-exit suppresses the exit from the baseline error count produced by un-overridden Google error-level rules, not from warnings/suggestions (which never trigger non-zero exit regardless of --no-exit). DEREM-15 (Nit): same model fix in the docs-ci.yaml prose-step comment. Verification: make lint/actions, make fmt/markdown, make lint/markdown, make lint/prose all clean. Vale baseline unchanged (391 errors / 5201 warnings / ~7673 suggestions across 458 files).
R2 follow-ups addressedCommit
Process note responseThe PR description was already rewritten earlier this session to remove the stale Verification
Filed via Coder Agents on Nick's behalf. |
|
/coder-agents-review Filed via Coder Agents on Nick's behalf. |
There was a problem hiding this comment.
All 15 findings from R1 and R2 addressed and verified by Netero + panel. The fixes are thorough and consistent: the --no-exit model is now correct across all five locations, the CI step split properly isolates infra failures, the problem matcher surfaces annotations inline, and the PR description matches the implementation.
One new Nit (DEREM-16) on the README escape-hatch command, otherwise clean.
As Hisoka put it: "Three rounds. Fifteen fixes. I pulled every thread I could find across the diff... Every thread either held or was guarded by a layer the author already placed. The code earned the silence."
🤖 This review was automatically generated with Coder Agents.
DEREM-16 (Nit) from review id 4321386259. `./build/vale-* docs/` is fine when only one vale-X.Y.Z binary exists in build/, but if a developer bumps the version in mise.toml without running `make clean`, multiple binaries coexist and the glob expands to multiple positional args, breaking the command. Low-risk path because three conditions have to align (version bump + no clean + manual invocation), but worth a sentence so a developer who hits it knows to `make clean`.
c184080 to
3e26bed
Compare
…tarter-microsoftgoogle-style-coder Reconcile Vale CI wiring with main's refactored docs lint: - main (#25608) deleted the standalone docs-ci.yaml and moved docs lint into the required lint-docs job in ci.yaml. Integrate Vale there (advisory, continue-on-error so a vale sync blip never blocks the required job) instead of resurrecting docs-ci.yaml. - Delete docs-ci.yaml; keep .vale.ini, Makefile vale targets, mise.toml, vale-problem-matcher.json, .linkspector.yml, .markdownlint-cli2.jsonc, .gitignore vale entries. - deploy-docs.yaml: keep main's release(published) trigger plus this branch's docs/.style/** reindex exclusions. - Scaffold prose (docs/.style/*, .claude/docs/DOCS_STYLE_GUIDE.md, AGENTS.md): take the merged DOCS-180 canonical versions. Generated with Coder Agents on Nick's behalf.
|
/coder-agents-review Context for the reviewer: this branch was rebased onto Requested by Coder Agents on behalf of @nickvigilante. |
|
Chat: Review posted | View chat Review historydeep-review v0.7.1 | Round 6 | Last posted: Round 6, 23 findings (5 P2, 10 P3, 1 P4, 7 Nit), APPROVE. Review Finding inventoryFindings
Contested and acknowledged(none) Round logRound 1Panel. Netero: 2 P3 (folded into panel findings). Panel: 4 P2, 5 P3, 1 P4, 2 Nit. 0 dropped. Reviewed against cb723c3..4cb4d63. Round 2Panel. DEREM-1 through DEREM-12 all addressed. 2 P3, 1 Nit new. Reviewed against cb723c3..e49b5cc. Round 3Panel. DEREM-13 through DEREM-15 all addressed. 1 Nit new. Reviewed against cb723c3..0048444. Round 4Panel (post-rebase). DEREM-16 addressed. PR restructured: Vale moved from standalone docs-ci.yaml to required lint-docs job in ci.yaml. 1 P2, 3 P3, 2 Nit new. Reviewed against 182bdc8..55e7ab0. Round 5BLOCKED. CRF-18 addressed. 5 silent (CRF-17, CRF-19, CRF-20, CRF-21, CRF-22). No review. Round 6Panel. CRF-17 through CRF-22 all addressed. 1 P3, 1 Nit new. 1 dropped (Mafuuu P3 factually wrong: Vale --output=line group 4 is rule name, not severity). Reviewed against 182bdc8..30072f1. About deep-reviewCRF = Coder Review Finding (P0-P4, Nit, Note)
|
…ning Merging main surfaced two CI failures from wiring Vale into the required lint-docs job: - mise install --locked failed because aqua:errata-ai/vale@3.7.1 was in mise.toml but missing from mise.lock. Added all 11 platform entries via mise lock. - zizmor flagged the Vale styles cache (actions/cache) as a cache-poisoning risk. Split it into actions/cache/restore plus an actions/cache/save gated to pushes on main, matching the existing golangci-lint cache pattern in this workflow. Generated with Coder Agents on Nick's behalf.
There was a problem hiding this comment.
Post-rebase review. The restructuring from standalone docs-ci.yaml to the required lint-docs job in ci.yaml is well-reasoned: continue-on-error: true on every Vale step keeps the advisory linter from blocking merges, while the split-step design preserves diagnostic visibility. The PR description was rewritten to match the new integration point, and all 16 prior findings remain addressed in the rebased code.
Two themes in the new findings: (1) the Makefile's grep -oP for version extraction is GNU-only and silently breaks Vale on macOS (CRF-17), and (2) the CI file list includes deleted paths that cause Vale to error on missing files, degrading the advisory signal (CRF-19). Both have one-line fixes.
As Hisoka put it: "The advisory system trains its users to stop reading it."
Severity: 1 P2, 3 P3, 2 Nit.
CRF-20 proposes a structural alternative: replacing the ~30-line binary-download block with mise exec vale -- (8 lines), following the pattern actionlint and zizmor already use in this Makefile. This would also eliminate CRF-17 as a side effect. Worth considering.
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
There was a problem hiding this comment.
Five of six R4 findings have no author response or code change. CRF-18 (actions/cache version) was addressed in 4b8f87c. Further review is blocked until the remaining findings are addressed or acknowledged.
Open findings requiring a response:
- CRF-17 (P2)
Makefile:833—grep -oPis GNU-only; breaksVALE_VERSIONextraction on macOS. Fix: use POSIXsedorawk, or adopt CRF-20'smise execapproach. - CRF-19 (P3)
ci.yaml:209—all_changed_filesincludes deleted paths; Vale errors on missing files. Fix: useall_modified_files. - CRF-20 (P3)
Makefile:833— ~30-line binary download block is the sole surviving instance of this pattern;actionlintandzizmoralready usemise exec. Adoptingmise exec vale --eliminates CRF-17 as a side effect. - CRF-21 (Nit)
.markdownlint-cli2.jsonc:4— add a JSONC comment documenting the coupling to.vale.iniPackages. - CRF-22 (Nit)
.vale.ini:56— replace opaquek.Rexample with a real codebase example.
For each: push a fix, acknowledge, contest, or file a ticket.
🤖 This review was automatically generated with Coder Agents.
Resolves DOCS-40 review findings CRF-17/19/20/21/22: - Makefile: invoke Vale via `mise exec "aqua:errata-ai/vale"` like actionlint/zizmor instead of the bespoke curl/tar download. This removes the GNU-only `grep -oP ...\K` version extraction that silently returned empty on macOS BSD grep, producing a malformed download URL (CRF-17). mise.toml stays the single version source of truth; mise handles the OS/arch build (CRF-20). - ci.yaml: filter the changed-Markdown list to docs/ paths still present on disk so Vale never errors on files this PR deleted (CRF-19); run Vale through `mise exec`; drop the now-unused build/vale-* cache path; set MISE_YES so first-use auto-install is non-interactive. All Vale steps remain continue-on-error (advisory). - .markdownlint-cli2.jsonc: document the coupling with .vale.ini's Packages directive (CRF-21). - .vale.ini: replace the unreal `k.R` example with a real codersdk type name (CRF-22). CRF-18 was already satisfied: both Vale cache steps pin actions/cache@v5.0.5, matching the repo standard. Validated locally: make lint/prose (mise-installed Vale 3.7.1, exit 0 via --no-exit), actionlint (exit 0), and zizmor (no findings) all pass. Filed via Coder Agents on Nick's behalf.
Addressed post-rebase review (CRF-17 through CRF-22)Pushed
Validated locally: /coder-agents-review Filed via Coder Agents on Nick's behalf. |
…tarter-microsoftgoogle-style-coder
There was a problem hiding this comment.
All 6 R4 findings addressed in 30072f1. The mise exec migration (CRF-17/CRF-20) is clean: 30 lines of platform-specific binary management replaced by 8 lines of mise exec, matching the established actionlint/zizmor pattern. Deleted-file filtering (CRF-19), coupling documentation (CRF-21), and the opaque example fix (CRF-22) are all verified correct.
Two minor items remain (CRF-23, CRF-24), neither blocking.
As Hisoka put it: "Six rounds in and this opponent has hardened. I pulled every thread I could find. Most held."
🤖 This review was automatically generated with Coder Agents.
Documentation CheckUpdates Needed
Automated review via Coder Agents |
- .vale.ini: drop the stale "missing binary" failure mode from the exit-code comment; mise auto-installs Vale, so that mode no longer exists (CRF-23). - ci.yaml: correct the **.md glob rationale -- the action's globber collapses a `**` adjacent to `.md` to a single segment, so docs/**.md misses nested pages; the prior "skips dot-prefixed dirs" reason was inaccurate (CRF-24). Comment-only; no behavior change. Both are non-blocking nits from the Coder Agents R6 review (which APPROVED the PR). Filed via Coder Agents on Nick's behalf.
|
Addressed the two non-blocking R6 nits in
Thanks for the thorough six-round pass. Not re-triggering a review for these comment-only fixes. Filed via Coder Agents on Nick's behalf. |
| # The styles themselves live under docs/.style/styles/ after `vale sync`, | ||
| # which the Makefile target invokes once per .vale.ini change. They are | ||
| # gitignored to keep the repo lean. |
There was a problem hiding this comment.
Given the only style guide we have is in docs/ is there any reason why we have the .vale.ini the root and not in ./docs? The only reason I ask is it can be visually pleasing to have a simple repo structure (and less scroll for users to the README). Plus - then all files and rules for the docs only exist in docs versus it being scattered in docs and the root
There was a problem hiding this comment.
This is a huge nit and see our root is already messy so feel free to ignore.
bpmct
left a comment
There was a problem hiding this comment.
Approving, but: Will this cause all of our existing PRs/builds to fail for engineers in CI since I'd assume we're not compliant?
The Doc-Check bot flagged three items on the rebased PR: 1. docs/.style/README.md referenced .vale.ini as 'added in a follow-up PR' on two lines, but this PR lands .vale.ini. Switched both to present tense and pointed at `make lint/prose` for local reproduction. 2. docs/.style/style-guide.md said the Vale rule-set rationale 'lives in the follow-up PR that lands .vale.ini'. Replaced with a pointer to the .vale.ini inline comments and `make lint/prose`. 3. docs/about/contributing/documentation.md's Tools section listed alex.js, Grammarly, and Hemingway but had no mention of Vale, even though Vale now runs on every doc PR. Added a paragraph explaining that Vale runs in CI on docs/, points at .vale.ini and the style guide, and runs locally via `make lint/prose`. Kept the existing external-tools bullet list with a slightly tightened lead-in that notes why those tools aren't a substitute (not tuned for Coder's voice). The third edit is also a natural illustration of Vale's non-blocking posture on this PR: the file already produces 9 warnings + 22 suggestions against the curated rule set, and the new paragraph adds a few more. CI's prose step lints the changed Markdown files and surfaces those as inline PR annotations, but the job still exits 0 because none of them are error-level.
Thanks for the review! |
Wires Vale into docs CI as an advisory (non-blocking) prose-lint step. Closes DOCS-40.
A sample of what this check does is as follows:
What changes
.vale.iniat the repo root: Google base + Coder (custom, empty in v1) + curated write-good.alexrules are pulled in a la carte. Inline comments justify every enable/disable.mise.toml: pin Vale3.7.1via aqua.mise.lock: lock that pin across all platforms somise install --locked(used bybuild_image) resolves it.Makefile: adocs/.style/.vale-syncedsentinel that gatesvale sync, and alint/prosetarget that runsvale --no-exit. Both invoke Vale viamise exec "aqua:errata-ai/vale" -- vale ..., so mise owns the version and the OS/arch download (no hand-rolled install path)..github/workflows/ci.yaml: append Vale steps to the existing requiredlint-docsjob:Detect changed Markdown,Restore Vale styles,Prepare Vale styles(make docs/.style/.vale-synced),Vale prose lint, and a default-branch-onlySave Vale styles. They lint only changed Markdown underdocs/that still exists on disk, with a problem matcher for inline PR annotations..github/vale-problem-matcher.json: parsesvale --output=lineso alerts surface as annotations on the Files Changed tab..gitignoreand the workflow cachepath:: usedocs/.style/styles/*plus a!docs/.style/styles/Codernegation so adding a package does not require parallel edits..markdownlint-cli2.jsonc: ignore the synced styles somake lint/markdowndoes not lint upstream READMEs.Scaffold prose under
docs/.style/and.claude/docs/DOCS_STYLE_GUIDE.md/AGENTS.mdcome from the merged DOCS-180; this PR no longer touches them. Net diff againstmainis the 8 Vale-wiring files only.Severity policy (v1)
Rule severity reflects two things together: the rule's false-positive rate against real Coder docs and the gravity of the rule. Low FPs plus high gravity argues for
error; lower gravity or more judgment calls argue forwarningorsuggestion. v1 lands most rules atwarningand the wordiness rules atsuggestion.A rule promotes to
erroronly when (a) its false-positive rate against real content is effectively zero and (b) the existing-content violation count for that rule is also zero. Vale exits non-zero only on error-level alerts regardless ofMinAlertLevel; the Makefile and CI invoke Vale with--no-exitso the baseline error count from un-overridden Google rules does not fail the build while real failures (bad config, missing files) still propagate.CI integration
Vale runs as steps appended to the required
lint-docsjob inci.yaml, gated on changed Markdown:Detect changed Markdown(tj-actions/changed-files) scopes to changed**.md; the prose step re-filters todocs/(thedocs/**.mdglob silently skips dot-prefixed dirs and would missdocs/.style/style-guide.md).Restore Vale styles(actions/cache/restore), keyed offhashFiles('.vale.ini', 'mise.toml', 'docs/.style/styles/Coder/**'). mise manages the Vale binary, so only the synced styles are cached.Prepare Vale stylesrunsmake docs/.style/.vale-synced(mise exec ... vale sync).Vale prose lintfilters the changed set todocs/paths still present on disk, then runsmise exec ... vale --no-exit --output=line, emitting inline annotations via the problem matcher.Save Vale styleswrites the cache, gated torefs/heads/mainonly so PR runs cannot poison the cache other branches restore from (the zizmorcache-poisoningconcern).Every Vale step is
continue-on-error: true. This is a deliberate change from the original standalone-workflow design: now that Vale lives inside the requiredlint-docsjob, a transientvale syncnetwork failure (or first-usemiseinstall blip) would otherwise block merges.continue-on-errorkeeps Vale advisory, so only the markdownlint / table-formatter checks above (pnpm check-docs) remain merge-blocking.vale --no-exitadditionally keeps the baseline error count from un-overridden Google rules from failing the step.Verification
actionlintclean onci.yaml(local +make lint/actions/actionlint);zizmor --persona regularreports no findings.make lint/proseon the fulldocs/corpus: ~406 errors, ~5,346 warnings, ~7,928 suggestions across 461 files, exit 0 (--no-exit), Vale3.7.1installed by mise.mainis the 8 Vale-wiring files only; thedocs/.style/scaffold already matchesmain.Implementation plan and decision log
Why this rule set
The Vale evaluation against the full docs corpus (measured 2026-05-18) produced ~43,940 raw violations across six candidate base styles. The selection here drops Microsoft and RedHat (overlap with Google, and RedHat's Spacing rule hammers technical IDs), and proselint (Annotations rule treats
> [!NOTE]admonitions as TODO markers).Within the kept styles:
EmDash(conflicts withmake lint/emdash),Latin(i.e./e.g. are fine for our audience),Spacing(4,500 errors oncodersdk.SomeTypepatterns in the auto-generated API reference). Softened:Parenstosuggestion,WordListtowarning.PassiveandE-Primeoff.TooWordyandThereIsare suggestions;Weaselis a warning.BasedOnStyles):Ablist,Condescending,LGBTQ,ProfanityLikely,Race,Suicideat warning. TheProfanityMaybe/ProfanityUnlikelyrules trip onexecute,kill,failed, andattack, which read as technical vocabulary in our context.BasedOnStylesbut the directory is empty in v1. Rules land through the per-rule tickets in the Docs style guide project.Why
mise execinstead of a download blockVale is pinned in
mise.tomllikeactionlintandzizmor, so invoking it viamise exec "aqua:errata-ai/vale" -- vale ...makes the pin the single source of truth and lets mise handle the OS/arch-specific download. This replaced an earlier ~30-linecurl/tarblock whose GNU-onlygrep -oP ...\Kversion extraction returned empty on macOS BSD grep. Note: the barevaleshort name inmise execignores the pin and resolves to the latest release, so the full aqua key is required.Why
vale syncinstead of vendoringThe three style packages weigh ~272 KB combined, so vendoring is cheap. But Vale's ecosystem treats
Packages =+vale syncas canonical, the upstream LICENSE files are not in the package tarballs (would need to be added manually), and the CI cache makes the sync nearly free after the first run. Sticking with the canonical pattern keeps the repo lean and the upgrade path obvious.Why
lint/proseis not inlint:orlint-light:Vale on the full docs corpus takes ~20s on cold caches. Forcing every pre-commit through that would be aggressive for a feature that ships as warnings.
make lint/typosfollows the same pattern (it is inlint-lightbut notlint; CI invokes it directly). v1 keeps Vale opt-in locally and CI-only by default; promote tolint:once the rule set stabilizes.Exit-code handling
Two mechanisms combine, and the choice changed when the step moved into the required
lint-docsjob:vale --no-exitsuppresses Vale's non-zero exit on alerts, so the baseline error-level violations from un-overridden Google rules do not fail the step while the cleanup PRs land. Real failures (config invalid, file missing) still exit non-zero.continue-on-error: trueon every Vale step. Because the steps now run inside the requiredlint-docsjob, avale syncdownload/network blip must not block merges. The original (standalone, non-required) design rejectedcontinue-on-errorfor showing a misleading yellow badge; in a required job that tradeoff flips, and advisory-yellow is strictly preferable to merge-blocking-red on an infrastructure flake.|| truein the Makefile was also rejected: it swallows missing-config failures indiscriminately.Pre-mortem
docs/reference/is dominated by auto-generated content (clidocgen, apidocgen, auditdocgen, metricsdocgen). The architectural decision is to fix the generators, not exclude paths in Vale. Google.Spacing is the only rule silenced specifically to defer the generator fix; everything else surfaces as warnings.miseinstalls the pinned Vale (a single small binary) andvale syncpulls the style packages on a cold run. The Actions cache keyed offhashFiles('.vale.ini', 'mise.toml', 'docs/.style/styles/Coder/**')makes subsequent runs near-instant; theCoder/**hash is defense-in-depth against actions/toolkit#713 so a future cache release that regresses path-negation cannot serve a staleCoder/from cache.lint-docsjob means any Vale step failure would gate merges. Mitigated bycontinue-on-erroron all Vale steps plus a clean skip when no changeddocs/Markdown remains on disk, so onlypnpm check-docsstays blocking.uname/arch map, which removes the macOS BSD-grep break the review flagged.all_changed_filesis ACMRD and lists paths a PR removes; the prose step filters to files still present on disk so Vale does not error on a missing file.make lint/proselints the full tree. This mirrorsmake lint/markdown(full tree) vs the changed-files CI step. Acceptable for v1.Filed via Coder Agents on Nick's behalf.