@@ -556,14 +556,19 @@ jobs:
556556 echo 'Items on this shard (a package name, or a package plus a k/n file-level slice):'
557557 cat "$RUNNER_TEMP/shard-packages.txt"
558558
559- # ⛔ A FILE-LEVEL SLICE BUILDS ITS DEPENDENCY CLOSURE HERE, IN A RUN THAT
560- # CARRIES NO PASSTHROUGH, so that the sharded run in the next step can be
561- # `--only` (#16395).
562- #
563- # Turbo folds a run-level passthrough into the hash of EVERY task in the
564- # run, not only the task that receives it -- and `-- "--shard=k/n"` is the
565- # whole reason a slice gets its own invocation at all (the next step's
566- # comment says why it cannot ride the shared run). Measured on turbo
559+ # ⛔ A FILE-LEVEL SLICE BUILDS ITS DEPENDENCY CLOSURE HERE, IN ITS OWN
560+ # GUARDED STEP, so the slice leg in the next step REPLAYS it. Since #19278
561+ # that leg carries its slice in `OS_TEST_SHARD`, which only the `test`
562+ # task declares, so its build tasks hash exactly as they do here (61 of 61
563+ # identical, measured) and it schedules its own closure: this step is no
564+ # longer what makes the leg correct, only what keeps the closure build off
565+ # the test step's stall-guard site (see the last paragraph below).
566+ #
567+ # Why the step first existed (#16395, when the slice was still a
568+ # passthrough and the leg was `--only`): turbo folds a run-level
569+ # passthrough into the hash of EVERY task in the run, not only the task
570+ # that receives it -- and `-- "--shard=k/n"` was then the whole reason a
571+ # slice got its own invocation at all. Measured on turbo
567572 # 2.10.10, `--filter=@objectstack/cli`, `turbo run test ... --dry=json`
568573 # (60 tasks: 59 `build` + 1 `test`):
569574 #
@@ -677,12 +682,15 @@ jobs:
677682
678683 # Split the shard's ITEMS into the whole packages, which share one
679684 # turbo run as they always have, and the file-level slices, which
680- # cannot: `--shard=k/n` is passed through to vitest by turbo as a
681- # RUN-level argument, so it would reach every package in the run —
682- # and on any package with fewer test files than n that is a hard
683- # vitest failure (or, with --passWithNoTests, silently no tests at
684- # all). A slice therefore gets its own invocation, filtered to the one
685- # package the partitioner sliced.
685+ # cannot: a slice's `k/n` travels as `OS_TEST_SHARD` in the turbo
686+ # run's environment, and a run has ONE environment — set on the
687+ # shared run it would reach every package's `test` task, which
688+ # turbo.json declares it on. (Before #19278 it travelled as a
689+ # `--shard=k/n` passthrough, which reached every package's vitest: a
690+ # hard failure on any package with fewer test files than n, or with
691+ # --passWithNoTests silently no tests at all.) A slice therefore gets
692+ # its own invocation, filtered to the one package the partitioner
693+ # sliced.
686694 FILTERS=""
687695 SLICES=""
688696 while read -r PKG SLICE; do
@@ -727,74 +735,73 @@ jobs:
727735 PKG="${LEG%%=*}"
728736 SLICE="${LEG#*=}"
729737 LOG="$RUNNER_TEMP/test-core-slice-$(printf '%s' "$PKG" | tr -c 'A-Za-z0-9' '-').log"
730- # `--only ` (#16395): the step above already built this slice's
731- # dependency closure in a passthrough-free run, so this run must
732- # schedule the ONE task the passthrough is for. Without it turbo
733- # re-hashes the whole `^build` closure under `--shard=k/n` and
734- # rebuilds it -- that comment carries the measurement. ⚠ The build
735- # step is load-bearing for this flag: a sliced package whose build
736- # never ran fails LOUDLY here (its imports resolve to a missing
737- # dist), never as a silent green.
738+ # THE SLICE RIDES IN `OS_TEST_SHARD ` (#19278), a variable turbo.json
739+ # declares on this package's `test` task and its vitest.config.ts
740+ # reads into vitest's `shard` (vitest 4.1.11 reads no shard
741+ # variable of its own). Not a `-- -- shard=k/n` passthrough, and so
742+ # neither `--only` nor `--force`. The partitioner's `--self-test`
743+ # fails a package it can slice whose config or task does not.
744+ #
745+ # Why the two flags existed, and why they are gone:
738746 #
739- # ⛔ `--force` (#18671) IS NOT REDUNDANT BESIDE `--only` -- do not
740- # delete it as a no-op. Read the paragraph above backwards: if
741- # `--only` is what stops turbo re-hashing the `^build` closure,
742- # then under `--only` this task's hash NO LONGER CARRIES that
743- # closure, and the one path by which a change in a dependency
744- # reaches this task is gone with it. What is left is the package's
745- # own files plus the hand-declared `$TURBO_ROOT$` inputs in
746- # turbo.json. So a slice that IS in the affected set -- and this
747- # shard's package set is exactly the affected set, computed two
748- # steps up -- can match a main-seeded cache entry across the very
749- # change that put it in that set, and be replayed instead of run.
747+ # `--only` (#16395). Turbo folds a run-level passthrough into the
748+ # hash of EVERY task in the run (turbo 2.10.10, cli's plan, plain
749+ # vs `-- --shard=1/2`: 0 of 62 hashes identical), so the leg
750+ # re-hashed and rebuilt the `^build` closure the step above had
751+ # just built. `--only` scheduled the test alone -- and dropped the
752+ # closure out of the test's HASH with it (#18671), leaving the
753+ # package's own files plus the hand-declared `$TURBO_ROOT$`
754+ # inputs. A slice in the affected set (on a PR, queue or push run
755+ # this shard's set IS the affected set) could then match a
756+ # main-seeded entry across the very change that put it there.
757+ # Run 34746808828 did: it replayed `@objectstack/cli:test` on
758+ # this leg -- `Cached: 1 cached, 1 total`, `73ms >>> FULL
759+ # TURBO` -- out of a log a main push run had produced ~15
760+ # minutes earlier, on a commit that did not contain the PR under
761+ # test. All six shards reported success,
762+ # `check-test-completeness` graded the replay OK, the shard
763+ # attestation said "ran to completion", and the red reached
764+ # `main`. Neither of those two can tell a run from a replay.
750765 #
751- # That is not a hypothetical. Run 34746808828 replayed
752- # `@objectstack/cli:test` on this leg -- `Cached: 1 cached, 1
753- # total`, `73ms >>> FULL TURBO` -- out of a log a main push run
754- # had produced ~15 minutes earlier, on a commit that did not
755- # contain the PR under test. All six shards reported success,
756- # `check-test-completeness` graded the replay OK, and the shard
757- # attestation said "ran to completion". Neither of those two can
758- # tell a run from a replay; the red reached `main`.
766+ # `--force` (#18671, PR #19271). Made the leg execute; a constant
767+ # bypass cannot alarm, and the hash stayed blind to the closure.
759768 #
760- # Measured on this tree (turbo 2.10.10) with a package whose
761- # `test` task has the same shape (`dependsOn: ["^build"]`), after
762- # a source change in an upstream package PLUS the closure rebuild
763- # the step above performs -- i.e. exactly this job's sequence:
769+ # A declared env reaches ONLY the task that declares it: same plan,
770+ # plain vs `OS_TEST_SHARD=1/2` is 61 of 62 identical, the one that
771+ # moves is `cli#test`, and `1/2` vs `2/2` moves that one alone. The
772+ # closure keeps the hashes the step above gave it (61 of 61 equal
773+ # to `turbo run build --filter=$PKG`) and replays, while the test's
774+ # hash carries the closure again. `cli#test`, `--dry=json`:
764775 #
765- # --only (before) 1 task `1 cached, 1 total` 81ms >>> FULL TURBO <- NOT RUN
766- # --only --force (here) 1 task `0 cached, 1 total` 1.15s <- runs
767- # no --only (option) 6 tasks `0 cached, 6 total` 1m54.963s <- runs, and rebuilds the closure
776+ # this leg, OS_TEST_SHARD=1/2 clean 1ee03ac2f26389a6
777+ # + packages/spec/src/ui/view.zod.ts 04eabd0b5a9db364 moves
778+ # + packages/types/src/env.ts 4b15652b8c493471 moves
779+ # + connector-slack/src/* (not in closure) 1ee03ac2f26389a6 still (control)
780+ # old leg, --only --force -- --shard=1/2
781+ # clean / + view.zod.ts d5e7ec263710fe59 still (the defect)
768782 #
769- # The third row is why the repair is `--force` rather than
770- # "drop `--only`": dropping it re-executes the closure the step
771- # above just built, which is #16395's bill paid twice per job.
772- # That bill re-measured TODAY at cli's real scale, same tree,
773- # `--dry=json` against a cache the passthrough-free build had
774- # just filled: the `--only` leg plans 1 task; dropping `--only`
775- # plans 60 and every one of the 60 is a cache MISS, against 57
776- # HIT / 3 MISS for the same plan without the passthrough (2 of
777- # those 3 are `#build` tasks for packages that declare no `build`
778- # script, so they never execute; the real miss is the test). Cost
779- # of re-executing that closure here, `--concurrency=2` on a
780- # SHARED container: 5m11.262s, against 60ms `>>> FULL TURBO` for
781- # the same command when its hashes are left alone.
783+ # Executed (cli, slice 1/16 for time; `packages/client/src/index.ts`
784+ # edited -- a cli dependency no `$TURBO_ROOT$` input names -- then
785+ # the step above rebuilt the closure, 57 of 59 cached):
782786 #
783- # `--force` re-executes THIS ONE TASK and nothing else, which is
784- # why `--only` stays: the two are a pair. Precedent, for the same
785- # reason in one sentence -- a gate must not be satisfiable by a
786- # replayed artifact -- is the docs-build gate's `TURBO_FORCE`
787- # below. Two things fall out of it that are worth keeping:
788- # `--summarize` now records a REAL duration for the sliced
789- # package (measure-test-shard-timings.mjs refuses to read one
790- # from a replay), and the log says `cache bypass, force
791- # executing <hash>` where it used to say `cache hit, replaying
792- # logs <hash>`.
787+ # old leg, no --force `cache hit, replaying logs` 69ms FULL TURBO <- NOT RUN
788+ # old leg, --force `cache bypass, force executing` (same hash) <- runs
789+ # this leg `cache miss, executing`, 59 of 60 cached <- runs
793790 #
794- # ⚠ What `--force` does NOT do is make the hash honest. It stays
795- # blind to the closure, so nothing in this repo yet fails when a
796- # slice leg's hash stops moving for an upstream source change.
797- set -- pnpm turbo run test "--filter=$PKG" --only --force --concurrency=4 --summarize --log-order=stream -- "--shard=$SLICE"
791+ # and on an unchanged tree this leg replays (`60 cached, 60 total`,
792+ # 104ms): with the closure in the hash a HIT means these inputs were
793+ # already tested, which is why no `--force`. Cost: 62 tasks planned,
794+ # 59 HIT / 3 MISS against the cache the step above fills (the test,
795+ # plus two `#build` tasks of packages with no `build` script, which
796+ # never execute), where the passthrough without `--only` was 62 MISS.
797+ # The step above is no longer load-bearing for correctness -- this
798+ # run schedules its own closure -- but it keeps that build on its
799+ # own stall-guard site, and here it replays. `--summarize` records
800+ # the slice only as the sha256 of `OS_TEST_SHARD` (`cliArguments`
801+ # is empty); measure-test-shard-timings.mjs resolves that digest
802+ # against the k/n the partitioner can emit and refuses one it
803+ # cannot, so a slice is never timed as the whole package.
804+ set -- env "OS_TEST_SHARD=$SLICE" pnpm turbo run test "--filter=$PKG" --concurrency=4 --summarize --log-order=stream
798805 fi
799806 LOGS="$LOGS $LOG"
800807 node scripts/run-with-stall-guard.mjs --log "$LOG" --stall-minutes 10 \
0 commit comments