web lint hook: run a check when a file it reads changes (Swift-only pushes skipped check:text-focus)

LA
3d ago
+266-13

Summary

The pre-push web lint did not run a check when a push changed a file that the check reads but that is outside the check's package triggers. webviews' check:text-focus (scripts/cmux-next/check-text-focus-rings.py) walks Packages/macOS/CmuxNext/Sources/**/*.swift. The hook planned the webviews check only from triggers (webviews/, config/vite-plus/, scripts/cmux-next/, the acpmux spec), so a Swift-only push linted nothing. That is how 385cb09a747 (McpConnectCardParts.swift, Swift only) passed the hook and then turned feat-cmux-next's web lint (fast) red (fixed by #33979).

Correction (from review): c0230efd501 (AllThemesPlaygroundView.swift, fixed by #34025) is not covered. That push also changed scripts/cmux-next/media/states/*.json. This folder is a webviews trigger and an executed path, so the hook refused to lint the push ("not linted here") for that reason, before and after this PR. The module docstring also names c0230efd501; a follow-up will correct it.

The rule now: a check runs when any input it reads changes.

  • Each source-check script declares what it reads next to its own path constants, as a module-level INPUTS tuple. Example: INPUTS = (TREE, f"{SWIFT_TREE}/**/*.swift"). The declaration is part of the check, so there is one source of truth.
  • scripts/web_lint_prepush.py reads INPUTS with ast and never runs it (declared_inputs(), input_pieces()). Only python3 pieces that the hook already accepts as guarded source checks (light_script) qualify.
  • A change that misses the package triggers but touches a piece's INPUTS runs only those pieces, as argument lists with no shell and no install. This is the same on a build host and on a host with CMUX_LOCAL_HEAVY_CHECKS=0. A Swift-only push costs about 3 s, not the whole webviews check.
  • These pieces never run code that the push changed. A change to a piece's own script is under scripts/cmux-next/, which is a trigger and an executed path. The hook therefore refuses to lint that push, as before.

Other webviews pieces that read files outside webviews/ are now declared in the same way:

PieceReads outside webviews/
check:text-focus, check:toast-targets, check:dialog-keysPackages/macOS/CmuxNext/Sources/**/*.swift
check:system-bluePackages/macOS/CmuxNext/Sources, Packages/Shared
check:session-info-namestwo CmuxNext Swift files (one under Tests/)
check:catalog-keysevery *.xcstrings
check:type-scale, check:motion-scale, check:layout-grid, check:status-glyphs, check:surface-rolestheir schemas/ source and generated Swift file

Not covered (these are not source-check pieces):

  • vp check (the type check) imports JSON and JS from outside webviews/: schemas/{settings,layout-grid,agent-pane,sync-motion}, web/data/model-catalog, Packages/Shared/CmuxAgentQuestion/.../Fixtures, Resources/markdown-viewer, cmux-tui/spec/page-router.json, a CmuxNext font. Running the type check for those changes would need the full install, so this PR leaves them to CI.
  • check:attachment-caps runs with --warn and cannot fail.

The web lint (fast) job on feat-cmux-next runs the same script, so a Swift-only push with a known base now runs these pieces there too. No CI job, step or gate is added. The PR fast gates' web_needed is unchanged.

Testing

Red on the base, green on the head (the test is in its own commit, 4fe06333544):

(cd tests && python3 -m unittest -k swift test_web_lint_prepush)
  • Base ba1cf8e38ee: 2 of 3 fail. The Swift-only push with a ringed TextField reaches origin. The dry run prints nothing to lint.
  • Head: 3 of 3 pass. The push is refused and names Field.swift:3, on a build host and on a host with CMUX_LOCAL_HEAVY_CHECKS=0. No other piece runs. A clean Swift push runs only check-text-focus-rings.py and passes. A Swift file that no piece reads lints nothing.

Observed / Not run

Observed:

  • python3 tests/test_web_lint_prepush.py: 62 tests OK. This includes two new unit tests: declared_inputs and input_matches forms, and the real webviews/package.json that selects the four Swift-reading pieces for a CmuxNext Swift path and none for README.md or ios/App.swift.
  • python3 -m unittest test_cmux_next_fast_gates: 77 OK.
  • python3 scripts/cmux-next/prepush-gate.py: no new violations.
  • Every declared piece run by hand on the tip: all pass in 3.3 s or less, except check:text-focus. Its red is the base red from c0230efd501, which #34025 fixes.
  • scripts/web-lint.sh: only that same base red.

Not run:

  • A real push to feat-cmux-next with a Swift-only change through the installed hook. The tests drive the real git push and the installed hook copy in a throwaway repository.

Changelog

none

Proof

No capture: hook and CI tooling only.