Skip to content

chore: write the repo in en-US, and gate it so it stays that way - #204

Merged
doublegate merged 2 commits into
mainfrom
chore/en-us-spelling
Jul 30, 2026
Merged

chore: write the repo in en-US, and gate it so it stays that way#204
doublegate merged 2 commits into
mainfrom
chore/en-us-spelling

Conversation

@doublegate

Copy link
Copy Markdown
Owner

Motivation

The project standard is en-US. The tree had drifted to en-GB — and I made that worse: on #202 I rejected a reviewer's generalisinggeneralizing suggestion on the measured grounds that the repo was consistently en-GB (37 behaviour to 3, 41 modelled to 0). The measurement was correct; the conclusion was backwards. Consistency with a drift is not a reason to keep drifting.

The sweep

1,505 replacements across 131 files, from 51 stem-level pairs applied case-preservingly. Stems rather than whole words, so one entry covers every inflection (colour also fixes colours/coloured/colouring/colourful). Families covered: -our/-or, -ise/-ize, -isation/-ization, -re/-er, doubled -lled/-lling, plus a dozen individual words (artefact, analogue, catalogue, judgement, acknowledgement, licence, grey, …).

Touches prose, doc comments, assertion messages, and private test-function names.

Safety checks run before applying

No public item is renamed, so there is no API change. Enumerated every pub fn|struct|enum|const|static|trait|type|mod name against the stem list: zero matches. The only identifiers affected are private — three local variables (centre_r/g/b, traveled) and ~14 #[test] function names.

Check Result
Public item renamed? none — no API break
CI job or script filtering on an affected test name? none
Excluded directory citing an affected test name? none — swept and unswept text cannot desync
Verbatim external quotation altered? none — searched for quoted phrases beside a citation marker (§, UM, N64brew); the single hit was our own italic emphasis, not a quotation

Excluded trees, and why:

Tree Reason
ref-docs/ Immutable research corpus — corrections land as new dated supplemental files, never in-place rewrites (module 40)
n64brew_wiki/ CC BY-SA mirror, quoted verbatim by design
ref-proj/ Study clones of other emulators
third_party/ Vendored libdragon — not our prose to edit (it contains a whilst that stays)

Two literals preserved because they are values, not words: lightgrey in a shields.io badge URL — a color parameter, and a naive sweep would have edited it — and GitHub Actions' own cancelled run status where the CHANGELOG quotes it.

Stems deliberately left out because the form is correct in en-US too, and a stem there would corrupt a correct word: analysis, analyses (as a noun), synthesis, hypothesis, peripheral, exercise, precise, imprecise, premise, promise, otherwise, likewise, bitwise, advertise, revise, praise, controlled, installed, stalled. synthesise is handled as a whole word so synthesis survives; mis-analyses is targeted specifically because bare analyses is ambiguous between the verb and the plural noun.

The gate — scripts/check_en_us.sh + an en-US spelling CI job

A one-off sweep decays. Nothing fails when a single en-GB form returns, so it survives review and the next one has precedent. This repo already demonstrates the pattern: markdownlint runs in pre-commit only, never in CI, and an MD040 fence violation consequently sat unnoticed on main until #203 happened to catch it.

The gate is mutation-checked in both directions, which is the part that makes it evidence rather than decoration:

unswept tree → en-US check FAILED: 1355 line(s) carry an en-GB spelling.
swept tree   → en-US check passed: 443 tracked files, no en-GB spellings.

Two design details worth calling out:

  • It strips allowed literals from the line before matching rather than skipping the whole line. A line-level skip would let a permitted value shield a genuine hit sitting beside it — verified with a synthetic case (badge lightgrey and also the word colour here is still reported).
  • It offers a documented per-line spell-exempt marker for quoted external values, and says in its own header to prefer rephrasing, since every marker is a small permanent exception. This PR uses zero of them: the CHANGELOG entry was rephrased to describe the families instead of naming en-GB examples.

Wired into pre-commit as well for a faster local loop, with CI as the unskippable gate — a contributor can bypass a hook with --no-verify, not a CI job.

The CI job takes no untrusted input: actions/checkout@v7 plus one run:, no ${{ }} interpolation, and triggers unchanged (pull_request, not pull_request_target).

Gates run locally

cargo fmt --all --check · cargo clippy --workspace --all-targets -- -D warnings · cargo test --workspace · RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps · cargo build -p rustyn64-core --target thumbv7em-none-eabihf --no-default-features · pre-commit run markdownlint --all-files · check_no_roms.sh · check_en_us.sh — all green.

Note for reviewers

This is a large mechanical diff. The substantive review surface is small and worth focusing on: scripts/check_en_us.sh (the stem list, the exclusions, the two protected literals), and the ~17 lines in the table above where the sweep touched something other than prose. The remaining ~1,470 lines are single-word substitutions in comments and Markdown.

🤖 Generated with Claude Code

The project standard is en-US. The tree had drifted to en-GB -- and I made that
worse: on #202 I rejected a reviewer's generalising -> generalizing suggestion
on the measured grounds that the repo was consistently en-GB (37 "behaviour" to
3). The measurement was right and the conclusion was backwards: consistency with
a drift is not a reason to keep drifting.

1,505 replacements across 131 files, from 51 stem-level pairs applied
case-preservingly, so every inflection of a stem is covered by one entry.
Touches prose, doc comments, assertion messages, and private test-function
names.

NO public item is renamed, so there is no API change -- checked by enumerating
`pub fn|struct|enum|const|static|trait|type|mod` names against the stem list and
finding none. Also checked in advance:

- no CI job or script filters on an affected test name
- no excluded directory cites an affected test name, so swept and unswept text
  cannot desync
- no verbatim external quotation is altered (searched for quoted phrases beside
  a citation marker; the one hit was our own italic emphasis, not a quote)

Excluded trees, and why:
  ref-docs/       immutable research corpus -- corrections land as new dated
                  supplemental files, never in-place rewrites (module 40)
  n64brew_wiki/   CC BY-SA mirror, quoted verbatim by design
  ref-proj/       study clones of other emulators
  third_party/    vendored libdragon; not our prose to edit

Two literals are preserved because they are values, not words: `lightgrey` in a
shields.io badge URL (a color PARAMETER), and GitHub Actions' own `cancelled`
run status where the CHANGELOG quotes it. Stems whose form is correct in en-US
too were deliberately left out of the list -- analysis, synthesis, hypothesis,
peripheral, exercise, precise, premise, promise, otherwise, likewise, bitwise,
controlled, installed, stalled -- since a stem there would corrupt a correct
word.

Adds scripts/check_en_us.sh and an `en-US spelling` CI job, because a one-off
sweep decays: nothing fails when one en-GB form returns, so it survives review
and the next has precedent. This repo already demonstrates the pattern --
markdownlint runs in pre-commit only, and an MD040 violation sat unnoticed on
main until #203. The gate is mutation-checked in BOTH directions (fails on the
unswept tree at 1,355 lines, passes on the swept one at 443 files), strips
allowed literals rather than skipping their whole line so a permitted value
cannot shield a real hit beside it, and documents a per-line `spell-exempt`
escape hatch. Also wired into pre-commit for a faster local loop, with CI as the
unskippable gate.

Gates: fmt, clippy -D warnings, cargo test --workspace, rustdoc -D warnings,
no_std thumbv7em, markdownlint, check_no_roms, check_en_us -- all green.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@doublegate, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 38 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2d0e8125-9d14-4a7e-bdbc-ef3c984097f2

📥 Commits

Reviewing files that changed from the base of the PR and between cbf1651 and 4fd3b63.

📒 Files selected for processing (133)
  • .coderabbit.yaml
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .pre-commit-config.yaml
  • AGENTS.md
  • CHANGELOG.md
  • README.md
  • crates/rustyn64-audio/src/lib.rs
  • crates/rustyn64-cart/src/lib.rs
  • crates/rustyn64-cart/src/pi.rs
  • crates/rustyn64-cart/src/pif.rs
  • crates/rustyn64-cart/src/save.rs
  • crates/rustyn64-core/src/boot.rs
  • crates/rustyn64-core/src/bus.rs
  • crates/rustyn64-core/src/scheduler.rs
  • crates/rustyn64-core/src/vi.rs
  • crates/rustyn64-cpu/src/alu.rs
  • crates/rustyn64-cpu/src/cache.rs
  • crates/rustyn64-cpu/src/cop0.rs
  • crates/rustyn64-cpu/src/cop1.rs
  • crates/rustyn64-cpu/src/decode.rs
  • crates/rustyn64-cpu/src/exception.rs
  • crates/rustyn64-cpu/src/exec.rs
  • crates/rustyn64-cpu/src/fpr.rs
  • crates/rustyn64-cpu/src/fpu.rs
  • crates/rustyn64-cpu/src/lib.rs
  • crates/rustyn64-cpu/src/pipeline.rs
  • crates/rustyn64-cpu/src/regs.rs
  • crates/rustyn64-cpu/src/softfloat.rs
  • crates/rustyn64-cpu/src/sysad.rs
  • crates/rustyn64-cpu/src/tlb.rs
  • crates/rustyn64-frontend/Cargo.toml
  • crates/rustyn64-frontend/src/emu.rs
  • crates/rustyn64-frontend/src/romfile.rs
  • crates/rustyn64-frontend/src/savestate.rs
  • crates/rustyn64-rdp/src/command.rs
  • crates/rustyn64-rdp/src/lib.rs
  • crates/rustyn64-rsp/src/lib.rs
  • crates/rustyn64-rsp/src/sp.rs
  • crates/rustyn64-rsp/src/su.rs
  • crates/rustyn64-rsp/src/vu.rs
  • crates/rustyn64-snapshot/Cargo.toml
  • crates/rustyn64-snapshot/src/lib.rs
  • crates/rustyn64-test-harness/src/accuracy.rs
  • crates/rustyn64-test-harness/src/conformance.rs
  • crates/rustyn64-test-harness/src/rom.rs
  • crates/rustyn64-test-harness/src/runner.rs
  • crates/rustyn64-test-harness/tests/audio_play_rom.rs
  • crates/rustyn64-test-harness/tests/commercial_boot.rs
  • crates/rustyn64-test-harness/tests/composite_frame.rs
  • crates/rustyn64-test-harness/tests/determinism.rs
  • crates/rustyn64-test-harness/tests/first_rom.rs
  • crates/rustyn64-test-harness/tests/game_microcode.rs
  • crates/rustyn64-test-harness/tests/golden_frame.rs
  • crates/rustyn64-test-harness/tests/golden_log.rs
  • crates/rustyn64-test-harness/tests/microcode.rs
  • crates/rustyn64-test-harness/tests/microcode_families.rs
  • crates/rustyn64-test-harness/tests/mixer_microcode.rs
  • crates/rustyn64-test-harness/tests/rdp_conformance.rs
  • crates/rustyn64-test-harness/tests/real_rom_frame.rs
  • crates/rustyn64-test-harness/tests/savestate.rs
  • crates/rustyn64-test-harness/tests/systemtest.rs
  • crates/rustyn64-test-harness/tests/vectors/fuzz/README.md
  • crates/rustyn64-test-harness/tests/vi_conformance.rs
  • crates/rustyn64-test-harness/vectors-gen/.gitignore
  • crates/rustyn64-test-harness/vectors-gen/README.md
  • crates/rustyn64-test-harness/vectors-gen/driver.c
  • docs/DOCUMENTATION_INDEX.md
  • docs/STATUS.md
  • docs/accuracy-ledger.md
  • docs/adr/0002-lle-coprocessors.md
  • docs/adr/0004-determinism-contract.md
  • docs/adr/0005-sub-cycle-bus-timing-refactor.md
  • docs/adr/0006-one-canonical-master-clock.md
  • docs/adr/0007-cycle-accurate-vr4300-pipeline.md
  • docs/adr/0008-microcode-boot-harness.md
  • docs/adr/0009-hle-vs-real-pif-boot.md
  • docs/adr/0010-retail-boot-in-core.md
  • docs/architecture.md
  • docs/audio.md
  • docs/cart.md
  • docs/compatibility.md
  • docs/cpu.md
  • docs/engineering-lessons.md
  • docs/frontend.md
  • docs/performance.md
  • docs/rdp.md
  • docs/release-notes/v0.1.0.md
  • docs/release-notes/v0.2.0.md
  • docs/release-notes/v0.3.0.md
  • docs/residuals/R-10.md
  • docs/residuals/R-13.md
  • docs/residuals/R-18.md
  • docs/residuals/R-19.md
  • docs/residuals/R-5.md
  • docs/residuals/README.md
  • docs/rsp.md
  • docs/scheduler.md
  • docs/testing-strategy.md
  • screenshots/README.md
  • scripts/check_en_us.sh
  • scripts/check_no_roms.sh
  • scripts/mirror_n64brew_wiki.py
  • tests/roms/README.md
  • tests/roms/homebrew/README.md
  • tests/roms/homebrew/render_fill.s
  • tests/roms/peterlemon-timing/README.md
  • to-dos/LOCKSTEP-CHECKLIST.md
  • to-dos/ROADMAP.md
  • to-dos/VERSION-PLAN.md
  • to-dos/phase-0-foundation/overview.md
  • to-dos/phase-0-foundation/sprint-1-workspace-ci.md
  • to-dos/phase-0-foundation/sprint-2-reference-corpus.md
  • to-dos/phase-1-cpu-golden-log/overview.md
  • to-dos/phase-1-cpu-golden-log/sprint-1-integer-core.md
  • to-dos/phase-1-cpu-golden-log/sprint-2-cop0-tlb-exceptions.md
  • to-dos/phase-2-rsp-lle/overview.md
  • to-dos/phase-2-rsp-lle/sprint-1-scalar-sp.md
  • to-dos/phase-2-rsp-lle/sprint-4-microcode-boot.md
  • to-dos/phase-3-rdp-lle-vi/overview.md
  • to-dos/phase-3-rdp-lle-vi/sprint-1-decode-vi.md
  • to-dos/phase-3-rdp-lle-vi/sprint-2-texture.md
  • to-dos/phase-3-rdp-lle-vi/sprint-3-pipeline.md
  • to-dos/phase-4-ai-audio/overview.md
  • to-dos/phase-4-ai-audio/sprint-1-ai-dma.md
  • to-dos/phase-5-cart-boot-saves/overview.md
  • to-dos/phase-5-cart-boot-saves/sprint-1-pi-dma.md
  • to-dos/phase-6-frontend-integration/overview.md
  • to-dos/phase-6-frontend-integration/sprint-1-shell-wiring.md
  • to-dos/phase-7-accuracy-breadth/overview.md
  • to-dos/phase-7-accuracy-breadth/sprint-1-battery-triage.md
  • to-dos/phase-8-reach/overview.md
  • tools/mrdram-timing-rom/README.md

Comment @coderabbitai help to get the list of available commands.

… class

Adjudicates the Antigravity review on #204, which caught one of four
corruptions. A before/after word-pair audit over the whole diff caught all
four, and it is the check I should have run before committing the sweep:

  characteris -> characteriz   corrupted  characteristics -> characteriztics
  optimis     -> optimiz       corrupted  optimistic      -> optimiztic
  realis      -> realiz        corrupted  realistically   -> realiztically
  centre      -> center        corrupted  centred         -> centerd

All four are stems matching INSIDE a word already correct in en-US. The gate
passed on the corrupted tree, and correctly so -- the outputs are not en-GB
either, so an en-GB pattern cannot see them.

The same defect was in the gate itself, in both directions: bare -is stems made
it report `characteristics`, `optimistic` and `realistically` as violations.
Split the stem list in two -- PLAIN_STEMS matched as substrings, ISE_STEMS
requiring an en-GB verb/noun ending -- so `optimis+tic` no longer matches while
`optimis+ation` still does.

Also:

- Added a MALFORMED backstop list so these specific non-words cannot return,
  with a comment saying plainly that it is a backstop for forms already seen and
  NOT a substitute for auditing a future sweep's word pairs.
- Added `cancelled`/`cancelling` and `centring` as stems. Their omission left
  real en-GB spellings unswept -- `the_sign_of_a_cancelled_zero_...` (renamed)
  and two prose sites -- while the value references keep the backticked
  `cancelled` form that names GitHub Actions' literal status.
- `centring` and `cancelling` are listed separately because neither CONTAINS its
  sibling stem, which is how a stem list silently under-matches.

The gate is now mutation-checked three ways: it catches an injected en-GB word,
catches an injected malformed word, and does NOT flag optimistic /
realistically / characteristics / synthesis / analysis.

Antigravity also reported scripts/check_en_us.sh as missing from the patch;
rejected as incorrect -- `git ls-files` lists it and the `en-US spelling` CI job
PASSED on this PR, which is impossible if the script were absent.

Gates: fmt, clippy -D warnings, cargo test --workspace, rustdoc -D warnings,
no_std thumbv7em, markdownlint, check_no_roms, check_en_us -- all green.
@doublegate

Copy link
Copy Markdown
Owner Author

Adjudication of the Antigravity review

Blocking issue — scripts/check_en_us.sh is missing from the patch. REJECTED, on evidence.

The script is committed. git ls-files scripts/ lists it, and git show --stat 17b2403 -- scripts/ shows its 87 lines among the 91 insertions in that directory.

The decisive evidence is stronger than the file listing, though: the en-US spelling CI job PASSED on this PR.

$ gh pr checks 204 --json name,bucket
en-US spelling: pass

That job's only step is bash scripts/check_en_us.sh. If the script were absent from the tree CI checked out, the job would have failed with exactly the No such file or directory you predicted — so its passing is proof of presence. The check count also went 10 → 11 on this PR, which is the new job appearing.

I suspect the patch view truncated: this diff spans 133 files, and scripts/check_en_us.sh sorts late.

Suggestion — centerd typo introduced by the replacement pass. ADOPTED, and it was the tip of a bigger problem.

You found one. I ran a before/after word-pair audit over the entire diff — reconstructing each changed line's words and reporting every pair that differs — and it found four:

Produced Should be Stem that did it
centerd centered centrecenter on centred
characteriztics characteristics characteris matched inside an already-correct word
optimiztic optimistic optimis matched inside an already-correct word
realiztically realistically realis matched inside an already-correct word

Three of those are worse than a typo: they are stems firing inside words that were already correct in en-US. I had explicitly reasoned about this class when building the list — excluding analysis, synthesis, hypothesis, peripheral, exercise and others for exactly this reason — and then failed to check -istic, -ism and -istically. All six occurrences are repaired.

Worth being clear about what this says about my own gate: it PASSED on the corrupted tree, and correctly so. The outputs are not en-GB either, so an en-GB pattern cannot see them. Your review caught one; the audit caught all four. The audit is the check I should have run before committing, and its absence is the actual mistake here.

The same defect was in the gate, in both directions. Bare -is stems made it report characteristics, optimistic and realistically as violations. Fixed by splitting the list:

  • PLAIN_STEMS — matched as substrings (colour, behaviour, centre, …)
  • ISE_STEMS — matched only when followed by an en-GB ending (e|es|ed|er|ers|ing|ation|ations|able|ably), so optimis+tic no longer matches while optimis+ation still does.

Three further fixes in the same commit:

  1. A MALFORMED backstop list so these specific non-words cannot return — with a comment stating plainly that it covers forms already seen and is not a substitute for auditing a future sweep's word pairs. A backstop presented as a solution would be the more dangerous artifact.
  2. Added cancelled/cancelling and centring as stems. Omitting them left genuine en-GB spellings unswept — a test function the_sign_of_a_cancelled_zero_… (renamed) and two prose sites — while the references that name GitHub Actions' literal status keep the backticked `cancelled` form the allowlist protects.
  3. centring and cancelling are listed separately from centre/cancelled, because neither contains its sibling stem. That is how a stem list silently under-matches, and it is the mirror image of the over-matching bug above.

The gate is now mutation-checked three ways rather than two:

inject an en-GB word        -> caught
inject a malformed word     -> caught
optimistic / realistically / characteristics / synthesis / analysis -> correctly NOT flagged

Good catch — the one typo you surfaced is what prompted the audit that found the other three.

@github-actions

Copy link
Copy Markdown

Antigravity review (Gemini via Ultra)

This PR converts repository documentation, comments, and configuration text from en-GB to en-US spelling and adds CI and pre-commit gates to enforce en-US spelling going forward.

Blocking issues

  • Missing scripts/check_en_us.sh file: Both ci.yml and .pre-commit-config.yaml invoke scripts/check_en_us.sh, but this script is completely missing from the diff. CI runs and pre-commit hooks will fail immediately with No such file or directory.

Suggestions

  • Corrupted spelling replacement (realiztic): Over-aggressive find-and-replace converted realistic to realiztic (with a 'z') in ticket documentation:
    • to-dos/phase-2-rsp-lle/sprint-3-dma-scalar.md
    • to-dos/phase-5-cart-boot-saves/sprint-1-pi-dma.md
      realistic is already correct en-US spelling and should not be changed to realiztic.

Nitpicks

None.

Automated first-pass review by agy on a self-hosted runner -- not a human review.

@doublegate
doublegate merged commit 7ccb341 into main Jul 30, 2026
12 checks passed
@doublegate
doublegate deleted the chore/en-us-spelling branch July 30, 2026 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant