Repository navigation
ci(repo): give the release gate's shard reports one layout for any shard count - #76
Merged
Merged
Conversation
…ard count Main's verdict job failed run 37892133106 with every planned mutant "missing from the shard reports" although the one shard's stream held them all. download-artifact extracts a lone pattern match straight into its path and only nests artifacts under their names when several match, so with one shard the reports were not under mutation-shard-0/. The plan also sat in .cache/, so its ../packages/<name> project paths climbed out of each shard's reports/shards/<index> directory. The plan now lives at the repository root, so its project paths are packages/<name> and shard k writes reports/shards/<k>/packages/<name>/. Each shard uploads that directory alone, and the verdict downloads every shard artifact with merge-multiple, so shard k's reports are at .cache/shard-reports/<k> whatever the shard count. The per-shard HTML report moves to its own artifact. The sandbox proof now builds the verdict workspace from the workflow's own plan, upload and download steps for one shard and for two, and checks every planned mutant's stream is where merge looks. On main's workflow its one-shard case fails with the production error.
…se std path helpers The proof derived where the stryker-plan artifact lands twice and wrote the plan file twice; one helper each now does it. common from @std/path replaces the hand-written common-root helper, the workflow is read and decoded once, and the merge parser stops keeping the --out value no check reads. The verdict step drops its mkdir -p .cache: the dev-shell action already creates .cache, and the fixture now mirrors that.
…eads stryker gate reads reports/mutation/mutation.json from a constant in the stryker-js bundle, and only the verdict step's `stryker merge --out` puts the merged report there. The proof stopped checking --out in the simplify commit, so a changed --out left it green while the gate would fail. The proof now reads GATE_REPORT_FILE from the installed bundle, the same way it reads SHARD_OUT_MARKER, and fails both verdict cases when merge writes anywhere else.
Contributor
There was a problem hiding this comment.
Fresh review PASS on f1edb29; 7/7; 0 threads; hunt clean; real-artifact proof in body.
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.
Summary
Main's Release gate (run 37892133106 on
21fe21ef, #74's verdict job) failed withexit 1 (VerdictFail): planned mutant(s) missing from the shard reportsnaming all 114 planned mutants. The one shard'smutation-stream.jsonlholds all 114 (37 Killed, 6 Timeout, 71 CompileError, verdict score 100). The verdict read the wrong directory. This PR gives the shard reports one layout for any shard count.Root cause
Two layout facts, both read from source and from the run itself:
pattern: mutation-shard-*andmerge-multiple: false, download-artifact v6'srunextracts intopath/<name>only when more than one artifact matches; a single match goes straight intopath. The verdict log shows it:Starting download of artifact to: /home/runner/work/xstate/xstate/.cache/shard-reports, with nomutation-shard-0/. The plan had one shard, so the jq's.cache/shard-reports/mutation-shard-0/...did not exist. With two or more shards the old jq would have resolved, which is why only a one-shard plan exposed it.stryker planwrites project paths relative to the plan file's directory, so a plan in.cache/records../packages/xstate. stryker-js 17's shard runner writes tojoin(<planDir>/reports/shards/<index>, project), which normalises to.cache/reports/shards/packages/xstate: no<index>directory, and every shard writes the same path. Merge applies the samejoin(dir, project), so the missing index cancelled out, but the per-shard output was never unique.upload-artifact did not trim anything: the old upload had two globs (
.cache/reports/shards/**andpackages/*/reports/mutation-report.*), whose least common ancestor is the workspace root, so the artifact kept full paths. That matches the downloadedmutation-shard-0.Canonical layout
stryker-plan.json(gitignored). Project paths arepackages/<name>.kwritesreports/shards/<k>/packages/<name>/(stryker-js's default--out).reports/shards/. A single upload path is the artifact's root, so artifactmutation-shard-<job>holds<k>/packages/<name>/.mutation-shard-*withmerge-multiple: trueinto.cache/shard-reports, giving.cache/shard-reports/<k>/packages/<name>/for one shard or many..shards[] | ".cache/shard-reports/\(.index)", in plan order. It no longer needs the matrix lookup, because the artifact name no longer decides the directory.mutation-report-shard-<job>artifact, outside themutation-shard-*pattern.Proof against the real artifacts of run 37892133106
Source: the conductor's copies of
stryker-planandmutation-shard-0(xstate.worktrees/.rulings/artifacts-37892133106/, laid out asgh run download -n <name>writes them). Every file matches my owngh run download 37892133106by sha256. Each tree below is a scratch copy; the originals are untouched. Onlystryker mergeandstryker gateran (inside the repo's Nix dev shell); no mutants ran.1. Main's verdict command over CI's download layout reproduces the production failure. A pattern download that matches one artifact extracts straight into
path(download-artifact v6, theartifacts.length === 1case), so the tree is.cache/stryker-plan.jsonplus the shard's files directly under.cache/shard-reports/. The failure line is byte-identical to the CI log:2. This PR's verdict command over the same bytes in the layout this PR's download steps produce (
stryker-planto.,mutation-shard-*withmerge-multipleinto.cache/shard-reports) is also red. These artifacts came from main's plan and upload steps, not this PR's: the plan says../packages/xstate(written to.cache/), and the shard upload is rooted at the repo, so it holds.cache/reports/shards/...instead of1/packages/xstate/.... The verdict never sees a matching tree:3. The same bytes placed as this PR's plan and upload steps write them: exit 0 with the merged counts. Two changes. The plan sits at the root with its one project path as
packages/xstate, which is whatstryker plan --out stryker-plan.jsonwrites; the 114 ids and the shard index are unchanged. The shard'spackages/directory (byte-identical) goes under.cache/shard-reports/1/, wheremerge-multipleputs shard 1'sreports/shards/upload. The command is this head's verdict step, byte-identical to the workflow:The merged
reports/mutation/mutation.jsonholds 114 mutants: 37 Killed, 6 Timeout, 0 Survived, 0 NoCoverage (71 CompileError).4. Sabotage: the
mutantline for7bd13569d6302fbbdeleted from a copy of tree 3's stream: exit 1, naming the id.5. Gate check: in a copy of tree 3, one Killed mutant (
48a4b106fb2a618c) changed to Survived: exit 1, naming the id.Rows 2 and 3 are the limit of what the old run can prove: no artifact in the new layout exists until this merges. The first Release gate run on main after merge is the end-to-end check, and I will read it.
Sandbox proof (predicate 3)
sandbox-proofs/release-gate.test.tsnow builds the verdict job's workspace from the workflow itself: the plan where the plan step writes it, each shard's stream at stryker-js'sSHARD_OUT_MARKER(read from the installed dist), the upload root of themutation-shard-*upload, and download-artifact's extraction rule for the verdict's download step. It runs the verdict step in the sandbox with a recordingstrykerstub, resolves each shard directory merge receives the way merge does (join(dir, project)), and fails naming every planned mutant whose stream isn't there. It also requires merge's--outto be the directory of the gate'sGATE_REPORT_FILE, read from the same dist. It covers one shard and two shards listed in reverse matrix order. The old case pinned the jq's literal output, which is why a layout drift passed it; that case is gone.On main's workflow (this test file only, in a scratch worktree removed afterwards), the one-shard case fails with the production error:
On this head:
Sabotages of this head's workflow, each in a scratch worktree removed afterwards:
merge-multiple: trueremoved:shard upload back to the two globs:
jq dir
.cache/shard-reports/mutation-shard-<index>:--out reports/merged(control on the same scratch base:ok | 8 passed):Gates on f1edb29
pnpm format:check0,deno checkanddeno lintonsandbox-proofs/release-gate.test.ts0,pnpm test:sandbox0 (8 passed). The solution docdocs/solutions/workflow-issues/sharded-mutation-gate-without-verdict.mdis updated to the new layout, and its validator exits 0. No package changes, so no changeset.Review
A local adversarial review of
fdff4f1a5found two P3s and no P0 or P1. (1) After the simplify commit the proof no longer checked merge's--out, the only link to the gate's hard-coded report path. That is fixed inf1edb2921, and the--outsabotage above is red. (2) A shard that uploads no artifact (if-no-files-found: ignore) is not modelled. That is advisory and left as is: production fails closed there, because merge raisesShardReportGapfor a planned mutant with no stream, so it can't pass vacuously.Declared (CONST-W3 / CONST-E9)
.github/workflows/release-gate.ymland its sandbox proof are judgment surfaces. They are edited here at the conductor's direction (ruling cycle 190), which owns them. This PR grades none of my capability work.timeoutMSis unchanged.No local mutation run.