diff --git a/.vale.ini b/.vale.ini index b5e85ad869..7e2c1dfec0 100644 --- a/.vale.ini +++ b/.vale.ini @@ -45,17 +45,22 @@ 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 ` ` would show literally. +# Coder.UnitSpacing and Coder.AbbreviationFirstUse skip pages generated from Go +# source. Their prose comes from CLI flag descriptions, Swagger comments, and +# Prometheus metric help text. Those strings also render outside Markdown, +# where ` ` would show literally, and readers look up one entry at a time +# rather than reading from the first use of an abbreviation. [docs/reference/{api,cli}/*.md] Coder.UnitSpacing = NO +Coder.AbbreviationFirstUse = NO [docs/admin/setup/configuration-reference.md] Coder.UnitSpacing = NO +Coder.AbbreviationFirstUse = NO [docs/admin/integrations/prometheus.md] Coder.UnitSpacing = NO +Coder.AbbreviationFirstUse = 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 diff --git a/docs/.style/style-guide/README.md b/docs/.style/style-guide/README.md index 98e06d8cbc..7ef386393b 100644 --- a/docs/.style/style-guide/README.md +++ b/docs/.style/style-guide/README.md @@ -22,8 +22,8 @@ The doctrine for adding Vale rules lives in the [Vale doctrine README](../README ## What the tooling checks, and what it doesn't A clean `make lint/prose` run is not evidence that a page follows this guide. -The guide documents 80 rules. -Automated tooling checks 9 of them, and 1 of those 9 doesn't run on published pages. +The guide documents 81 rules. +Automated tooling checks 10 of them, and 1 of those 10 doesn't run on published pages. The other 71 are yours to apply by reading, 72 on published pages, where the one-sentence-per-line rule is off. Open the section that matches what you're writing and work through it. @@ -38,6 +38,7 @@ The linters catch a narrow band of mechanical errors; they can't tell you that a | `Coder.SelectClick` | Vale | `warning` | `docs/**` except `docs/.style/style-guide/**` | `click` and its inflections | | `Coder.OneSentencePerLine` | Vale | `warning` | `docs/.style/*.md` and `docs/.style/styles/Coder/*.md` only | Sentence boundaries mid-line, on contributor docs only | | `Coder.UnitSpacing` | Vale | `warning` | `docs/**` except `docs/.style/style-guide/**` and `docs/admin/integrations/prometheus.md` and `docs/admin/setup/configuration-reference.md` and `docs/reference/{api,cli}/*.md` | A regular space, or no space, between a number and its unit | +| `Coder.AbbreviationFirstUse` | Vale | `warning` | `docs/**` except `docs/.style/style-guide/**` and `docs/admin/integrations/prometheus.md` and `docs/admin/setup/configuration-reference.md` and `docs/reference/{api,cli}/*.md` | Abbreviations with no earlier "Expanded Form (ABBR)" on the page | | `MD001`, `MD025`, `MD040`, `MD045` | markdownlint | `error` | All Markdown | Heading increments, single H1, fence language, missing alt text | | `scripts/check_emdash.sh` | `make lint/emdash` | `error` | Repository | Em-dash, en-dash, and ` -- ` as punctuation | @@ -57,11 +58,11 @@ The markdownlint and emdash checks do fail the build. | [Voice and tone](./voice-and-tone.md) | 10 | 0 | 2 | 8 | | [Procedural writing](./procedural-writing.md) | 5 | 0 | 0 | 5 | | [Word choice](./word-choice.md) | 17 | 2 | 10 | 5 | -| [Accessibility and inclusion](./accessibility-and-inclusion.md) | 13 | 2 | 3 | 8 | +| [Accessibility and inclusion](./accessibility-and-inclusion.md) | 14 | 3 | 3 | 8 | | [Capitalization and punctuation](./capitalization-and-punctuation.md) | 11 | 2 | 6 | 3 | | [Formatting](./formatting.md) | 13 | 2 | 0 | 11 | | [Numbers, units, and dates](./numbers-units-and-dates.md) | 5 | 1 | 4 | 0 | -| **Total** | 80 | 9 | 25 | 46 | +| **Total** | 81 | 10 | 25 | 46 | Every column counts rule sections, not linter rule names. A rule section is a heading that carries an enforcement footer, the italic line that names the section's enforcement status. diff --git a/docs/.style/style-guide/accessibility-and-inclusion.md b/docs/.style/style-guide/accessibility-and-inclusion.md index 60379b51fb..8104b6bcbc 100644 --- a/docs/.style/style-guide/accessibility-and-inclusion.md +++ b/docs/.style/style-guide/accessibility-and-inclusion.md @@ -3,7 +3,7 @@ The Coder documentation aims for [WCAG 2.1](https://www.w3.org/TR/WCAG21/) Level AA conformance as a minimum, with Level AAA conformance wherever it doesn't sacrifice clarity. The rules on this page support that target. They cover heading structure, inclusive language, link text, and images. -They also cover plain English for international readers, page descriptions, and reading level. +They also cover plain English for international readers, abbreviations, page descriptions, and reading level. > [!NOTE] > Color contrast and other rendered-output accessibility concerns belong to the docs site theme, not to prose conventions. @@ -344,6 +344,47 @@ Restricting them burdens writers without a matching gain for readers familiar wi *Documentation-only. No Vale rule.* +## Expand abbreviations on first use + +Spell out an abbreviation the first time it appears on a page, followed by the abbreviation in parentheses: "Model Context Protocol (MCP)." +After that, use the abbreviation on its own. +Each page needs its own expansion, because readers arrive on a page from search or a link and don't read the docs in order. + +The rule supports [WCAG 2.2 Level AAA](https://www.w3.org/TR/WCAG22/#abbreviations) Success Criterion 3.1.4 (Abbreviations), which asks for a way to find the expanded form of an abbreviation. +It also helps readers whose first language isn't English, and readers who know the concept but not its abbreviation. + +**Do**: + +> Register a Model Context Protocol (MCP) server for your organization. +> Each MCP server provides additional tools to the agent. + +**Don't**: + +> Register an MCP server for your organization. +> Each MCP server provides additional tools to the agent. + +Write the expansion in lowercase unless it's a proper noun, such as a product, protocol, or standard name: "virtual machine (VM)" but "OpenID Connect (OIDC)." +For a plural, add `s` to both forms: "virtual machines (VMs)." + +When the first use is a UI label in bold, keep the label exactly as the UI shows it and put the expansion elsewhere in the same paragraph or list item. + +**Do**: + +> Paste the path to the certificate authority (CA) certificate in **CA Path**. + +**Don't**: + +> Paste the path to the certificate in **certificate authority (CA) Path**. + +A few abbreviations are familiar enough to every reader of the Coder docs that they don't need an expansion, such as API, CLI, URL, SSH, and JSON. +The `Coder.AbbreviationFirstUse` rule keeps that list, with the reason for each entry. +Extend the list only for an abbreviation that every reader of the docs already knows, not for one that a page's expected audience knows. + +The rule skips headings, code, link URLs, and pages generated from source code. +An abbreviation in a page title still needs its expansion in the body of the page. + +*Enforced by `Coder.AbbreviationFirstUse`.* + ## Page title and sidebar title A page's H1 and its sidebar title serve different jobs and may diverge. diff --git a/docs/.style/styles/Coder/AbbreviationFirstUse.yml b/docs/.style/styles/Coder/AbbreviationFirstUse.yml new file mode 100644 index 0000000000..6f1af6f341 --- /dev/null +++ b/docs/.style/styles/Coder/AbbreviationFirstUse.yml @@ -0,0 +1,136 @@ +# Coder.AbbreviationFirstUse - require an abbreviation to be expanded on its +# first use on a page, in the form "Expanded Form (ABBR)". +# +# The policy supports WCAG 2.2 Level AAA Success Criterion 3.1.4 +# (Abbreviations) and lives in the style guide: +# docs/.style/style-guide/accessibility-and-inclusion.md#expand-abbreviations-on-first-use +# +# Implementation: a conditional rule. Vale collects every abbreviation that +# `second` captures inside parentheses after a word, then reports each `first` +# match that hasn't been captured yet. The captures accumulate across the +# page's blocks in document order, so an expansion later on the page doesn't +# cover an earlier use. Inside one paragraph, list item, or table cell, an +# expansion anywhere in the block covers every use in it. +# +# An abbreviation is 2 to 6 capitals, each optionally followed by digits +# (`EC2`, `P2P`). A plural `s` is matched but not reported, so `VMs` counts as +# a use of `VM` and "virtual machines (VMs)" expands it. `second` also accepts +# a pair joined by a slash or a space, as in "(CI/CD)" and "(PCI DSS)". +# +# Scope: everything except headings. A page title often names the +# abbreviation that the first paragraph then expands. Vale already skips +# front matter, code blocks, inline code, and link URLs. +# +# The rule checks that an expansion exists, not that it's correct: any word +# before the parentheses satisfies it. +# +# Generated pages are excluded in .vale.ini. +# +# Level: warning. Whether an abbreviation is familiar enough to skip is a +# judgment call, and the exceptions list records those calls. +extends: conditional +message: "Expand '%s' on its first use on the page, in the form 'Expanded Form (ABBR)'. Refer to accessibility-and-inclusion.md#expand-abbreviations-on-first-use." +link: https://github.com/coder/coder/blob/main/docs/.style/style-guide/accessibility-and-inclusion.md#expand-abbreviations-on-first-use +level: warning +scope: ~heading +ignorecase: false +first: '\b(?:[A-Z][0-9]*){2,6}(?=s?\b)' +second: '[\w-]+ \(((?:[A-Z][0-9]*){2,6})s?(?:[/ ]((?:[A-Z][0-9]*){2,6})s?)?\)' +exceptions: + # Abbreviations every reader of these docs already knows. + - AI + - API + - AWS + - CLI + - CPU + - DNS + - GCP + - HTTPS? + - ID + - IDE + - IP + - JSON + - OS + - PR + - RAM + - SQL + - SSH + - TLS + - UI + - URL + - YAML + # Units, clock times, and file and package formats, which readers know by + # the abbreviation rather than by the expansion. + - GB + - KB + - MB + - AM + - PM + - CSV + - GIF + - JPEG + - PDF + - PNG + - RPM + - SVG + - VSIX + - ZIP + # Not abbreviations: alert labels, file names, emphasis and keywords in + # capitals, HTTP methods, SQL keywords, SMTP authentication mechanisms, + # control characters, rule labels, RFC numbers, and TL;DR. + - NOTE + - TIP + - OK + - README + - SKILL + - ALL + - AND + - ANY + - ERROR + - MUST + - NOT + - 'ON' + - OR + - DELETE + - GET + - POST + - PUT + - ILIKE + - VACUUM + - LOGIN + - PLAIN + - NUL + - CRON + - TERM + - DOCS + - DOC\d+ + - RFC\d+ + - TL + - DR + # Names written in capitals, where the capitals are the name: VS Code, + # IntelliJ IDEA and its IU product code, NGINX, SUSE, GNU, Xfce, DX, IBM, + # Amazon DCV, Emacs TRAMP, MSYS2, .NET, Open VSX, Arm, GPT models, and + # cryptographic algorithms. + - VS + - IDEA + - IU + - NGINX + - SUSE + - GNU + - XFCE + - DX + - IBM + - DCV + - TRAMP + - MSYS2 + - NET + - VSX + - ARM + - GPT + - AES + - GCM + - HMAC + - HS256 + - RSA + - SHA + - SHA256