Repository navigation
Commit 57c9fe3
ci: the core filter starts Build Core for a build-input-only diff, held to turbo.json by check-ci-filter-parity (#21338)
Fixes #21202
Clause-②: no
## What changes
1. **`.github/workflows/ci.yml`, the `core:` filter** gains 18 literal
entries: `turbo.json`, the root `tsup.config.ts`, and the 16
`scripts/*.mjs` files that a build task Build Core runs declares as a
`$TURBO_ROOT$/...` input. A PR that changes only one of them now starts
Build Core at PR time. Before this change the merge queue was the first
place that build ran (PR #21199, a `turbo.json`-only diff, skipped Build
Core).
2. **`scripts/check-ci-filter-parity.mjs`** gets a third subject,
`judgeBuildInputs`. It derives the required set and does not keep a
copy:
- from `turbo.json`: the file itself, its `globalDependencies`, and
every `$TURBO_ROOT$/...` input of a `build` or `PKG#build` task;
- minus the builds that Build Core's `run: pnpm build` skips. Those are
read from the root `build` script's `--filter=!PKG` tokens (today
`@objectstack/docs#build` and its `content/**` input). If the script is
misread, the gate can only drop an exclusion, which makes it require
more of `core`. So a misread is a loud red, never a silent gap.
- It reds when a declared build input has no covering `core` entry.
- It also checks the reverse direction where the declarations alone can
decide it. A literal `core` entry sitting in a directory that holds
declared build inputs, but covering none of them, reds as a leftover.
- It refuses eight unread states: no `build-core` job; its `if:` no
longer names `core`; no `run: pnpm build` step; `turbo.json` or the root
manifest unreadable or not JSON; no `tasks` map; no build task; a
`build` script that is not `turbo run build ...`.
- It uses the same pure-string coverage rule as the existing `crosspkg`
subject, so no third matcher is added.
3. **Two forced follow-ons, both outside the claim's declared file
surface.** Each is the remedy text of a gate that this change turned
red. Neither is a design choice.
- **Build Core gains `node scripts/check-dts-emitted.mjs --self-test`.**
Once `core:` named that file, `check:self-test-wired` reported that a
workflow names a script whose `--self-test` no workflow runs. That is
true: 67 package build commands end with that checker, and its self-test
ran nowhere in CI. The gate's remedy is "wire it into the step that runs
it". The step takes milliseconds, needs no prerequisites, and runs
before `pnpm build`.
- **`scripts/pm/dispatch-gates.mjs`, one self-test specimen.** The case
"a name-shaped script no family runs is NOT a gate script" used
`scripts/check-dts-emitted.mjs`, which item 3a turned into a family
file. The specimen is now `scripts/check-test-typecheck.mts`, which only
package manifests run. That file is already named in the same docblock's
list of such files.
4. **Three comments this change made false, corrected in `e6aa08f322`
(patch round 2, comments only):** the GAP 1 block in
`scripts/sync-template-versions.mjs`, the same block in
`.github/workflows/lint.yml`, and the extglob docblock sentence in
`scripts/pm/dispatch-gates.mjs` ("one entry of six"). Each now reads
true with `core` matching the root build inputs. The re-measure for a
diff confined to `scripts/sync-template-versions.mjs` reads `core=true`,
`crosspkg=true`.
No change to `turbo.json` or `fleet-write.yml`. `lint.yml` changes only
its GAP 1 comment block (about lines 2660 to 2675), which is disjoint
from #21295's pm roster block.
## Granularity: literal files, not `scripts/**`
I measured this over the 3288 first-parent commits of `main` in the 30
days to `1371dc980c`, with `scripts/pm/git-history.mjs` proving the
window was present (floor 2026-06-27). I used picomatch `{ dot: true }`,
the options `dorny/paths-filter` uses, under both 2.3.1 and 4.0.5. The
two versions agree on every commit.
| `core` filter | commits it matches | added by this change |
|:--|--:|--:|
| before | 2247 | — |
| + the 18 literal build inputs (this PR) | 2275 | **+28** |
| + `scripts/**`, `turbo.json`, `tsup.config.ts` | 2840 | +593 |
516 of the 593 that `scripts/**` would add touch a `scripts/pm/` tool or
a `scripts/check-*` gate. The gate holds the literal list to the
declarations, so the narrow choice costs nothing in drift.
Widening `core` starts every job that `core` gates, not only Build Core:
Test Core, Temporal Conformance and Dogfood also run on those 28. That
matches turbo's own view, because every one of those jobs builds, and a
moved build hash re-runs everything downstream of it.
## Acceptance: the filter evaluated per path
The `core` list is parsed out of `ci.yml` at the base and at this head,
in the action's order (YAML, then the `filters` string). Each path is
matched with picomatch `{ dot: true }`.
| path | before (2.3.1 / 4.0.5) | after (2.3.1 / 4.0.5) |
|:--|:--|:--|
| `turbo.json` | false / false | true / true |
| `tsup.config.ts` | false / false | true / true |
| each of the 16 `scripts/*.mjs` build inputs | false / false | true /
true |
| `tsconfig.json` (globalDependencies) | true / true | true / true |
| `packages/cli/src/commands/init.ts` (create-objectstack#build) | true
/ true | true / true |
| control: `scripts/check-ci-filter-parity.mjs` | false / false | false
/ false |
| control: `scripts/pm/dispatch-gates.mjs` | false / false | false /
false |
| control: `content/docs/index.mdx` | false / false | false / false |
| control: `packages/spec/src/ui/view.zod.ts` | true / true | true /
true |
The 16 scripts are each checked individually: `build-input-hash`,
`check-dev-prereqs`, `check-dts-emitted`, `check-dts-references`,
`check-regen-pending`, `cli-build-prerequisite`, `git-env`,
`import-prerequisite`, `invoked-as`, `js-comment-mask`,
`regen-artifacts`, `sync-scaffold-emission-policy`,
`sync-template-versions`, `ts-parse`, `tsup-drop-sources-content`,
`workspace-enumerator`.
**Live run: none yet.** This PR changes `ci.yml`, which `core` already
matched, so its own run proves nothing. The first demonstration will be
the first PR after this one lands whose diff is confined to listed
paths. At the measured rate that is about one a day (28 in 30 days). The
`turbo.json` card #20790 is the known candidate if its PR touches only
`turbo.json`.
## The new leg can go red
- **Self-test battery (9), 33 cases; the gate goes from 68 to 101
assertions.**
- A build input dropped from a fixture `core:` reds, naming the path and
the task that declared it.
- `turbo.json` itself, a `globalDependencies` entry, and an input under
a new root are each required.
- Test-task inputs, negated inputs, and the excluded docs build are left
out. The docs build's input is required again once the build script
stops excluding it.
- A leftover entry reds.
- All eight refusals are covered (ten cases).
- The checked-in tree is green. With `scripts/invoked-as.mjs` dropped
from it, the gate reds through `main()`, the report path.
- **Battery (8)'s report-path scratch root** now carries the real
`turbo.json` and root manifest, so a red there cannot come from the new
subject refusing a missing file.
- **Before/after on the real tree.** The extended gate run over the base
`ci.yml` exits 1 and lists the 18 inputs. Over this head it exits 0.
- **Ablations**, done with `scripts/ablation-replace.mjs`. Each mutation
was confirmed on disk, and each restore was proven by blob equal to
`HEAD` and an empty `git diff HEAD`:
- Coverage forced true in `judgeBuildInputs`: production exit 0 (green),
`--self-test` exit 1 with 9 named failures.
- Leftover rule disabled: production exit 0, `--self-test` exit 1 with 1
named failure.
- My first attempt at the leftover ablation was a no-op. Its replacement
text contained the anchor, so the tool refused and wrote nothing. I
re-ran it with a non-overlapping replacement.
## Gates (local, head ec413ce)
- I re-derived the list with `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` (no paths; merge base
`1371dc980`): 58 commands.
- `--ran` reconciliation: "58 derived famil(ies) accounted for — 54 run,
4 NOT-MEASURED (0 DERIVED from a recorded exit 3, 4 claimed)". Every one
of the 54 recorded exit 0.
- That includes `check-ci-filter-parity` and its `--self-test`,
`check:self-test-wired`, `bare-root-worklist --self-test`,
`check:required-contexts`, `check:workflow-step-name-quoting`,
`check:step-collectors`, `check:stall-guard-budget` and
`check:nul-bytes`.
- It also includes `check:pm-dispatch-gates`, whose self-test passed
1976 cases (778 s on this box). Its "fabrication direction" case passes
with the new specimen.
- The four `dist/`-reading Build Core gates (`check:dts-closure`,
`check:dual-build-cjs-loads`, `check:lean-entry-closure`,
`check:sourcemap-no-sources-content`): their `--self-test` legs exit 0.
Their real legs are **NOT MEASURED** locally, because they read a full
workspace `dist/` and this diff moves no build hash. The changed files
are a workflow and two root scripts, none of them a declared build
input. Build Core runs them on this PR.
## Changeset
None. The changed files are a workflow, a root script and a
`scripts/pm/` tool. None of them is in any published package's
`files[]`, and the root package is private. `skip-changeset` applies.
## Acceptance notes (not changed here)
- **Two comments this change made false, plus a third the grep found:**
all three are corrected in this PR (`e6aa08f322`, item 4 above), per the
seat's patch round. The carrier this note first named, #21294's PR, had
already landed. (Seat edit.)
- **Build Core's own guard scripts do not schedule Build Core.**
`check-dts-closure`, `check-dual-build-cjs-loads`,
`check-sourcemap-no-sources-content` and `check-lean-entry-closure` run
only inside Build Core. A diff confined to one of them leaves `core`
false (picomatch 2.3.1 and 4.0.5, both before and after this PR).
Measured on PR #17100 (`91f65c4ea4`), which changed only
`scripts/check-lean-entry-closure.mjs`: Build Core was `skipped`, so
neither the changed gate's self-test nor its real leg ran at PR time.
This is a different population from build inputs, because turbo does not
declare these files, so it is reported here and left unchanged.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01UtnxvdiN376GF3sgXwAw4d)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 99e1912 commit 57c9fe3
5 files changed
Lines changed: 515 additions & 41 deletions
File tree
- .github/workflows
- scripts
- pm
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
178 | 178 | | |
179 | 179 | | |
180 | 180 | | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
181 | 223 | | |
182 | 224 | | |
183 | 225 | | |
| |||
2047 | 2089 | | |
2048 | 2090 | | |
2049 | 2091 | | |
| 2092 | + | |
| 2093 | + | |
| 2094 | + | |
| 2095 | + | |
| 2096 | + | |
| 2097 | + | |
| 2098 | + | |
| 2099 | + | |
| 2100 | + | |
| 2101 | + | |
2050 | 2102 | | |
2051 | 2103 | | |
2052 | 2104 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2660 | 2660 | | |
2661 | 2661 | | |
2662 | 2662 | | |
2663 | | - | |
2664 | | - | |
2665 | | - | |
2666 | | - | |
2667 | | - | |
2668 | | - | |
2669 | | - | |
2670 | | - | |
2671 | | - | |
2672 | | - | |
2673 | | - | |
2674 | | - | |
2675 | | - | |
| 2663 | + | |
| 2664 | + | |
| 2665 | + | |
| 2666 | + | |
| 2667 | + | |
| 2668 | + | |
| 2669 | + | |
| 2670 | + | |
| 2671 | + | |
| 2672 | + | |
| 2673 | + | |
2676 | 2674 | | |
2677 | 2675 | | |
2678 | 2676 | | |
| |||
0 commit comments