Add a gate that keeps the codebase in US spellings - #1458
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#1457 made the tree clean. Nothing stopped it drifting back — this is the
gate. It runs inside the existing
fogproject / testscontext, so theruleset 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
phpstanjob isbuilt on: a gate that can only be satisfied, never one that grows.
Two patterns
One right-hand boundary cannot serve both shapes:
enroldoes not fire inside
enrolledorenrollment. Left edge is "notpreceded by a letter, or on a camelCase hump", so
getCancelledStatematches at the
C.ENROLmatches inside
ENROLL_SECUREBOOTand the gate fails on a correctlyspelled task type.
ENROLMENT_MODEstill matches, because_is not aletter.
Both case-sensitive. A trailing
/ialso 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
labellinginsideRelabelling, which reads likea find and is really the guard rail dissolving.
File enumeration
git ls-files --cached --others --exclude-standard, because the twoobvious alternatives are each wrong in one direction:
packages/web/lib/plugins/— gitignored,root-owned, written by the installer rather than by this repo;
git ls-filesis blind to a file written but not staged, which ishow a new class passed
psr4-layoutlocally and failed in CI.What writing it found
Three classes the sweep had missed:
ENROLMENT,ENROL,RECOGNISES,Normalising,Initialised,Behavioural. An enumerated word listnever listed them; the sweep now carries the match's own case.
relabelling, plusafterwards,towards,judgement,ageing,artefact,programme.$-variable guard had skipped:$cancelled,$cancelledIDs,$jobcancelled,$SessCancelled,$inTaskCancelledIDs. All file-local, all renamed.What stays UK, and why
getCancelledState(), theCANCELLED_STATEhook, 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
SNAKE_CASEenrollment,enrolled,enrollingENROLL_SECUREBOOTKnown 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 outof reach by construction rather than by oversight — said so in the file.
Verification
tests/run-all.sh— 186 passed, 0 failedvendor/bin/phpstan analyse— no errorsvendor/bin/phpstan analyse -c phpstan-tests.neon— no errorsThe matching gate for FOS is FOGProject/fos#169.