Repository navigation
Coverage gate: replace the global MaxSkipped ceiling with per-file skip attribution #132
Description
Activity
- addedstatus:agent-readyScope and approach are unambiguous enough for an agent to pick up unattended.Scope and approach are unambiguous enough for an agent to pick up unattended.priority:P3Nice to have. Safe to leave indefinitely.Nice to have. Safe to leave indefinitely.size:SOne sitting. Single file or a mechanical change.One sitting. Single file or a mechanical change.area:ciWorkflows, gates, Pester scoping and test economics.Workflows, gates, Pester scoping and test economics.source:driftOpened from a drift-report finding, by tooling.Opened from a drift-report finding, by tooling.
on Sep 21, 2026 juemerson-at-purestorage commented
on Sep 21, 2026 CollaboratorAuthorMore actionsWritten by Claude during triage, reviewed by @juemerson-at-purestorage before posting.
Agent Brief
Category: bug
Summary: Establish whether PR #135'sExpectedSkipsfully satisfies this issue's ask, then either recommend closure with evidence or state precisely what remains. This is a close-out, not an implementation.Verification: n/a — cannot reach the wire. This is test-infrastructure work with no request path.
Read this before starting.
flywheel/issue-triage.mdrecords that this issue is "FIXED by PR #135, merged 2026-08-21 —ExpectedSkipsis now an exact per-file pin. Close it, or say what remains." That claim has not been checked against the merged code. Do not assume it is true and do not assume it is false — this issue exists because a ceiling with headroom silently drifted from what its own comment claimed, so an unverified belief about a coverage gate is exactly the thing this issue is about.Current behavior:
The issue was filed against a single globalMaxSkippednumber per edition in the test coverage baseline. Because it was a ceiling with headroom rather than a pin, it absorbed skip movement until an unrelated later change crossed the line, then failed that change instead of the one that caused the drift. The issue documents the incident with exact arithmetic: 292 measured against a ceiling of 268, where 6 of the +40 belonged to a PR two days earlier that had passed on slack and the next branch across the line was billed for all forty.The issue proposes a per-file
ExpectedSkipsmap as the fix. PR #135 is reported to have shipped exactly that.Desired behavior:
One of two outcomes, whichever the evidence supports:- The ask is met. A comment states what shipped, cites the merged code, and shows that each of the issue's stated problems is addressed. Recommend closure as
completed; do not close it — that is the maintainer's call. - Something remains. A comment names precisely what, in terms of the issue's own three complaints: unattributable reds, invisible coverage regression bounded by the headroom, and a stale ceiling whose comment misstates its own slack.
Key interfaces:
- The coverage baseline data file and whatever gate script reads it. Find them by searching for the
ExpectedSkipsandMaxSkippedkeys rather than by any path quoted here or in the issue — the issue predates the fix and its paths may have moved. - The question to answer about the shape: is
ExpectedSkipsan exact per-file pin (a file measuring fewer skips than expected also fails), or a per-file ceiling? Only the exact pin closes the invisible-regression half of the complaint. A per-file ceiling is a smaller version of the same bug. - Whether the global
MaxSkippedstill exists alongside it, and if so whether it can still drift.
Acceptance criteria:
- A comment on the issue states, with the merged code as evidence, which of the issue's three complaints are addressed and which are not.
- The pin-versus-ceiling question above is answered explicitly, not implied.
- If anything remains, it is stated as a concrete change, not as "further work needed".
- A recommendation to close or to keep open, with the reason. The issue is not closed by this work — recommend, and leave it.
- No source change is made. If the investigation finds a real remaining defect, it is reported, not fixed; fixing it is a separate task with its own review.
Out of scope:
- Implementing anything. Even if a gap is found. This brief buys an answer, not a patch.
- Closing the issue. Triage permission allows it; the standing rule is that closure and its reason are the maintainer's call.
- Re-running the full suite to produce fresh skip numbers. The aggregate run is never a task's own completion check here, and a number measured in a worktree missing the
tools/specs/cache differs from one measured with it — roughly 27 tests are spec-cache-gated and skip without it. If a number is needed, say which environment it assumes. - Issue CI silently skips ~23% of the test suite, including the absolute-path regression guards #63 (CI skipping ~23% of tests). Adjacent and a superset of the invisible-coverage concern, but a separate issue with a separate fix.
- The ask is met. A comment states what shipped, cites the merged code, and shows that each of the issue's stated problems is addressed. Recommend closure as
Problem
The
MaxSkippedceiling inTests/coverage-baseline.psd1is a single global number peredition. Because it is a ceiling with headroom rather than a pin, it silently absorbs skip
movement until some later, unrelated change crosses the line — and then it reds that change
instead of the one that caused the movement.
This is not hypothetical. It just happened, and the arithmetic is exact.
The incident
A local Windows PowerShell 5.1 full-suite run measured 292 skipped against the ceiling of
268, so the gate failed. Attributing that 292 by source file shows the +40 over the 252 that
originally justified 268 splits in two:
Update-PfbTestModuleImport.Tests.ps1#Requires -Version 7.0, so the PS7 gate is correct, and the file runs in full on the pwsh7 leg.Build-PfbDeadKeyReport.Tests.ps1So #120 added 6 legitimate PS7-gated skips and never needed to touch the ceiling, because at
258 measured against 268 it still had slack. It passed. The ceiling was then stale — carrying
10 headroom, not the 16 its own comment claimed — and the next branch to cross the line was
billed for all 40, including #120's 6.
Why the headroom is the mechanism, not the mitigation
Headroom exists to avoid false reds. What it actually does is convert an attributable red
on the PR that caused the movement into an unattributable red on a later innocent PR. That
is strictly worse for whoever has to diagnose it: they get a number that is wrong by an amount
they did not cause, with no signal telling them which part is theirs.
It also means a real coverage regression of up to
MaxSkipped - measuredtests is invisible.That is the issue #63 failure shape — green summary, lost coverage — just bounded in size.
Proposed design: per-file expected skips
Replace (or supplement) the global ceiling with a per-file map of expected skip counts.
Assertion becomes: for every file, actual skips equal expected. Then
maintainer actually wants to eyeball;
being absorbed by slack;
a ceiling structurally cannot see;
This composes with the existing
RequiredDescribesallowlist rather than replacing it. Thatlist catches a Describe vanishing from the result tree entirely (contributing neither a skip
nor a pass), which per-file skip counts still cannot see.
Data already gathered
Full per-file skip attribution from the 5.1 run described above (2983 passed / 0 failed / 292
skipped). The 19 entries sum to exactly 292, so this is complete, not a sample:
Corresponding pwsh7 leg for the same tree: 3273 passed / 0 failed / 2 skipped against its
ceiling of 8 — which is why these files being PS7-gated is correct behaviour rather than lost
coverage.
Caveat on provenance: both figures are local runs, not CI run numbers like the ones cited
in
coverage-baseline.psd1today. Expect CI onwindows-latestto differ slightly. Theper-file shape is what matters here, not the absolute totals.
Implementation notes
No log parsing needed.
Assert-PfbTestCoverage.ps1already receives the result object, andthat object carries the file per test. Verified directly on Pester 6.0.1, both editions:
$Result.Tests[].ScriptBlock.File— full path of the source file for each test.$Result.Containers[].Item— aFileInfoper container, so.Namegives the leaf.Both are available alongside the existing
.Path[0](top-level Describe) and.Resultthatthe current assertions already use, so this needs no new plumbing in the gate's signature.
Gotchas worth knowing up front:
between a normal checkout and a worktree.
Tests/currently has no test files in subdirectories, so leaf names are unique today. Ifthat changes, a leaf-keyed map silently merges two files — worth a uniqueness assertion.
pwsh7andwinps51) need the treatment. They differ by a widemargin by design: the tooling Describes are PS7-gated, so the 5.1 leg skips essentially all
of them.
Import-PowerShellDataFilecannot parse a single collection literal with more than ~500entries. A ~195-entry hashtable per edition is well clear of that, but the two blocks should
stay separate hashtables rather than being merged into one flat list.
??, no&&/||. It runs under both editions.deleted) is the interesting design question — that is the graceful-skip hole
RequiredDescribesexists for, and a per-file skip map has the same blind spot unlessabsence is treated as a violation.
Reproducing the current numbers
The attribution above was produced by scraping a saved full-suite log, purely because the run
had already finished. This is a one-off diagnostic, not the shape the real implementation
should take — use the result object instead, as above. Included only so the numbers can be
re-derived from any existing log.
Sanity check: the total must equal the run's reported skipped + not-run count. If it does not,
the boundary detection is wrong and the per-file numbers cannot be trusted.
Open questions for the maintainer
file-level map drifting out of date, but two overlapping assertions on the same quantity may
not be worth the maintenance.
test reds CI until the map is updated in the same PR. That is the point, but it is a real
increase in required diff churn.
Cheap interim alternative
If the per-file map is more churn than wanted, setting
MaxSkippedto the measured value withzero headroom captures most of the benefit for a one-line change: movement then reds the PR
that caused it rather than a later one. It still cannot say which file moved, and it cannot
detect a test that stopped skipping.