You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ci.yml's crosspkg filter is a second, hand-kept recognizer of CROSS_PACKAGE_TEST_INPUTS — nothing fails when a declaration lands in a root it does not cover #10379
Found while implementing #10015 (which makes the ten then-unschedulable declarations schedule). Filed unassigned.
The residual hole
After #9829/#10014 and #10015, ci.yml carries a crosspkg paths-filter whose entries mirror the
top-level roots that CROSS_PACKAGE_TEST_INPUTS declares and core does not already match:
pnpm check:cross-package-test-inputs verifies two of the three layers the mechanism has:
it finds escaping tests itself, statically, and fails naming any package that has one and no
declaration;
--verify requires turbo.json to carry a matching $TURBO_ROOT$/… input, so the task hash
moves with the declared path (Layer B).
Nothing verifies the third: that the scheduler can start the job in which Layer A's --union-into step lives. The five entries above are a second recognizer of the same declarations,
kept in step by hand. Add a declaration in a root none of them covers — tools/, docker/, paseo.json, a second skills/* bundle, another docs/… file — and the gate stays green, the
turbo hash still moves, and the test still does not run at PR time. That is exactly the #7802
shape, one layer up, and it is the failure #10015 was filed for after #9829 fixed one root.
Measured, on f3996182b
Instantiating every $TURBO_ROOT$ declaration to a real tracked file and running it through
ci.yml's filters with picomatch (the matcher dorny/paths-filter@v4 uses), under both 2.3.1
(bundled by the action) and 4.0.5 (this tree) — the two agree on every row:
A static parity gate: assert at lint time that every declared glob is covered by core or crosspkg. No CI-time coupling, entries stay readable and commented. Cost: it needs a
coverage decision. Instantiating to tracked files needs a picomatch-compatible matcher for core's apps/!(docs)/** extglob, which the gate's deliberately dependency-free globToRegExp does not support — i.e. a third recognizer, with its own divergence risk. A
pure-string rule avoids that: a declared glob is covered iff some list literally contains it, or
contains <prefix>/** for a directory prefix of its leading literal segments. Checked by hand
against all 55 unique declared globs on f3996182b, that rule classifies every one correctly —
red on the exact ten ci.yml's core filter misses ten more declared cross-package test inputs — content/ (7), docs/, skills/, .github/workflows/ #10015 fixes (including .github/workflows/scaffold-e2e.yml, the
same-root-different-file case a root-level rule would false-green), green on the other 45.
Route 2's pure-string rule looks like the cheaper and safer of the two, but choosing between them
is a mechanism decision, which is why this is a card rather than a rider on #10015's PR.
Refs: #10015 (the four roots), #9829 / #10014 (the scripts/ root), #9826 (the merged rewrite that
unblocked route 1), #7802 (the defect the mechanism exists for), #4928 (THE FILTER CONTRACT).
Found while implementing #10015 (which makes the ten then-unschedulable declarations schedule). Filed unassigned.
The residual hole
After #9829/#10014 and #10015, ci.yml carries a
crosspkgpaths-filter whose entries mirror thetop-level roots that
CROSS_PACKAGE_TEST_INPUTSdeclares andcoredoes not already match:pnpm check:cross-package-test-inputsverifies two of the three layers the mechanism has:declaration;
--verifyrequiresturbo.jsonto carry a matching$TURBO_ROOT$/…input, so the task hashmoves with the declared path (Layer B).
Nothing verifies the third: that the scheduler can start the job in which Layer A's
--union-intostep lives. The five entries above are a second recognizer of the same declarations,kept in step by hand. Add a declaration in a root none of them covers —
tools/,docker/,paseo.json, a secondskills/*bundle, anotherdocs/…file — and the gate stays green, theturbo hash still moves, and the test still does not run at PR time. That is exactly the #7802
shape, one layer up, and it is the failure #10015 was filed for after #9829 fixed one root.
Measured, on
f3996182bInstantiating every
$TURBO_ROOT$declaration to a real tracked file and running it throughci.yml's filters with picomatch (the matcher
dorny/paths-filter@v4uses), under both 2.3.1(bundled by the action) and 4.0.5 (this tree) — the two agree on every row:
crosspkgThe "after" row is green today, and no gate holds it there.
Two routes, both previously considered
Derive the filter entries from
CROSS_PACKAGE_TEST_INPUTSat CI time — option 1 of ci.yml'scorepaths-filter names no path underscripts/, so a scripts-only PR skips Test Core — and with it the--union-intostep three cross-package declarations depend on #9829'sown list, held there because it collided with fix(ci): reconstruct the paths cross-package tests really read, instead of trusting quoted prose #9826's rewrite of
scripts/check-cross-package-test-inputs.mjs. fix(ci): reconstruct the paths cross-package tests really read, instead of trusting quoted prose #9826 has since merged, so the collision isgone.
dorny/paths-filteraccepts itsfiltersinput as a string, and a YAML flow sequence(
crosspkg: ["scripts/**", …]) is a single line, so an earlier step could emit it into$GITHUB_OUTPUTwith no indentation problem. Cost: a new failure mode inside thefilterjob —the one job whose death THE FILTER CONTRACT (
filterjob 一旦失败,Test Core / Build Core / Dogfood 会全部 skipped 而分支保护判为通过 —— 隐式 success() 今天已第三次咬人 #4928) was written about — and the entries stopbeing readable in the workflow file.
A static parity gate: assert at lint time that every declared glob is covered by
coreorcrosspkg. No CI-time coupling, entries stay readable and commented. Cost: it needs acoverage decision. Instantiating to tracked files needs a picomatch-compatible matcher for
core'sapps/!(docs)/**extglob, which the gate's deliberately dependency-freeglobToRegExpdoes not support — i.e. a third recognizer, with its own divergence risk. Apure-string rule avoids that: a declared glob is covered iff some list literally contains it, or
contains
<prefix>/**for a directory prefix of its leading literal segments. Checked by handagainst all 55 unique declared globs on
f3996182b, that rule classifies every one correctly —red on the exact ten ci.yml's core filter misses ten more declared cross-package test inputs — content/ (7), docs/, skills/, .github/workflows/ #10015 fixes (including
.github/workflows/scaffold-e2e.yml, thesame-root-different-file case a root-level rule would false-green), green on the other 45.
Route 2's pure-string rule looks like the cheaper and safer of the two, but choosing between them
is a mechanism decision, which is why this is a card rather than a rider on #10015's PR.
Refs: #10015 (the four roots), #9829 / #10014 (the
scripts/root), #9826 (the merged rewrite thatunblocked route 1), #7802 (the defect the mechanism exists for), #4928 (THE FILTER CONTRACT).