ci(test-core): retire the CLI's file-level slicing by the partitioner's own slice-count derivation - #21487
Merged
Conversation
…'s own derivation, and re-point the slicing pins at fixtures The refreshed shard-timings dataset (run 36380128221) moves the mean, not only the CLI: @objectstack/spec at 1391.38s is the heaviest item, and with the CLI sliced at 2, whole as measured (733.33s), or whole at its worst reading (1231.52s), the split is 1.124x / 1.124x / 1.053x of the mean, all inside 1.3x. The smallest slice count that meets the bound is 1, so FILE_SHARDED_PACKAGES is emptied; the mechanism stays. - Pin 3c no longer substitutes the 1231.52s bridge reading for the CLI. It asks the committed dataset, for every map entry, whether n - 1 slices would also meet the bound (sliceCountProblems), with five fixtures that hold each refusal in both directions. - Pin 3b grades the real split and a cut of the dataset's heaviest package, so it is not vacuous while the map slices nothing. - The mechanism's pins (vitest floor, slice-share prediction, drift on a sliced package, weighItems slicing, the OS_TEST_SHARD wiring reader) read a fixture map through new optional `sliced` parameters. - Pin 6's inversion pair flipped in the refresh (example-todo 35.30s vs core 57.09s); the new pair is plugin-pinyin-search over sdui-parser, and a guard now reads the dataset's order so a flipped pair asks for a new pair instead of reporting a weighing defect. - measure-test-shard-timings.mjs: its live-map case holds for an empty map. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…ange replaced, so the refresh lane survives the retirement
The refresh lane's pull_request rehearsal on this branch (run 37074888579)
refused all ten eligible hourly runs on main and regenerated nothing. Every
retained run summary carries the CLI's slices as an OS_TEST_SHARD digest
of 1/2 or 2/2, and with FILE_SHARDED_PACKAGES emptied the generator's
digest matcher had no candidate for either, so it refused each summary
whole.
- partition-test-shards.mjs declares PREVIOUS_FILE_SHARDED_PACKAGES, the
outgoing map ({ '@objectstack/cli': 2 }), with when it decodes nothing:
run summaries are kept for one day.
- sliceOfEnvironment matches a digest against both closed maps, exactly by
hash. A decoded slice is still summed within its run (an incomplete set
contributes nothing), and a digest neither map names is still refused.
- measure self-test: the live-maps case covers both defaults, and a new
case reads a pre-change run's two halves into its 733.33s whole while
refusing a count neither map names. Battery floor 10 to 11.
Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
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.
Unblocks #20388 (the Test Core shard-timings refresh), which #16465 and #16468 wait on.
This PR binds no card: #20388, #16465 and #16468 all remain open. #20388 lands by itself after this merges, on its own green, through the auto-merge the maintainer armed.
What this changes
scripts/partition-test-shards.mjs --self-testnow passes on BOTH datasets: thescripts/test-shard-timings.jsononmain, and #20388's (blob84342b45, byte-identical to its head8d60ae86, overlaid unstaged in a second worktree and never committed).FILE_SHARDED_PACKAGESis emptied (the CLI's2is retired). The mechanism stays: the item grammar,expandSlices, the vitest file-count floor, theOS_TEST_SHARDwiring judge, the generator's slice reassembly, and the dormant CLI wiring inturbo.jsonandpackages/cli/vitest.config.ts.CLI_MEASURED = 1231.52bridge. It asks the committed dataset, for every map entry, whethern - 1slices would also meet the bound (sliceCountProblems), and refuses annthatn - 1could replace. Five fixtures hold each refusal in both directions: needed, retire, lower, unmeasured entry, and an entry below 2.slicedparameters (default: the live map) onsliceCountFor,weighItemsanddriftReport. The re-pointed cases are the vitest floor, the slice-share prediction, drift on a sliced package, observed-run-wins,weighItemsslicing, and the wiring reader pointed at the CLI's real tree.example-todoovercoreflipped in the refresh (35.30s vs 57.09s). The new pair isplugin-pinyin-searchoversdui-parser: 2 vs 13 test files, 14.40s vs 1.62s onmain's dataset, 38.77s vs 4.54s on chore(ci): refresh the Test Core shard-timings dataset #20388's. A new guard reads the dataset's own order, so a flipped pair asks for a new pair instead of reporting a weighing defect.PREVIOUS_FILE_SHARDED_PACKAGES(new, beside the map) holds the outgoing map,{ '@objectstack/cli': 2 }. The generator's slice-digest matcher decodes a digest against both declared maps, exactly by hash, so a run summary written before this change still reads. Without it, the refresh lane refused every run onmain; see the next section. A decoded slice is still summed within its run (an incomplete set contributes nothing), and a digest neither map names is still refused. The map has no reader once a day has passed, because run summaries are kept for one day (retention-days: 1).scripts/measure-test-shard-timings.mjs(outside the claimed surface, and why). This is the matcher change above. Its live-map case also readFILE_SHARDED_PACKAGES['@objectstack/cli'], which reds under an empty map (measured: the unedited file exits 1). That case now covers both live maps, and a new case reads a pre-change run's two halves into their 733.33s whole while still refusing a count neither map names. The env-carried battery floor goes from 10 to 11. A stale "(2 for @objectstack/cli today)" parenthetical is dropped.Battery floors are raised to the measured counts: balancing pins 21 to 25, OS_TEST_SHARD wiring 9 to 11. File-level slice items stays at 20. The counts are the same on both datasets.
The three bin readings, and the keep-or-retire choice
Predicted bins at 6 shards against the 1.3x bound, using the partitioner's own
partition/balanceOf/expandSlices:main(70 pkgs, 3997.47s)mainmainOn #20388's dataset, both R and R-worst meet the bound, and slicing changes no bin's maximum (spec is the heaviest item in all three cases). Solving C ≤ (1.3/6)(6696.67 + C), the CLI fits whole until about 1852s, which is 1.5x its worst reading. The file's own rule makes n the smallest count that meets the bound. That count is 1, so the entry is retired.
Four axes:
Test Core (5/6)and 6m43s on(6/6), and 5/6 was the longest job at 19m23s.2would leave a count no pin can justify. The old counterfactual cannot be rewritten on any measured basis, because R-worst meets. Retirement keeps the mechanism, and pin 3 (the floor) is the live trigger to slice again.The refresh lane across the change: red, then green
c614a094. This PR'spull_requestrehearsal ofshard-timings-refresh.yml(run 37074888579, job 111062437870) refused all ten eligible hourly runs onmain, 37010481060 through 37070188866. It then ended with "The 0 eligible run(s) ... NOTHING was regenerated".main's dataset in the exact turbo 2.10.10 shape: six whole-leg summaries, plus two slice legs whoseOS_TEST_SHARDdigest is the sha256 of1/2or2/2(d939926f…, the measured format). It was fed to the lane's own two commands: the generator with--run/--merge-into, thenselect-shard-timings-run.mjs --check-coverage.aa463223(the map{cli: 2}): exit 0, coverage OK.c614a094(the empty map): exit 1, "matches no slice the partitioner can emit for it (none: FILE_SHARDED_PACKAGES does not slice it)".d049d353: exit 0, coverage OK, and apackagesmap identical toaa463223's.d049d353does: run 37075730446 (job 111065090886) is green. It accepted its first candidate, with no "dropping that run" warning, somain's real env-carried summaries decode once the matcher knows the outgoing map.d049d353: a post-change run alone gives exit 0 (cli whole, 740s). A post-change run accumulated with a pre-change sliced run gives exit 0 (cli 599.08s, the median of 740 and 458.15). So a refresh that straddles the merge also reads. It is still a prediction: it depends on an eligible full-battery run existing, as every refresh does.Self-test on both datasets (head
d049d353)The BEFORE red reproduces #20388's AFTER block on today's
main(line 1075 now, 967 in that body). It also mislabels spec's 1391s as the CLI's, because the old counterfactual read the overall heaviest item. A second red was masked behind it. With the 3c throw muted onaa463223, pin 6 reds on #20388's dataset with "The run is weighing test-file count again". That is a misdiagnosis: the pair had flipped.Mutation proof, one per rewritten or added pin
Every leg was taken from committed
c614a094throughscripts/ablation-replace.mjs. The whole table plus N1 to N4 was then re-run from committedd049d353on both datasets: 48 legs, every one landed and restored. In each leg the anchor hit 1 and the replacement went 0 to 1. Each leg was restored to the HEAD blob withgit diff HEADempty, under a shelltrapthat re-proved the hashes in both worktrees at the end. The red line below is the self-test's firstError:, the same on both datasets unless shown.'@objectstack/cli': 2to the live mapslice derivation, committed dataset (1 of 1 ...), "sliced 2 ways at 458.15s (main) / 733.33s (#20388), but at 1 the split already meets 1.3x ... Retire the entry"meetsBoundalways meetsa count of 2 that 1 cannot replace was refuseda package that fits whole kept its slicing with no refusala count of 3 where 2 meets the bound was acceptedan entry the dataset never measured was acceptedan entry of fewer than 2 slices was acceptedexpandSlicesstops slicingslice spread: cutting @objectstack/cli (main) / @objectstack/spec (#20388) in two produced no ... pair to grademain(the pair still holds there); on #20388:the dataset no longer measures @objectstack/example-todo slower than @objectstack/core (35.3s vs 57.09s) ... Pick a new inversion pairweighItemsweighs test-file countweight: @objectstack/plugin-pinyin-search weighed 2 and @objectstack/sdui-parser weighed 13 ...slice count: a package outside the slice map was slicedsliceCountForignoresslicedslice count: the configured package did not read its configured countslice floor: slicing below the test-file count was not refused (no throw)prediction: a sliced package was charged its WHOLE dataset entrydriftReportignoressliceddrift: a sliced overshoot read 0.83x and was not reported as driftdrift: an observed WHOLE run was charged a slice-sized prediction (1.67x)weighItemsignoresslicedweighItems: 1 package(s) produced 1 item(s), expected 2slice wiring: judged 1 of 0 sliced package(s) ...packages/cli/vitest.config.tsreadsOS_TEST_SHARD_UNREADslice wiring, the tree read through a fixture map ... never reads OS_TEST_SHARD into vitest's shardsamplesFromSummary's defaultslicedis not the live mapenv slice: a @objectstack/cli digest of 1/3, a count neither live map names, was not refused listing (1/2, 2/2) (got "no throw")@objectstack/cli ran with OS_TEST_SHARD set ... matches no slice the partitioner can emit for it, or emitted under the map it replaced (none: ...)samplesFromSummary's defaultpreviousis not the live onesamplesFromSummarydrops itspreviousargumenta: cli ran with OS_TEST_SHARD set (digest d939926f…) ... matches no slice ...env slice: a @objectstack/cli digest of 1/3, a count neither live map names, was not refused listing (1/2, 2/2)Premise checks (the dispatch's A1 to A4)
aa463223: the map was{ '@objectstack/cli': 2 }, pin 3b carried the 1231.52s/800.7s prose, and pin 3c carriedCLI_MEASURED = 1231.52.main; see BEFORE above.main: 70 packages, 3997.47s, cli 458.15s, spec 403.65s. On chore(ci): refresh the Test Core shard-timings dataset #20388: 72 packages, 7430.00s,measuredAt2026-09-28, runs[36380128221], spec 1391.38s (heaviest), cli 733.33s. The two new packages areorganizationsandvitest-filter-preflight. The package set equals today's workspace minus the CI-excludeddogfood.provenancekeys, and byte-identicalnote,mergeRuleandrefreshstrings. It accepts the file as a--merge-intotarget (carriedspecon a HIT witness).skippedAsCached,skippedIncompleteSlicesandcarriedOverare all empty, and the CLI's 733.33s is a two-slice sum from one run. The 09-28 run carried its slices as a--shardpassthrough, which today's generator still reads (sliceOfCliArguments). Its run-summary artifacts are no longer retained (the run lists onlytest-core-timing-tableandbuild-output), so a byte-level re-generation is NOT MEASURED.Consequences outside this diff (known, deliberate)
c614a094, green atd049d353.test-nightly-tiers.ymlpartitions the one tier-owning package at 2 shards. Measured locally: shard 1/2 now carries@objectstack/cliwhole, and 2/2 carries nothing ("No packages on this shard", exit 0). The run stays inside its 45-minute timeout by its own header's estimate. Its header prose and its 2-shard matrix are now stale; no carrier.mainthen splits on the stale weights with the CLI whole. Modeled with chore(ci): refresh the Test Core shard-timings dataset #20388's weights standing in for real cost: the heaviest actual bin stays spec's (1775s sliced, 1773s whole). The CLI's bin is 1116s at 733.33s, or 1614s at 1231.52s. Mergingmaininto chore(ci): refresh the Test Core shard-timings dataset #20388 right after this lands keeps the window short.Gates (head
d049d353)node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(change set from git, 2 paths) derived 32 families. The list is the same onc614a094andd049d353. On both heads, all 32 ran with exit 0, recorded and reconciled by--ran: "32 derived, 32 run, 0 NOT-MEASURED, 0 UNRUN".node scripts/report-test-timings.mjs --self-testalso ran, exit 0. The list includes the three self-tests (partition / measure / select-shard-timings-run),check:cross-package-test-inputs,check:nul-bytes,check:pm-dispatch-gates(1976 cases, 977s),check-scripts-symbol-anchorsandcheck-self-test-wired.Lint, narrowed and proven.
eslint --no-inline-config --format jsonon the 2 changed files reports 2 files, 0 errors and 0 warnings on both heads, and neither file is ignored.--print-configshows 2 per-file rules (no-restricted-imports,comment-swallow/no-code-inside-block-comment) and noparserOptions.projectorprojectService. Type-aware linting is off, so this diff cannot move any untouched file's verdict. The fullpnpm lintis CI's.skip-changeset: rootscripts/ships in no package'sfiles[](the root package is private).Acceptance notes
testandtest:repowindows, and the windows overlapped. Spec is now the floor, at about 83% of its own breach point (about 1670s). ci: a per-package suite-duration ratchet — a PR that makes a suite exceed its measured ceiling is red; ceilings rise only by ruling (maintainer-directed, growth constraint) #16468's ceilings will read this number.::error::blames a coverage shortfall ("a suite failed, a package was renamed or removed, or its slices could not be assembled") rather than the refusals, as run 37074888579 showed. No public door; no carrier.ci.ymlslice-leg comments and the 1231.52s note at its drift step are for ci: Test Core compares each shard's measured duration with its predicted weight — warning at 1.3x, red at 70% of the timeout (maintainer-directed, drift alarm) #16465, which edits that file.packages/cli/vitest.config.ts's "partition-test-shards.mjs slices this package" has no carrier. Thetest-nightly-tiers.ymlheader and matrix have no carrier.shard-timings-refresh.yml's "pin 3c ... the day the CLI comes back under the bound" is still true in mechanism; no carrier.Generated by Claude Code