Skip to content

Add a gate that keeps the codebase in US spellings - #1458

Merged
mastacontrola merged 7 commits into
working-1.6from
us-spelling-gate
Aug 29, 2026
Merged

Add a gate that keeps the codebase in US spellings#1458
mastacontrola merged 7 commits into
working-1.6from
us-spelling-gate

Conversation

@mastacontrola

Copy link
Copy Markdown
Member

#1457 made the tree clean. Nothing stopped it drifting back — this is the
gate. It runs inside the existing fogproject / tests context, so the
ruleset needs no new required check.

Why a whole-tree scan and not a diff

The obvious shape is "check only the lines this PR adds", and it was the
first thing tried. It needs a base ref, and this file cannot see or set
the checkout depth — the job that runs it lives in FOGProject/fog-workflows.
A shallow clone has no merge-base, so the check would find nothing to look
at and pass, for a reason that has nothing to do with spelling,
silently and on every pull request. A gate that can only report success is
worse than no gate, because it also reports "verified".

Scanning everything needs no ref, cannot skip, and is only possible
because the tree is already clean. Same principle the phpstan job is
built on: a gate that can only be satisfied, never one that grows.

Two patterns

One right-hand boundary cannot serve both shapes:

  • word / camelCase — refuses a following lower-case letter, so enrol
    does not fire inside enrolled or enrollment. Left edge is "not
    preceded by a letter, or on a camelCase hump", so getCancelledState
    matches at the C.
  • ALL CAPS — refuses a following letter of any case, or ENROL
    matches inside ENROLL_SECUREBOOT and the gate fails on a correctly
    spelled task type. ENROLMENT_MODE still matches, because _ is not a
    letter.

Both case-sensitive. A trailing /i also folds the [a-z] and [A-Z]
in the boundary assertions, collapsing the camelCase hump into "preceded
by a letter, followed by a letter" — no boundary at all. That mistake made
an earlier draft fire on labelling inside Relabelling, which reads like
a find and is really the guard rail dissolving.

File enumeration

git ls-files --cached --others --exclude-standard, because the two
obvious alternatives are each wrong in one direction:

  • a filesystem walk drags in packages/web/lib/plugins/ — gitignored,
    root-owned, written by the installer rather than by this repo;
  • plain git ls-files is blind to a file written but not staged, which is
    how a new class passed psr4-layout locally and failed in CI.

What writing it found

Three classes the sweep had missed:

  • ALL-CAPS and capitalized formsENROLMENT, ENROL, RECOGNISES,
    Normalising, Initialised, Behavioural. An enumerated word list
    never listed them; the sweep now carries the match's own case.
  • relabelling, plus afterwards, towards, judgement, ageing,
    artefact, programme.
  • UK spellings inside identifiers the $-variable guard had skipped:
    $cancelled, $cancelledIDs, $jobcancelled, $SessCancelled,
    $inTaskCancelledIDs. All file-local, all renamed.

What stays UK, and why

getCancelledState(), the CANCELLED_STATE hook, and the
'cancelledState' key that hook hands a plugin in its arguments array.
All three are the plugin ABI — a plugin reading
$arguments['cancelledState'] breaks the moment that key is respelled.
Allowlisted with that reason in the file.

Proven by mutation, not by being green

Mutation Result
lower-case word in a comment fails ✓
Title-case word fails ✓
ALL-CAPS standalone word fails ✓
ALL-CAPS word inside SNAKE_CASE fails ✓
camelCase identifier fails ✓
UK word in an untracked new file fails ✓
file enumeration broken fails ✓ (loud, never a silent skip)
enrollment, enrolled, enrolling stays green ✓
ENROLL_SECUREBOOT stays green ✓

Known limit

It cannot see a UK word glued inside an all-lower-case identifier
(withenrol). No boundary separates that from a longer word, so it is out
of reach by construction rather than by oversight — said so in the file.

Verification

  • tests/run-all.sh — 186 passed, 0 failed
  • vendor/bin/phpstan analyse — no errors
  • vendor/bin/phpstan analyse -c phpstan-tests.neon — no errors

The matching gate for FOS is FOGProject/fos#169.

mastacontrola and others added 7 commits August 29, 2026 06:57
GH-1457 made the tree clean; nothing stopped it drifting back. This is
the gate.

A whole-tree scan, not a diff. The obvious shape is "check only the lines
this pull request adds", and it needs a base ref -- which this file cannot
see or set, because the job that runs it lives in FOGProject/fog-workflows.
A shallow clone has no merge-base, so the check would find nothing to look
at and pass, for a reason that has nothing to do with spelling, silently
and on every pull request. A gate that can only report success is worse
than no gate, because it also reports "verified". Scanning everything needs
no ref, cannot skip, and is only possible because the tree is already
clean -- the same principle the phpstan job is built on: a gate that can
only be satisfied, never one that grows.

Two patterns, because one right-hand boundary cannot serve both shapes.
The word/camelCase one refuses a following lower-case letter, so `enrol`
does not fire inside `enrolled` or `enrollment`. The ALL CAPS one refuses
a following letter of any case, or `ENROL` matches inside
`ENROLL_SECUREBOOT` and the gate fails on a correctly spelled task type.
Both are case-sensitive: a trailing /i also folds the [a-z] and [A-Z] in
the boundary assertions, which collapses the camelCase hump into
"letter, letter" -- no boundary at all.

Files come from `git ls-files --cached --others --exclude-standard`. A
filesystem walk drags in packages/web/lib/plugins/, which is gitignored,
root-owned and written by the installer rather than by this repository;
plain `git ls-files` is blind to a file a developer has written but not
staged, which is how a new class passed psr4-layout locally and failed in
CI. That pair is exactly right: tracked, plus new, minus ignored.

Writing it found what the sweep had missed, in three classes:

- ALL-CAPS and capitalised forms (ENROLMENT, RECOGNISES, Normalising,
  Initialised, Behavioural) that an enumerated word list never listed.
  The sweep now carries the match's own case instead.
- `relabelling`, and the words afterwards/towards/judgement/ageing/
  artefact/programme.
- UK spellings inside identifiers the $-variable guard had skipped:
  $cancelled, $cancelledIDs, $jobcancelled, $SessCancelled,
  $inTaskCancelledIDs. All file-local, all renamed.

Three identifiers stay UK and are allowlisted with the reason:
getCancelledState(), the CANCELLED_STATE hook, and the 'cancelledState'
key that hook hands a plugin in its arguments array. All three are the
plugin ABI.

Proven by mutation, not by being green: a lower-case word, a Title-case
word, an ALL-CAPS word, an ALL-CAPS word inside SNAKE_CASE, a camelCase
identifier, a UK word in an untracked new file, and a broken file
enumeration each make it fail; `enrollment`, `enrolled`, `enrolling` and
`ENROLL_SECUREBOOT` each leave it green.

tests/run-all.sh: 186 passed, 0 failed. Both phpstan passes clean.

Co-Authored-By: Claude <noreply@anthropic.com>
The empty-enumeration guard covered "git exited non-zero". It did not
cover the case that actually happens: git exits 0 and returns no rows,
because a path moved or an ignore rule grew to swallow it. That printed
"0 file(s) scanned, no UK spellings in scope" and exited 0 -- green, and
meaningless. Exactly the silent pass the whole file exists to avoid, and
CI could not have told me otherwise: run-all.sh captures a passing test's
output, so the log said `ok us-spelling.test.php` either way.

Checked per $scope entry rather than as a total, because a total still
passes when one directory of the seven drops out.

Also drops CONTEXT.md from $scope. It is gitignored here, so it never
contributed a file and never could -- listing it implied coverage that
did not exist, and it would have tripped the new floor.

Mutation-proven both ways: renaming one scope entry fails, and making the
enumeration return nothing at all fails.

tests/run-all.sh: 186 passed, 0 failed.

Co-Authored-By: Claude <noreply@anthropic.com>
Brings in ADR 0030's ImagingStats split, which landed while this branch
was open. The gate caught six UK spellings in it -- `$CANCELLED` and four
comments in tests/imaging-stats.test.php, and one comment in
dashboardpage.page.php -- and they are fixed here.

That is the check doing exactly what it was built for, on its own first
contact with code written after the sweep, before either branch merged.

FOG_VERSION resolved to working-1.6's 4373; the version-sync bot restamps
the post-merge value at PR time.

Co-Authored-By: Claude <noreply@anthropic.com>
Second catch-up in one sitting -- several sessions are landing on this
branch's base concurrently.

Two conflicts. FOG_VERSION resolved to working-1.6's 4381. The dashboard's
Recent Activity block was removed upstream, so this side's copy goes with
it rather than being resurrected by the merge; the spelling fix it carried
goes away with the code it applied to.

The gate then found the same UK comment in dashboardpage's surviving
ADR 0030 note, which arrived on the other side of the merge. Fixed.

tests/run-all.sh: 186 passed, 0 failed.

Co-Authored-By: Claude <noreply@anthropic.com>
@mastacontrola
mastacontrola merged commit 699cb36 into working-1.6 Aug 29, 2026
9 checks passed
@mastacontrola
mastacontrola deleted the us-spelling-gate branch August 29, 2026 12:21
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