Files
coder/.vale.ini
Nick Vigilante 88aa2cc373 feat: enable Coder.UnitSpacing (#29944)
## Summary

Adds `Coder.UnitSpacing`, a Vale rule that enforces the style guide's
[non-breaking space between number and
unit](https://github.com/coder/coder/blob/main/docs/.style/style-guide/numbers-units-and-dates.md#non-breaking-space-between-number-and-unit)
policy.
Until now, the guide pointed at `Google.Units (planned)`, but that rule
accepts a regular space, so it can't enforce the policy.

Resolves [DOCS-1072](https://linear.app/codercom/issue/DOCS-1072).

## Changes

- **Cleanup commit**: replaces the regular space (or missing space) with
` ` in 189 prose findings across 55 files. One config default,
`(default: 15s)`, moves to code font instead, as the guide requires for
configuration values. One table row that was realigned also swaps a
pre-existing en dash for a hyphen, since `lint/emdash` checks changed
lines.
- **Enable commit**: adds `docs/.style/styles/Coder/UnitSpacing.yml` at
`warning`, updates the enforcement footer in
`numbers-units-and-dates.md`, and updates the coverage tables in the
style guide README.
- **Reflow commit**: every hard-wrapped paragraph the cleanup touched
(45 paragraphs in 29 files) is rewrapped to one sentence per line.
Joining lines exposed units split across a line break, which now use
` `, and two em dashes on rewritten lines are reworded.
- **Rule fix commit**: the token now matches ASCII whitespace, including
a newline, between the number and the unit, so a hard-wrapped paragraph
can't hide a missing ` `. The class is spelled out because Vale's
`\s` is Unicode and would match U+00A0. Vale can't locate a match that
spans list indentation or a blockquote marker, so splits there still go
unreported.
- **Rule count sync**: the tooling paragraph in the style guide README
now reads 79 rules, 9 tool-checked, to match the coverage table. The 79
corrects drift already on `main` since #29758; the 9 is this PR's new
rule.
- `.vale.ini` turns the rule off for pages generated from Go source:
`docs/reference/{api,cli}/*.md`, `configuration-reference.md`, and
`prometheus.md`. That text comes from flag descriptions, Swagger
comments, and metric help text, which also render outside Markdown,
where ` ` would show up literally.

<details>
<summary>Rule design decisions</summary>

- An `existence` rule matches `\d+(\.\d+)?` followed by a regular space
or no space, then a unit from a curated list (time, data size,
bandwidth, frequency, vCPU/CPU/cores).
- Vale renders Markdown before matching, so `&nbsp;` and a literal
U+00A0 both pass. Code spans and fences are skipped.
- Hyphenated compound modifiers (`12-hour clock`) don't match, because
the token allows only a space or nothing between the number and the
unit.
- Exceptions cover HTTP status plurals (`413s`) and decades (`1990s`).
- Severity is `warning`, because the unit list is curated and a count
followed by a unit-like word can still be a judgment call.
- Alternative considered: a `BlockIgnores` pattern for the `<!-- Code
generated ... -->` regions. I didn't use it because it would silence
every rule in those regions, not just this one.

</details>

## Testing

- Ran the rule against fixtures: `30 seconds`, `150ms`, `4 vCPU` in a
table, and `16` / `GB` split across lines in a paragraph all flag.
`30&nbsp;seconds`, literal U+00A0, `12-hour`, `413s`, `1990s`, and ``
`30s` `` don't.
- `vale docs/` reports 0 `Coder.UnitSpacing` findings, and the counts
for every other rule match `main`.
- A scratch config with `Coder.OneSentencePerLine` turned on reports 0
findings on changed lines.
- `make lint/markdown`, `make lint/style-claims`, `make lint/emdash`,
and the `pre-commit-light` hook pass.

<details>
<summary>CI flake note</summary>

`Storybook` failed on b3c53b6874 after capturing all 3,421 snapshots,
when the Pixel build was marked `failed` during finalization. This PR
changes no files under `site/`. The re-run failed the same way, and
`Storybook` is failing in the same Pixel step on the latest `main`
commits, so this isn't caused by this PR.

</details>

---

*Generated by [Coder Agents](https://coder.com/docs/ai-coder/agents) on
behalf of @nickvigilante.*
2026-09-28 12:29:40 -04:00

71 lines
2.9 KiB
INI

# Vale configuration for Coder documentation.
#
# Rule rollout doctrine. Every rule listed below ships clean: zero
# 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` 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.
#
# To add a rule, follow the per-rule PR template in
# docs/.style/README.md ("Adding a Vale rule"). Third-party rules
# from Google, alex, and write-good are not enabled by default; each
# returns via the same per-rule PR pattern after its corpus is clean.
#
# About Vale's exit code: Vale exits non-zero only when error-level
# alerts are found. Warning and suggestion annotate without
# affecting exit. Real runtime failures (bad config, missing files)
# propagate regardless of severity.
#
# The Coder rule package lives under docs/.style/styles/Coder/ and is
# the single source loaded by default.
StylesPath = docs/.style/styles
MinAlertLevel = suggestion
Vocab = Coder
[*.md]
BasedOnStyles = Coder
# Coder.OneSentencePerLine is rolled out per directory instead of repo-wide.
# The convention postdates most of the corpus, so enabling it everywhere would
# report roughly 2,200 findings and break the zero-baseline doctrine above.
# Move a directory into the allowlist below once its pages are converted.
Coder.OneSentencePerLine = NO
# Converted directories. The pages here are written one sentence per line, so
# the rule ships clean for this scope.
[docs/.style/*.md]
Coder.OneSentencePerLine = YES
[docs/.style/styles/Coder/*.md]
Coder.OneSentencePerLine = YES
# Coder.UnitSpacing skips pages generated from Go source. Their prose comes
# from CLI flag descriptions, Swagger comments, and Prometheus metric help
# text, which render outside Markdown where `&nbsp;` would show literally.
[docs/reference/{api,cli}/*.md]
Coder.UnitSpacing = NO
[docs/admin/setup/configuration-reference.md]
Coder.UnitSpacing = NO
[docs/admin/integrations/prometheus.md]
Coder.UnitSpacing = NO
# 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 =
Coder.OneSentencePerLine = NO