diff --git a/_layouts/docs.liquid b/_layouts/docs.liquid
index 4a6c8753e..407351b6a 100644
--- a/_layouts/docs.liquid
+++ b/_layouts/docs.liquid
@@ -63,7 +63,7 @@ editable: true
{%- if google %}
- Portions of this page are reproduced from work
+ Portions of this page are adapted from work
{
const problems: string[] = [];
- const colon = subject.indexOf(IDEOGRAPHIC_COLON);
+ const colon = subject.indexOf(FULLWIDTH_COLON);
if (colon === -1) {
problems.push(
- `subject needs an emoji prefix and “${IDEOGRAPHIC_COLON}” (U+FF1A), as in “🏗️🔧${IDEOGRAPHIC_COLON}fix the thing”`
+ `subject needs an emoji prefix and “${FULLWIDTH_COLON}” (U+FF1A), as in “🏗️🔧${FULLWIDTH_COLON}fix the thing”`
);
} else {
const prefix = subject.slice(0, colon);
- const description = subject.slice(colon + IDEOGRAPHIC_COLON.length);
+ const description = subject.slice(colon + FULLWIDTH_COLON.length);
// The variation selector belongs to the character before it, so the
// prefix has to be read as grapheme clusters and not code points.
const clusters = [...SEGMENTER.segment(prefix)].map(
diff --git a/build/shared/commit-message.test.mts b/build/shared/commit-message.test.mts
index 639a6a423..25bfd3043 100644
--- a/build/shared/commit-message.test.mts
+++ b/build/shared/commit-message.test.mts
@@ -34,7 +34,7 @@ describe('validateCommitMessage: the subject', () => {
deepStrictEqual(validateCommitMessage('📖:write it down'), []);
});
- test('wants the ideographic colon', () => {
+ test('wants the fullwidth colon', () => {
match(soleProblem('🏗️🔧: fix the thing'), /U\+FF1A/);
});
diff --git a/collections/_docs/README.md b/collections/_docs/README.md
index a6bb29b0b..4126e9439 100644
--- a/collections/_docs/README.md
+++ b/collections/_docs/README.md
@@ -16,7 +16,7 @@
-### Install Dependencies
+### Install dependencies
@@ -29,7 +29,7 @@ pnpm install
-### Running Locally
+### Running locally
One can preview contributions before opening a pull request.
diff --git a/collections/_docs/agent-forwarding.md b/collections/_docs/agent-forwarding.md
index 3e12ee428..33942c9f8 100644
--- a/collections/_docs/agent-forwarding.md
+++ b/collections/_docs/agent-forwarding.md
@@ -16,7 +16,7 @@ works today and what to do when it doesn't.
The devcontainer changed substantially in [#1775][]: it no longer runs its own
`sshd` on a forwarded port, and there is no more `vscode` user or manual
`RemoteForward` tunnel to configure. Everything below reflects that container.
-If you find instructions elsewhere -- including an old revision of this file --
+If you find instructions elsewhere — including an old revision of this file —
mentioning port 2222 or a `gpgtunnel` SSH host, they predate that change and no
longer apply.
@@ -25,7 +25,7 @@ longer apply.
VS Code (and compatible tools like the Dev Containers CLI) forwards your
_running_ SSH agent into the container automatically; no devcontainer.json
configuration is required for it. What it does **not** do is copy any key
-material in -- not the private key, and, for SSH-format signing, not even the
+material in — not the private key, and, for SSH-format signing, not even the
public key file. See VS Code's own docs on [sharing Git credentials][] for the
authoritative description.
@@ -39,7 +39,7 @@ That gap matters because of how the two signing formats differ:
`ssh-keygen -Y sign -f ...`. That `-f` argument is a **file
path**, and `user.signingkey` in a gitconfig copied from your host points at a
host path (typically `~/.ssh/id_ed25519.pub`) that has never existed in the
- container. The forwarded agent doesn't help until that file exists -- and the
+ container. The forwarded agent doesn't help until that file exists — and the
container's non-root user usually can't even create it: a Mac's `/Users/`
or a Linux host's `/home/` both live under a root-owned directory this
container's `node` user has no write access to, so recreating the host's path
@@ -47,14 +47,14 @@ That gap matters because of how the two signing formats differ:
`.devcontainer/post-start.sh` closes that second gap. It runs on every container
**start/attach**, unlike `post-create.sh`, which only ever runs once, when the
-container is first built -- too early, since the forwarded agent socket is a
+container is first built — too early, since the forwarded agent socket is a
fresh, per-session thing set up on each attach. If `gpg.format` is `ssh` and the
forwarded agent is holding exactly one identity, `post-start.sh` writes that
public key to a path under `$HOME/.ssh` in the container (not the host path
copied into `user.signingkey`) and repoints the container's own
`user.signingkey` at it. It deliberately does nothing if the agent has zero
identities (nothing to write) or more than one (no reliable way to know which
-one you mean) -- watch its output on attach to see which case you're in.
+one you mean) — watch its output on attach to see which case you're in.
Either way, the actual cryptographic signing still happens on the host, via the
forwarded agent. No private key material is ever copied into the container.
@@ -86,7 +86,7 @@ and involves nothing on your machine.
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
```
-- Point Git at it. Run this **on the host**, in a host terminal -- the container
+- Point Git at it. Run this **on the host**, in a host terminal — the container
gets its own copy of `~/.gitconfig` at build time, so running it inside the
container configures only the container and silently leaves the Mac unchanged:
@@ -99,14 +99,14 @@ and involves nothing on your machine.
- Reopen or rebuild the devcontainer and watch `post-start.sh`'s output on
attach. `Commit signing ready` means the public key was found in the forwarded
agent and written into the container. Anything else means the agent forwarded
- into _this_ session doesn't have exactly one identity -- check `ssh-add -l` on
+ into _this_ session doesn't have exactly one identity — check `ssh-add -l` on
the host first.
Use an ordinary `ssh-keygen`-generated key pair here. Keys that exist only
inside a Secure Enclave or an external agent, with no public key file on disk,
are a poor fit: `user.signingkey` has to name a real path on the host, and
`post-start.sh` needs a public key it can write out in the container. The two
-paths don't need to match -- `post-start.sh` retargets the container's own copy
+paths don't need to match — `post-start.sh` retargets the container's own copy
of `user.signingkey` to wherever it actually writes the file, under
`$HOME/.ssh`.
@@ -128,7 +128,7 @@ to verify it, which is a separate mechanism that can fail on its own. See
## Verifying signatures locally
Verification is a distinct mechanism from signing, with its own configuration
-and its own failure modes -- a commit can be perfectly signed and still fail to
+and its own failure modes — a commit can be perfectly signed and still fail to
verify here. For SSH-format signatures, Git needs an [allowed signers][] file
mapping each principal (an email address) to the keys it may sign with. Unlike
GPG, where the keyring is discovered automatically, Git has no default location
@@ -150,7 +150,7 @@ Two things it deliberately does not attempt:
to this address. That makes local verification meaningful for catching a
misconfigured or swapped key; it is not third-party attestation the way
GitHub's "Verified" badge is. GitHub does its own check against the keys
- registered on your account -- see its docs on [commit signature
+ registered on your account — see its docs on [commit signature
verification][], and note that a key has to be added as a **signing** key
there, separately from the same key added for authentication.
@@ -165,7 +165,7 @@ error: gpg.ssh.allowedSignersFile needs to be configured and exist
No signature
```
-`No signature` here is the verifier reporting that it could not run -- not a
+`No signature` here is the verifier reporting that it could not run — not a
statement about the commit, which may well be signed. The wording invites the
opposite reading, and acting on it means re-checking `commit.gpgsign`,
`user.signingkey` and the agent, all of which were fine. Confirm with
@@ -193,9 +193,9 @@ If you use an actual OpenPGP key instead:
## Troubleshooting
-- **`ssh-add -l` says "The agent has no identities"** -- this is a host-side
+- **`ssh-add -l` says "The agent has no identities"** — this is a host-side
fact, not a container problem. Add the key on the host and reattach.
-- **`post-start.sh` reports more than one identity** -- it won't guess. Either
+- **`post-start.sh` reports more than one identity** — it won't guess. Either
unload the extra identities from the agent for this session, or, inside the
container, write the file yourself from the one you mean, then point
`user.signingkey` at it:
@@ -205,14 +205,14 @@ If you use an actual OpenPGP key instead:
git config --global user.signingkey ~/.ssh/id_ed25519.pub
```
-- **It worked before, stopped working after a container rebuild** -- the signing
+- **It worked before, stopped working after a container rebuild** — the signing
key and `allowed_signers` files `post-start.sh` writes, and the
`user.signingkey`/`gpg.ssh.allowedSignersFile` overrides pointing at them, all
live in the container's filesystem, not a volume, so a rebuild removes them
along with the host's copied-in gitconfig. Everything gets rewritten on the
next attach as long as the agent still has exactly one identity at that point.
- **`post-start.sh` says "Signature verification NOT configured: no
- user.email"** -- it needs `user.email` to know which principal to list against
+ user.email"** — it needs `user.email` to know which principal to list against
your key in `allowed_signers`, and won't guess one. Set it (globally, on the
host, same as the other signing settings) and reattach:
@@ -220,12 +220,12 @@ If you use an actual OpenPGP key instead:
git config --global user.email you@example.com
```
-- **`git log --show-signature` says `No signature`** -- establish that the
- commit is actually unsigned before treating it as a signing problem, since
- that message is also what a verifier that could not run prints.
+- **`git log --show-signature` says `No signature`** — establish that the commit
+ is actually unsigned before treating it as a signing problem, since that
+ message is also what a verifier that could not run prints.
`git cat-file commit HEAD` settles it; see
[above](#when-show-signature-says-no-signature).
-- **Everything looks configured, but commits still come out unsigned** -- check
+- **Everything looks configured, but commits still come out unsigned** — check
for a per-repository override before re-checking anything global:
```console
diff --git a/collections/_docs/handbook/style/capitalization.md b/collections/_docs/handbook/style/capitalization.md
index e3296f53d..65312509c 100644
--- a/collections/_docs/handbook/style/capitalization.md
+++ b/collections/_docs/handbook/style/capitalization.md
@@ -1,14 +1,113 @@
---
title: Capitalization
key_point: When to capitalize, and when to leave a word lowercase.
-stub: true
---
-> [!NOTE]
->
-> This page is a placeholder. It is linked from elsewhere in the handbook and is
-> yet to be written.
+Capitalize a name. Leave everything else alone. Most disagreements about
+capitalization are really disagreements about whether a thing is a name, and
+answering that question settles the spelling.
+
+A capital letter is a claim that a word is the name of one particular thing.
+Applying it to an ordinary noun — a feature, a format, a role — asks the reader
+to look for a proper noun that is not there.
## Capitalization in headings
-Yet to be written.
+A page title is set in title case, capitalizing the first word, the last word,
+and everything between them except articles, coordinating conjunctions, and
+prepositions.
+
+
+ Recommended: Documenting Command-Line
+ Syntax
+
+
+ Not recommended: Documenting command-line
+ syntax
+
+
+The exceptions are what the rule turns on. A preposition in the middle of a
+title stays lowercase however long the title is:
+
+
+ Recommended: Code in Text
+
+
+ Not recommended: Code In Text
+
+
+A heading inside a page is set in sentence case: the first word capitalized, and
+after that only what would be capitalized in running text.
+
+
+ Recommended: Explaining placeholders
+
+
+ Not recommended: Explaining Placeholders
+
+
+An adapted page follows these rules too. A page that carries an attribution line
+says where its wording came from, not whose house style it is set in, and a
+reader moving between pages should not be able to tell which is which from the
+headings.
+
+## The name of the project
+
+The project is **OpenINF**. One capital at the front for _Open_, three at the
+back for _INF_, and nothing else.
+
+
+ Recommended: OpenINF
+
+
+ Not recommended: OPENINF, Openinf, openINF
+
+
+Setting the name in full capitals is shouting it, and a name that shouts in
+running text is a name the reader learns to skip. This holds in headings, in
+navigation, and in the small print at the foot of a page — nowhere is it
+`OPENINF`.
+
+The scope on npm is lowercase, because npm scopes are lowercase: `@openinf`.
+Write a package name exactly as it is published, in code font, and never
+capitalize it to start a sentence. Rewrite the sentence instead.
+
+
+ Recommended: The
+ @openinf/util-types package has no dependencies.
+
+
+ Not recommended:
+ @openinf/util-types has no dependencies.
+
+
+## Words that only look like names
+
+Technologies, formats, and general concepts are ordinary nouns. They take a
+capital only where a name is embedded in them.
+
+| Write | Not |
+| :------------------- | :------------------- |
+| open source | Open Source |
+| the web | the Web |
+| the internet | the Internet |
+| a pull request | a Pull Request |
+| the command line | the Command Line |
+| JavaScript, npm, Git | Javascript, NPM, git |
+
+The last row is the exception that proves the rule: those three are names, and
+each has one correct spelling that is neither all lowercase nor all capitals.
+
+## After a colon
+
+A colon does not start a new sentence, so what follows it is capitalized only if
+it would be capitalized anywhere else. See [Colons][] for when the colon is the
+right mark at all.
+
+
+
+
+[Colons]: https://open.inf.is/docs/handbook/style/colons/
+
+
+
diff --git a/collections/_docs/handbook/style/code-in-text.md b/collections/_docs/handbook/style/code-in-text.md
index 74a57eb1e..11b9de967 100644
--- a/collections/_docs/handbook/style/code-in-text.md
+++ b/collections/_docs/handbook/style/code-in-text.md
@@ -1,18 +1,94 @@
---
title: Code in Text
key_point: What to set in code font, and how to explain placeholders.
-stub: true
---
-> [!NOTE]
->
-> This page is a placeholder. The sections below are linked from elsewhere in
-> the handbook and are yet to be written.
+Code font marks text the computer reads as-is. It tells the reader that what is
+between the marks is to be typed, or found, exactly as written — that the
+capitalization matters, the underscore is really there, and the plural `s` is
+not part of it.
+
+Use it for what the machine reads. Do not use it for emphasis; that is what
+**bold** is for, and a reader who has learned that code font means _literal_ is
+misled every time it means _important_.
+
+## Some specific items to put in code font
+
+| Item | Example |
+| :----------------------- | :---------------------------------- |
+| File and directory names | `eleventy.config.mjs`, `_includes/` |
+| Commands and flags | `pnpm install`, `--frozen-lockfile` |
+| Package and scope names | `@openinf/util-types` |
+| Identifiers in code | `replaceInlineSvg`, `$utilities` |
+| Literal values | `true`, `null`, `0`, `"production"` |
+| Environment variables | `ELEVENTY_ENV` |
+| HTML elements | ``, `` |
+| Selectors and classes | `.doc-prose`, `#sidebar-toggle` |
+| Git refs and trailers | `live`, `Signed-off-by` |
+
+Leave in ordinary text the things that are names of concepts rather than strings
+to be typed: a pull request, the commit queue, the style handbook.
+
+
+ Recommended: Run nps test
+ before opening a pull request.
+
+
+ Not recommended: Run nps test
+ before opening a pull request.
+
+
+A trailing punctuation mark belongs outside the code font unless the mark is
+part of the thing being named.
+
+
+ Recommended: The config lives in
+ eleventy.config.mjs.
+
+
+ Not recommended: The config lives in
+ eleventy.config.mjs.
+
## Explaining placeholders
-Yet to be written.
+A placeholder stands where the reader supplies a value of their own. Mark it
+with the `` element so it is visibly not a literal, and give it a name that
+says what kind of value belongs there.
-## Some specific items to put in code font
+
+ Recommended:
+ gh pr view number
+
+
+ Not recommended:
+ gh pr view NUMBER
+
+
+Then say what to put there. A placeholder the reader has to guess at is worse
+than no placeholder, because it looks like it has already been explained.
+
+Explain it in the sentence that introduces the sample, or in a list directly
+after it, naming each placeholder in the order shown:
+
+
+ Recommended: Replace
+ number with the pull request's number, which
+ gh pr list prints.
+
+
+Do not explain a placeholder whose name already answers the question.
+number in a command that plainly takes a pull request needs no
+sentence of its own; ref does, because a reader cannot tell whether
+it wants a branch, a tag, or a commit.
+
+For how placeholders are set in command-line syntax specifically — including
+optional and repeated arguments — see [Documenting Command-Line Syntax][].
+
+
+
+
+[Documenting Command-Line Syntax]: https://open.inf.is/docs/handbook/style/code-syntax/
-Yet to be written.
+
+
diff --git a/collections/_docs/handbook/style/code-samples.md b/collections/_docs/handbook/style/code-samples.md
index bb58d5b1b..2baf97410 100644
--- a/collections/_docs/handbook/style/code-samples.md
+++ b/collections/_docs/handbook/style/code-samples.md
@@ -1,14 +1,88 @@
---
title: Code Samples
key_point: How to introduce and present a code sample.
-stub: true
---
-> [!NOTE]
->
-> This page is a placeholder. The section below is linked from elsewhere in the
-> handbook and is yet to be written.
+A sample is read by someone about to run it. Show what they should type, show
+what they should expect back, and leave out everything they would have to undo.
## Intros
-Yet to be written.
+Introduce a sample with a complete sentence ending in a colon, saying what the
+sample does rather than that it exists:
+
+
+ Recommended: Compare the vendored copy
+ against what upstream serves:
+
+
+ Not recommended: Example:
+
+
+ Not recommended: Run the following command:
+
+
+The second says nothing the reader cannot see. The third describes the shape of
+the page instead of the work.
+
+Where the sample is the object of the introducing sentence, no colon is needed
+and none should be added:
+
+
+ Recommended: The queue is triggered by
+ applying the 🚀 Status: Commit Queue label.
+
+
+## Show the command, not the ceremony
+
+Give the shortest sample that actually works. Leave out flags that repeat a
+default, directory changes the reader does not need, and output that carries no
+information.
+
+
+ Recommended:
+ pnpm install
+
+
+ Not recommended:
+ cd ~/projects && pnpm install --silent=false
+
+
+Every line the reader has to skip is a line they might instead run.
+
+## Prompts
+
+A shell prompt marks which lines are typed and which are output. Which lines
+carry a `$` is settled by [Documenting Command-Line Syntax][], which owns that
+rule: every line of a multi-line input, optional on a lone command, and
+consistent across a page that mixes the two.
+
+Nothing here argues with that, because on this site the prompt costs the reader
+nothing. It is set in a `` styled `user-select: none`, so
+selecting the line copies the command and leaves the `$` behind. Where a prompt
+cannot be marked up that way, a reader who has to strip it after pasting is
+better served without it.
+
+Never show a root prompt (`#`) for something that does not need root.
+
+## Placeholders and long lines
+
+Set a value the reader supplies in a `` element and say what belongs there
+— see [Explaining placeholders][].
+
+Keep lines short enough not to wrap. A wrapped command reads as two commands,
+and the reader cannot tell where the break was ours and where it was theirs. If
+a command genuinely cannot fit, break it at a point the shell accepts and say so
+in the sentence above it.
+
+For the notation used to show optional and repeated arguments, see [Documenting
+Command-Line Syntax][].
+
+
+
+
+[Explaining placeholders]: https://open.inf.is/docs/handbook/style/code-in-text/#explaining-placeholders
+[Documenting Command-Line Syntax]: https://open.inf.is/docs/handbook/style/code-syntax/
+
+
+
diff --git a/collections/_docs/handbook/style/code-syntax.md b/collections/_docs/handbook/style/code-syntax.md
index f17f55905..18e981772 100644
--- a/collections/_docs/handbook/style/code-syntax.md
+++ b/collections/_docs/handbook/style/code-syntax.md
@@ -11,12 +11,18 @@ command, the reader replaces the placeholder with an actual value.)
### Example
-Recommended: `infuse source repos clone default local-directory-name`
+
+ Recommended:
+ infuse source repos clone default
+ local-directory-name
+
For information about how to discuss placeholders in procedure steps, see
[Explaining placeholders][].
-## Command-Line Syntax
+## Command-line syntax
Here's how to document command-line commands and their arguments.
@@ -27,8 +33,8 @@ line of input with the `$` prompt symbol.
Don't show the current directory path before the prompt, even if part of the
instruction includes changing directories. However, if the overall context of
-the command interface changes—such as from the local machine to a remote
-machine—then add an additional prompt indicator, as appropriate, for the new
+the command interface changes — such as from the local machine to a remote
+machine — then add an additional prompt indicator, as appropriate, for the new
context.
**Examples**
@@ -75,7 +81,9 @@ cat ~/.ssh/my-ssh-key.pub
The terminal shows your public key in the following form:
-ssh-rsa \[KEY-VALUE] \[USERNAME]
+```console
+ssh-rsa [KEY-VALUE] [USERNAME]
+```
### Required items (commands, arguments, etc.)
@@ -84,9 +92,15 @@ likely to be in code font.
**Examples**
-Recommended: `infuse compute project-info describe`
+
+ Recommended:
+ infuse compute project-info describe
+
-Recommended: `infuse alpha functions get-logs function-name`
+
+ Recommended:
+ infuse alpha functions get-logs function-name
+
In these examples, all words and arguments are required.
@@ -99,36 +113,43 @@ square brackets.
**Example**
-Recommended: `infuse dns group [global-flag] [filename]`
+
+ Recommended:
+ infuse dns group [global-flag]
+ [filename]
+
-In this example, group is required but global-flag and filename are optional.
+Here group is required, and global-flag and
+filename are not.
### Mutually exclusive arguments
Use braces (also known as _curly braces_) to indicate that the user must choose
-one—and only one—of the items inside the braces. Use vertical bars (also known
-as _pipes_) to separate the items. There can be more than two mutually exclusive
-choices, separated from each other by pipes.
+one — and only one — of the items inside the braces. Use vertical bars (also
+known as _pipes_) to separate the items. There can be more than two mutually
+exclusive choices, separated from each other by pipes.
**Examples**
-- Recommended: `{file1|file2}`
-
- In this example, choose either file1 or file2.
-
-
+
+ Recommended:
+ {file-1|file-2}
+
-- Recommended:
- `{**--source** cloud-source **--source-url** source-url | **--bucket** bucket`
+Name one of the two, and not both.
- In this example, there are also two options:
+
+ Recommended:
+ infuse functions deploy {--source repository|--bucket
+ bucket}
+
- - Left side of pipe: If the source code is deployed from a cloud repository,
- **--source** `cloud-source` **--source-url** `source-url` is required.
- - Right side of pipe: If the source code is in a local directory:
- - **--bucket** `bucket` is required.
- - **--source** `local-source` is optional, as specified by the square
- brackets.
+The braces make the pair required and the pipe admits only one of them, so a
+deployment names either a repository or a bucket, never the two together.
### Arguments that can repeat
@@ -137,7 +158,10 @@ the argument.
**Example**
-Recommended: `infuse dns group [global-flag ...]`
+
+ Recommended:
+ infuse dns group [global-flag ...]
+
In this example, the user can specify multiple instances of the optional
parameter global-flag.
diff --git a/collections/_docs/handbook/style/colons.md b/collections/_docs/handbook/style/colons.md
index c7bf56abc..2fa387402 100644
--- a/collections/_docs/handbook/style/colons.md
+++ b/collections/_docs/handbook/style/colons.md
@@ -1,10 +1,10 @@
---
title: Colons
-key_point: A colon indicates that closely-related information follows.
+key_point: A colon indicates that closely related information follows.
google: true
---
-## Introductory Phrase Preceding Colon
+## Introductory phrase preceding colon
When a colon introduces a list, the text that precedes the colon _**should**
ordinarily_ be able to stand alone as a complete sentence.
@@ -19,34 +19,50 @@ ordinarily_ be able to stand alone as a complete sentence.
Not recommended: The fields are:
-## Proper Etiquette for Use of Japanese Colon
+## The Japanese colon in commit subjects
-We at OpenINF are always interested in finding ways to optimize things and be
-more efficient. One particular use case of **[the Japanese colon][]** that we
-have picked-up is in its placement immediately after the _**[Classification][]**
-portion_ in the titles of commit messages written sure to be abiding by our
-commit message format and style guidelines.
+A commit subject separates its **[Classification][]** from the rest with **[the
+Japanese colon][]** — `:`, the fullwidth colon at U+FF1A — rather than with the
+ASCII one.
-Rather than using an ordinary colon from the ANSI, ASCII, or Unicode character
-sets, we use the Japanese colon as it is both less size (in memory) and can
-accomplish the task of both a colon character and the subsequent space all at
-once.
+
+ Recommended:
+ 🏗️🔧:let the glob see dot files — U+FF1A, nothing after it
+
+
+ Not recommended:
+ 🏗️🔧: let the glob see dot files — U+003A and a space
+
+
+Those two lines are within a few pixels of each other on screen, which is the
+whole difficulty: the mark is one to copy rather than to type.
+`nps verify.commits` refuses a subject that lacks it, so a colon typed by hand
+fails the pull request rather than landing.
+
+The mark is as wide as the emoji in front of it and carries its own trailing
+space, which is why nothing follows it. An ASCII colon is narrow enough that the
+emoji crowds the first word, and the space that would fix the crowding spends
+one of the fifty characters a subject is allowed.
+
+It is not chosen for size. `:` takes three bytes in UTF-8 where a colon and a
+space take two. What it buys is a subject that reads at the same width as the
+emoji beside it, in a terminal and on a page alike.
-## Bold and Italic Text Preceding Colons
+## Bold and italic text preceding colons
When _non-italic_ (also known as _Roman_) text (that precedes a colon is
**bold**), the colon _should **not**_ be made _bold_, _italic_, or _otherwise_
(e.g., _color-stylized_, etc.). This, however, _is **not**_ a hard and fast
rule. In general, use _best intuition_.
-## Code Text Preceding Colons
+## Code text preceding colons
When text that precedes a colon is tagged as ``, don't include the colon
in the **``** tagging **_unless_** it is _already_ part of the code
itself. For more information about formatting code, see **[Some specific items
to put in code font][]**.
-## Colons Within Sentences
+## Colons within sentences
In general, the first word in the text that follows a colon should be in
lowercase. For exceptions, see **[capitalization][]**.
@@ -64,7 +80,7 @@ lowercase. For exceptions, see **[capitalization][]**.
work, and request a developmental edit if you feel it's warranted.
-## See Also
+## See also
For more information about how to punctuate introductory material, see the
sections on [list introductions][] and [code-sample introductions][].
@@ -80,7 +96,7 @@ For information about when it's better to use colons than dashes, see
[Classification]: https://open.inf.is/docs/handbook/style/commit-messages/#classification
[list introductions]: https://open.inf.is/docs/handbook/style/lists/#intros
[code-sample introductions]: https://open.inf.is/docs/handbook/style/code-samples/#intros
-[Dashes]: https://open.inf.is/docs/handbook/style/dashes/#colons
+[Dashes]: https://open.inf.is/docs/handbook/style/dashes/#when-a-colon-is-better
[the Japanese colon]: https://wikipedia.org/wiki/Japanese_punctuation#Colon
diff --git a/collections/_docs/handbook/style/commit-messages.md b/collections/_docs/handbook/style/commit-messages.md
index a7784850c..1c549441c 100644
--- a/collections/_docs/handbook/style/commit-messages.md
+++ b/collections/_docs/handbook/style/commit-messages.md
@@ -23,8 +23,8 @@ The first line names a classification and then says what the change does:
🏗️🔧:let the glob see dot files
```
-An ideographic colon, `:` (U+FF1A), separates the two. It is not the ASCII
-colon; the wide character keeps the emoji from crowding the words after it.
+A fullwidth colon, `:` (U+FF1A), separates the two. It is not the ASCII colon;
+the wide character keeps the emoji from crowding the words after it.
- At most **50 characters**, counting an emoji as the one character it looks
like.
@@ -166,7 +166,7 @@ git log -1 --format=%B | git interpret-trailers --parse
Anything that does not come back is not a trailer.
-## See Also
+## See also
For the emoji as they appear when opening a pull request, see the [pull request
template][].
diff --git a/collections/_docs/handbook/style/dashes.md b/collections/_docs/handbook/style/dashes.md
index 1c0441755..5f231f8d2 100644
--- a/collections/_docs/handbook/style/dashes.md
+++ b/collections/_docs/handbook/style/dashes.md
@@ -1,14 +1,118 @@
---
title: Dashes
key_point: Which dash to use, and how it differs from a colon.
-stub: true
---
-> [!NOTE]
->
-> This page is a placeholder. The section below is linked from elsewhere in the
-> handbook and is yet to be written.
+Three marks look alike and do different work. Pick by the job, not by which one
+the keyboard offers first.
-## Colons
+| Mark | Name | Job |
+| :--- | :------ | :---------------------------- |
+| `-` | hyphen | joins words into one modifier |
+| `–` | en dash | spans a range |
+| `—` | em dash | breaks a sentence open |
-Yet to be written.
+Write the character itself rather than an approximation. A pair of hyphens is
+not an em dash, and a reader copying the text gets the pair.
+
+
+ Recommended: The queue squashes the branch
+ — every message it carried is kept.
+
+
+ Not recommended: The queue squashes the
+ branch -- every message it carried is kept.
+
+
+## Hyphens
+
+A hyphen joins two or more words doing the work of one modifier, and only when
+they sit in front of what they describe.
+
+
+ Recommended: a command-line tool
+
+
+ Not recommended: a command line tool
+
+
+After the noun, the words go back to being separate and the hyphen goes away.
+
+
+ Recommended: the tool runs on the command
+ line
+
+
+ Not recommended: the tool runs on the
+ command-line
+
+
+An adverb ending in `-ly` is already attached to what follows it, so it takes no
+hyphen: a _newly published package_, not a _newly-published package_.
+
+## En dashes
+
+An en dash spans a range, standing in for the word _to_. It takes no spaces
+around it.
+
+
+ Recommended: Node.js 20–24
+
+
+ Not recommended: Node.js 20 - 24
+
+
+If the range is introduced by _from_ or _between_, finish the phrase with a word
+rather than a dash: _from 20 to 24_, never _from 20–24_.
+
+## Em dashes
+
+An em dash breaks a sentence open to let something in — an aside, a correction,
+a sharp turn — and then lets it close again. Set it with a space on each side.
+
+Use one where a comma is too quiet and parentheses are too polite. Use two to
+fence off an aside in the middle of a sentence, and make sure the sentence still
+reads if the fenced part is lifted out.
+
+One pair to a sentence. A second pair leaves the reader unable to tell which
+aside ended where.
+
+## When a colon is better
+
+A colon and an em dash both introduce. They differ in what the reader is
+promised.
+
+A colon promises that what follows completes what came before — a list, a
+definition, a quotation. It points ahead, and the text after it delivers exactly
+what the text before it set up.
+
+An em dash promises nothing in particular. It marks a break in the sentence and
+lets anything through: an aside, a reversal, a remark the sentence did not need.
+
+
+ Recommended: The check does one thing: it
+ compares the vendored copy against what upstream serves.
+
+
+ Not recommended: The check does one thing —
+ it compares the vendored copy against what upstream serves.
+
+
+Both are correct English there, and the colon is better, because the sentence
+before it announced that one thing was coming and the colon is the mark that
+keeps the promise.
+
+Prefer the colon whenever what follows is the thing that was just announced.
+Keep the em dash for what the sentence did not announce.
+
+When a colon introduces a list, the phrase before it stands alone as a complete
+sentence. See [Colons][] for that rule and for the fullwidth colon this project
+uses in commit subjects.
+
+
+
+
+[Colons]: https://open.inf.is/docs/handbook/style/colons/
+
+
+
diff --git a/collections/_docs/handbook/style/lists.md b/collections/_docs/handbook/style/lists.md
index fa9ab7c9a..89620c536 100644
--- a/collections/_docs/handbook/style/lists.md
+++ b/collections/_docs/handbook/style/lists.md
@@ -1,14 +1,88 @@
---
title: Lists
key_point: How to introduce and punctuate lists.
-stub: true
---
-> [!NOTE]
->
-> This page is a placeholder. The section below is linked from elsewhere in the
-> handbook and is yet to be written.
+A list is for things the reader compares or works through in turn. Prose that
+has been chopped into fragments is not a list; it is prose with the connective
+tissue removed, and the reader has to put it back.
+
+Three items make a comfortable list. Two are usually a sentence with an _and_ in
+it.
## Intros
-Yet to be written.
+Introduce a list with a complete sentence, then a colon.
+
+
+ Recommended: A landed commit carries three
+ trailers:
+
+
+ Not recommended: A landed commit carries:
+
+
+The second reads as a sentence the list has to finish, which means the reader
+cannot take any item on its own. It also breaks the moment an item is reordered
+or removed.
+
+Keep the introduction and the list in agreement about what the items are. If the
+sentence says _three trailers_, three trailers follow — not two trailers and a
+note about a third.
+
+Never introduce a list with a fragment ending in a dash, and never with no mark
+at all.
+
+## Punctuation
+
+Punctuate by what the item is, and punctuate every item in a list the same way.
+
+Start each item with a capital, unless it opens with something whose case is
+fixed: a package name, an identifier, a flag.
+
+
+ Recommended: No space after the colon.
+
+
+ Not recommended: no space after the colon
+
+
+End an item with a full stop when it carries a verb or completes a thought,
+whether it is a whole sentence or a fragment. Leave the stop off a bare term,
+and end with a colon where the item introduces a block below it.
+
+
+ Recommended: At most 50 characters,
+ counting an emoji as the one character it looks like.
+
+
+ Recommended: Leave
+ gpg.format unset, and set:
+
+
+Do not end items with semicolons, and do not put a conjunction before the last
+one. Both are attempts to make a list read as a sentence, and a list that wanted
+to be a sentence should have stayed one.
+
+## Ordered or unordered
+
+Number a list when the order is part of the meaning: steps to follow, a
+sequence, a ranking. Numbering an unordered list tells the reader that item 1
+comes before item 2 in some way, and they will look for the way.
+
+Leave a list unnumbered when the items are alternatives or members of a set,
+even a set with a natural order to it.
+
+## Nesting
+
+One level of nesting is usually one too many already. If a list needs a second,
+the items have become sections and want headings instead — see
+[Capitalization][] for how to set those.
+
+
+
+
+[Capitalization]: https://open.inf.is/docs/handbook/style/capitalization/#capitalization-in-headings
+
+
+
diff --git a/collections/_docs/handbook/style/people-person-first-language.md b/collections/_docs/handbook/style/people-person-first-language.md
index 239851a88..e7b045f23 100644
--- a/collections/_docs/handbook/style/people-person-first-language.md
+++ b/collections/_docs/handbook/style/people-person-first-language.md
@@ -3,15 +3,80 @@ title: Prefer People/Person-First Language When Appropriate
key_point:
Follow the community's own preference between person-first and identity-first
language.
-stub: true
---
-> [!NOTE]
->
-> This page is a placeholder. The rule below stands; the guidance that would
-> follow it is yet to be written.
+There are two ways to name a person and a characteristic in the same phrase.
-As linguistic prescription: prefer person-first language when the community
-prefers referring to themselves as person-first.
+Person-first puts the person before the characteristic: _a person with
+diabetes_, _a person with a disability_. It was adopted to stop a condition from
+standing in for the whole of someone.
-
+Identity-first puts the characteristic first: _a disabled person_, _an autistic
+person_. It is used by people who do not regard the characteristic as something
+attached to them, to be separated off by a preposition, but as part of who they
+are.
+
+Neither is correct everywhere. The rule is to follow the preference of the
+people being described.
+
+## Ask what the community asks for
+
+Where a community has said what it prefers, that settles it, and no amount of
+reasoning from first principles overrides it. Preferences differ between
+communities, and sometimes within one.
+
+Where the preference is genuinely unsettled or unknown, use person-first. It is
+the safer default, not the better form.
+
+Where you are writing about one person who has told you how they describe
+themselves, use their words, whatever the wider convention is.
+
+## The Deaf community
+
+The clearest case where person-first is usually not what people want. Many deaf
+people use identity-first language — _a Deaf person_, not _a person with
+deafness_ — because deafness here is a culture and a language, not a condition
+someone carries.
+
+The capital carries meaning. Written _Deaf_, it refers to that cultural and
+linguistic community; written _deaf_, it refers to hearing loss as an
+audiological fact. Someone can be deaf without being Deaf, and the distinction
+belongs to them rather than to the writer.
+
+
+ Recommended: The library ships captions
+ contributed by Deaf reviewers.
+
+
+ Not recommended: The library ships captions
+ contributed by reviewers with deafness.
+
+
+The autistic community is a second widely documented case, where identity-first
+is broadly preferred for the same reason.
+
+## What to avoid either way
+
+Neither form rescues a phrase that frames a characteristic as a misfortune.
+
+
+ Recommended: a person who uses a
+ wheelchair
+
+
+ Not recommended: a person confined to a
+ wheelchair
+
+
+Avoid _suffers from_, _afflicted with_, and _victim of_ for a characteristic
+someone lives with. Avoid euphemisms invented by people outside the community —
+_differently abled_, _special needs_ — which are rarely what the people
+described use of themselves.
+
+Do not make a characteristic into a noun that stands for a person: write _people
+with epilepsy_ or _epileptic people_ as the community prefers, rather than
+_epileptics_ — unless that is the word those people use.
+
+And do not mention a characteristic at all unless it bears on what you are
+writing. Most of the time the question of which form to use does not arise,
+because the sentence never needed the detail.
diff --git a/collections/_pages/404.html b/collections/_pages/404.html
index 7fe7cc74c..dd3142b45 100644
--- a/collections/_pages/404.html
+++ b/collections/_pages/404.html
@@ -8,7 +8,7 @@
404