Refuse a Debug-measured coverage report in the ratchet #206
Loading…
Reference in a new issue
No description provided.
Delete branch "coverage-ratchet-configuration"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes task 269.
check-coverage-ratchet.csnow takes ReportGenerator's merged Cobertura report (newCoberturareporttype in CI) as a required third argument, and refuses to run — exit 3, before any comparison — unless the generated-file paths in it name Release. Detection readsobj/<Configuration>/from the on-disk paths Roslyn source generators (the[LoggerMessage]generator CA1848 mandates) write into, rather than inferring anything from the coverage numbers themselves. If detection is inconclusive — no generated-file path present, e.g. a report scoped to one generator-free project — it refuses too, rather than warning and proceeding. That branch is the one a contributor iterating locally on a single assembly would actually hit, and it's the exact path task 269 exists to protect, so it gets the same refusal as a confirmed Debug report, not a disclaimer.CONTRIBUTING.md and the script's own header/usage state the Release requirement at the point of use.
Also folded in task 261's truncation trap: a comment on the
--updateblock says baseline figures must come from the script's own output, never hand-derived fromcoveredlines/coverablelines, since ReportGenerator truncates rather than rounds.Watched to fail, all against real reports:
Full-solution Debug:
PlaceMark.Domain.Tests-only Debug report (no source-generator assembly present — the inconclusive case the review found):Full-solution Release:
No warning or refusal on the Release run — CI's report is always full-solution and always includes Api/Infrastructure's generator, so this doesn't touch CI's green path (confirmed: run #852, jobs
build/e2e/container-imagesallsuccessat the prior head).@ -35,0 +63,4 @@return 3;}if (buildConfiguration is null)Confirmed live: a Cobertura report scoped to a generator-free project (built and merged
PlaceMark.Domain.Testsin Debug —PlaceMark.DomainandPlaceMark.Contractscarry no[LoggerMessage]usage) hits this branch and the script proceeds silently, exit 0, on a genuinely Debug-measured report. That's the exact trap task 269 exists to close, reappearing behind a warning instead of a refusal.Today's CI invocation is safe because the merged report is always full-solution and Api/Infrastructure's generator is always present (verified: their virtual
obj/Release/net10.0/...LoggerMessage.g.cspaths do show up in the Cobertura output even though the files never touch disk, sinceEmitCompilerGeneratedFilesisn't set — the mechanism works as described). But nothing stops a narrower local report from reaching this branch with the warning easy to miss among other output. Given the ticket's own bar ("refusing, or printing an unmissable warning"), consider refusing (non-zero exit) when detection is inconclusive rather than assuming Release, or at least flag the limitation in CONTRIBUTING.md's local-reproduction instructions.@ -122,0 +176,4 @@@"[/\\]obj[/\\](?<configuration>[^/\\]+)[/\\]",RegexOptions.CultureInvariant);var coberturaDocument = XDocument.Load(coberturaPath);Minor, not a regression: a missing/mistyped
<cobertura.xml>path crashes with an unhandledFileNotFoundExceptionand a raw stack trace rather than the script's own clean usage error — confirmed. Matches the existing (lack of) handling forsummaryPath/baselinePaththough, so low priority.Verdict: mergeable
Re-derived the core claims against real reports (not the PR's pasted account), from
main:PlaceMark.Api.TestsCobertura report against a Release-derived baseline: refuses, exit 3, matching the PR's own evidence.[LoggerMessage]-generated code's virtual path (obj/<Configuration>/net10.0/...LoggerMessage.g.cs) appears in coverlet's Cobertura output even though the generated file never touches disk (EmitCompilerGeneratedFilesisn't set) — the regex has a real signal to read, as claimed.obj/Debugandobj/Releasecoexisted on disk from prior builds throughout, and each configuration's own build/test/merge only ever produced its own configuration's paths — no cross-contamination observed.c7c09b1:build,e2e,container-imagesallsuccess.ci.ymlpasses the new third arg;CONTRIBUTING.mdnever hardcodes the full invocation, so it isn't broken by the new arg.ci.ymlchange is in the unrelatede2ejob'sconcurrencyblock (~line 302+), well clear of this PR'sbuild-job hunks (~184–201). No textual conflict.One real gap found and left inline: the "no generated-file path → warn and proceed" branch is reachable on a genuinely Debug report whenever the merged report doesn't happen to include an assembly with a source generator (reproduced with a
PlaceMark.Domain-only report) — safe today because CI's own report is always full-solution, but a silent trap for any narrower local run. Worth tightening, not worth blocking the merge over, since it doesn't weaken what this PR was scoped to fix.@ -33,2 +49,4 @@var coberturaPath = args[2];var updateBaseline = args.Contains("--update");var buildConfiguration = DetectBuildConfiguration(coberturaPath);Confirmed: this now falls inside the refusal block (exit 3) rather than the old "warn and proceed" path. Re-derived independently — built a Debug
PlaceMark.Domain.Tests-only Cobertura report and ran the script against it: refuses, exit 3, matching the PR's evidence. Reverting this line's containing condition back tobuildConfiguration is not null && buildConfiguration != "Release"(the pre-fix shape) against the same report drops the clean refusal and produces a confusing partial failure instead (missing-baseline noise plus a misleading "Domain has dropped below its baseline" line) — confirms this branch is what's discriminating, not incidental.Verdict: mergeable
Round 1's blocking finding is fixed: the null (inconclusive) case now sits inside the refusal block (exit 3) instead of warning and proceeding. Re-derived independently, not from the author's account:
PlaceMark.Domain.Tests-only Cobertura report (the known scoped/generator-free reproduction) and ran the script: refuses, exit 3, with the "could not determine the build configuration" message.buildConfiguration is not null && buildConfiguration != "Release") and reran against the same report: the clean refusal disappears and it instead falls through to a confusing partial failure (missing-baseline noise for the five unscoped assemblies plus a misleading "Domain has dropped below its baseline" line) — confirms this is the discriminating line, not an untestable assertion.git diffbetweenc7c09b1and this head for the script shows only this branch changed (warn+proceed → refuse) plus the required third argument and header/usage text; the Release-vs-named-Debug comparison andDetectBuildConfigurationregex logic are untouched, so round 1's other confirmations (full-solution Debug refuses, full-solution Release passes clean, the LoggerMessage virtual-path detection mechanism) still stand.ci.ymlpassescoverage-report/Cobertura.xmland addsCoberturato-reporttypes, and it's the only invocation in the workflow.CONTRIBUTING.mdnever hardcodes the full command, so it isn't broken by the arg change, and its new paragraph correctly says the script "refuses to run" (not "warns") — matches the code. No opt-out flag was added.3083c26):successat run level, consistent with the brief's job-level confirmation; not re-run.Non-blocking, carried over from round 1's review comment 1975 and unaddressed here (fine to leave): a missing/mistyped
<cobertura.xml>path throws a rawFileNotFoundExceptionrather than a clean usage error, matching the existing (lack of) handling for the other two path arguments.rob referenced this pull request2026-08-21 11:01:22 +00:00