Shared spelling tools

Updated Aug 02, 2026

Run make spelling in this checkout to generate and validate the estate-wide en-GB-oxendict configuration. The command uses the tracked shared base in data/typos-oxendict-base.toml, merges repository-only exceptions from typos.local.toml, writes generated typos.toml, and checks the repository with the pinned typos version. It also rejects curated punctuation-separated phrases that typos cannot treat as one word, reporting the canonical replacement.

Consumer repositories use the same generation model. Their generator fetches the shared base into ignored .typos-oxendict-base.toml and records freshness metadata in .typos-oxendict-base.json. A valid cache supports offline runs; the tracked typos.toml remains deterministic and reviewable.

Cache metadata is scoped to the exact authority that supplied it. A stale cache or HTTP 304 Not Modified response is accepted only when the metadata names the requested source and the cached dictionary still validates. Switching local paths or HTTPS URLs therefore forces a refresh without reusing another authority's validators. Refresh decisions are available through standard Python logging with bounded operation, source-kind, error-class and decision fields; logs do not contain authority URLs or local paths.

The rollout CLI exposes the underlying operations:

uv run --script scripts/typos_rollout_cli.py generate --repository .
uv run --script scripts/typos_rollout_cli.py check --repository .
uv run --script scripts/typos_rollout_cli.py harvest ../project

generate accepts a local path or HTTP URL with --source, and --offline requires an existing valid cache. check applies curated exact phrase corrections to tracked text while respecting the merged ignore and exclusion policy. harvest emits JSON Lines evidence for Oxford -ize and plain-British -ise candidates in Git-tracked UTF-8 text. Generic spellings belong in the shared base; product names, quoted upstream terms, and deliberate fixtures belong in a consumer's typos.local.toml.

Ignore expressions are validated before scanning. Malformed expressions, backreferences, and nested or adjacent repetitions are rejected, including Python's {,n} upper-bound form; separated bounded repetitions remain valid. Phrase checking and harvesting skip tracked files that are not UTF-8. Other tracked-file read failures stop the operation and emit a bounded diagnostic, so an incomplete repository scan cannot appear successful.