Repository navigation
internals/checks: teach preflight the one-function-per-file gate - #1019
Merged
thekevinscott merged 8 commits intoSep 2, 2026
Merged
thekevinscott merged 8 commits into
thekevinscott merged 8 commits into
Conversation
RED. testing-conventions @v0 runs `unit one-function-per-file` in its static job, so a lane naming no `gates:` is held to it in CI. preflight's ROOT_GATES omits it, so `just preflight` skips it locally and reports green. skip-changelog: internals/ tooling tests, no published package touched
GREEN. Two changes, and the second is what makes the first observable. `one-function-per-file` joins the gate table and the default-gates list, so preflight derives it for the lanes that name no `gates:` and builds the right argv for a lane that names it. Resolving the CLI moves off `uvx` to `npx testing-conventions@latest`. The PyPI wheel is a laggier distribution of the same tool -- 0.0.104 against npm's 0.0.111 -- and has no `one-function-per-file` subcommand at all, so the gate could not run locally however the table was written. A bare `npx testing-conventions` is worse: npm resolves an unversioned name engine-aware, `engines.node` rose to `>=24` at 0.0.87, and a shim on an older node silently picks 0.0.86 and exits 0. Naming the tag makes the local ruleset the one CI enforces, which is the whole point of the recipe. skip-changelog: internals/ tooling, no published package touched
`gates:` is an allowlist, so internals-checks, internals-distcheck and plugins-embeddings each skip the gate until their array names it -- three lanes CI silently holds to a rule nothing local runs. skip-changelog: internals tooling test, no packaged behavior
thekevinbot
force-pushed
the
claude/1018-preflight-one-function-gate
branch
from
September 2, 2026 16:56
f20f8f6 to
829b30c
Compare
internals-checks, internals-distcheck and plugins-embeddings each pass an explicit `gates:` allowlist, so the reusable workflow's default set does not reach them and the gate was not running on those three lanes. skip-changelog: CI config, no packaged behavior
The wheel `uv run --with` fetches lags npm, and it rejects a config key the newer release added -- an unknown key fails the whole config, so the python coverage and mutation arms red locally on a config CI accepts. Running the npm CLI under `uv run` keeps the package venv's interpreter for the suite while resolving the same release CI does. skip-changelog: internals tooling test, no packaged behavior
`uv run --with testing-conventions` resolved both the CLI and the mutation adapter from the wheel, which trails the npm release. A config key the newer release added is an unknown key to the older one, and an unknown key fails the whole config -- so `unit coverage` and `unit mutation` red locally against a config CI accepts, on three python lanes at once. Split the two roles. The npm tag resolves the CLI, matching CI; `--with` stays only to put `testing_conventions` on the interpreter the gate hands to `python3 -m`, the sole form the mutation adapter ships in. skip-changelog: internals tooling, no packaged behavior
This was referenced Sep 4, 2026
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.
Fixes #1018.
Stacked on #1023 (
claude/1017-ofpf-threshold), which adds themax_lines = 100config this PR's local runs read. Review that one first; GitHub retargets this to
mainwhen it merges.What
just preflightderives its (root, language, gate) matrix from the workflows, soit should run locally exactly what CI runs. Three separate things broke that for
one-function-per-file— the gate that has been red onmainsince the@v0tagrolled and that nothing local was exercising.
1. The gate table did not know it.
matrix.pymaps gate names to CLI argv;one-function-per-filewas absent from bothROOT_GATES(the implicit set a lanenaming no
gates:is held to) andGATES(the name-to-argv table). A lane thatnamed it raised
KeyErrorrather than building an invocation.2. Three lanes did not name it.
gates:is an allowlist, sointernals-checks,internals-distcheckandplugins-embeddingswere skippingthe gate in CI too. Their arrays now name it.
3. The local CLI was not the CLI CI runs. Two independent resolution drifts,
both silent:
uvx testing-conventions/uv run --with testing-conventionsfetch thePyPI wheel, which trails the npm release (0.0.104 against 0.0.111 as of this
PR). It has no
one-function-per-filesubcommand at all, and it rejectsone_function_per_fileas an unknown key — which fails the whole config, sounit coverageandunit mutationwent red on three python lanes against aconfig CI accepts.
npx testing-conventionsis worse. npm resolves an unversioned nameengine-aware,
engines.noderose to>=24at 0.0.87, and a launcher shim onan older node therefore resolves the last release below that floor — dozens of
releases of rule changes behind, exiting 0 with no version banner to say so. CI
never hits this because every job provisions node 24.
Both close with
npx -y testing-conventions@latest. The python arm keepsuv run --with testing-conventionsaround it, but for a different reason thanbefore:
--withno longer resolves the CLI, it only puts the wheel'stesting_conventionspackage on the interpreter the gate hands topython3 -m,which is the sole form the mutation adapter ships in.
uv runalso keeps thepackage's own venv as the suite's interpreter (#706).
Verification
Before this PR,
just preflight --gate one-function-per-filereported0 failing pair(s), 0 skipped— because it derived nothing. It now derives andruns 5 pairs (python-sdk, typescript-sdk, internals-checks, internals-distcheck,
plugins-embeddings), all green.
Full
just preflight: 8 failing pairs before the launcher fix, 0 after(excluding the pre-existing
python-sdk integration-lintred tracked in #1024,which is on
mainand not this PR's to fix).Red proofs, both observed failing in CI for exactly the asserted behavior:
it_derives_..._for_a_lane_naming_no_gates1 failed, 32 passedit_derives_..._for_every_lane_naming_it1 failed, 33 passed19c23b4/ 1003427771472 failed, 395 passeduv run --project internals/checks pytest internals/checks/src internals/checks/tests -q→ 464 passed.E2E Verification
packages/source changedpackages/source changedpackages/source changedpackages/python/e2e-attestation.jsonrefreshed ifpackages/pythonchanged — N/Apackages/ts/e2e-attestation.jsonrefreshed ifpackages/tschanged — N/Ajust test-e2e-internals-checks(24 passed),just e2e-attest-internals-checksinternals/checks, whoseown
e2e-verifygate is satisfied by the receipt committed here.Changelog / Migrations
skip-changelogon each commit. The changelog gate scopes topackages/andplugins/; this PR touchesinternals/checksand three workflow files, and thegates:edits are CI config with no packaged behavior.Parity
No SDK public API touched, so
PARITY.mdis unchanged.