fix(vscode): persist the post-processed Cobertura document before the coverage-threshold assertion (#565) - #753
Merged
drmoisan merged 14 commits intoSep 3, 2026
Conversation
…rdering fix Promotes existing issue #565 into an active full-bug feature folder (issue.md, spec.md, research), and authors an atomic plan reordering Invoke-MSTestWithCoverage.ps1's Set-Content ahead of the coverage threshold assertion so a failing gate leaves the post-processed Cobertura document on disk instead of the raw pre-#441 output. Preparation-mode only: atomic execution, PR authoring, and CI monitoring are deferred to parallel-orchestrator. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTjXvNFHVh7Fo7kYGgWsx2
…r stops misreading them as writes The parallel-run blast-radius harvester extracts every backtick-delimited, whitespace-free, repository-relative path token from spec.md and the plan and treats each as a write target, with no notion of surrounding polarity. spec.md and the plan quoted several scope-EXCLUSION paths inside backticks (files this fix must not touch, plus the .claude/**, .codex/**, .agents/**, config/blast-radius.json, and config/orchestration-routing.json shared-surface excludes), so the harvester believed this item writes those shared trees, causing false contention with every other item in the bugs-2026-09-02 run. - Added an explicit "## Write Set" section to spec.md naming the plan's two actual write targets: scripts/vscode/Invoke-MSTestWithCoverage.ps1 and tests/scripts/vscode/Invoke-MSTest.RunSettings.Tests.ps1. - Rewrote every exclusion/context-only path mention in spec.md and the plan (Invoke-MSTestWithCoverage.Helpers.ps1, Invoke-MSTestWithCoverage.ClosureFilter.ps1, the non-modified sibling Pester test files, the Phase 0 policy-read list, and the five shared-surface excludes) as plain prose, with backticks removed. - No task text, acceptance-criterion substance, command, evidence path, or the 80% coverage threshold value was changed. Text-presentation revision only. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LTjXvNFHVh7Fo7kYGgWsx2
…coverage-threshold-before-setcontent-565
Records policy reads, feature-document reads (with #733/#748 drift notes), branch/commit baseline (BASELINE_SHA=dc5e8c0f...), citation verification (drifted-anchor branch taken for both checks), and PoshQC format/analyze/test baselines for the ordering fix in Invoke-MSTestWithCoverage.ps1. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…efect Adds the new It block to Describe 'Invoke-MSTestWithCoverageMain', inserted before the #733 '.claude worktree' test per the plan's primary-anchor resolution (the secondary anchor is now ambiguous after #733/#748 added an intervening test). Confirms RED against the pre-fix order: only the new test fails (Set-Content invoked 0 times, not 1), all 27 other tests in the file pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pure statement reorder in Invoke-MSTestWithCoverageMain: Set-Content now persists the post-processed Cobertura document immediately after it is computed, before Assert-CoberturaLineCoverageThreshold can throw on a sub-threshold run. Applied at the drifted-anchor location (actual lines 342/344, post-#733 Get-Content insertion) per re-derived P0-T4 citations. No change to Helpers.ps1, ClosureFilter.ps1, or Threshold.ps1 (confirmed by empty diffs against BASELINE_SHA). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…y tests Invoke-MSTest.RunSettings.Tests.ps1: 28/28 passed post-fix, including the new regression test and the pre-existing 5-test Describe 'Invoke-MSTestWithCoverageMain' block. Invoke-MSTestWithCoverage.Threshold.Tests.ps1 (the #733-relocated home of the five Assert-CoberturaLineCoverageThreshold boundary tests, not Helpers.Tests.ps1 as the plan originally assumed): 5/5 passed, confirming the threshold logic needed no change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…le pass PoshQC format: no rewrites on either owned file. PSScriptAnalyzer: 0 diagnostics on both files (matches P0-T6 baseline). Full Pester suite (10 files, 93 tests): Failed=0. Coverage of Invoke-MSTestWithCoverage.ps1 unchanged at 90.09% (111 commands, 100 executed) vs the P0-T7 baseline — no regression. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Each AC checked off individually, citing its corresponding evidence artifact. AC 3 and AC 5 carry inline drift notes recording that the threshold logic and its boundary tests now live in Invoke-MSTestWithCoverage.Threshold.ps1 / .Threshold.Tests.ps1 post-#733, not the originally cited Helpers.ps1 files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
spec.md Status -> Implemented, both Test Strategy "Seeded from issue" checkboxes checked. AC status summary: 6/6 checked off. Issue #565 comment posted summarizing the fix, mirrored locally. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
git status --porcelain is empty at this point (recorded before this commit itself); this commit adds only the recording artifact and the final [P6-T4] plan check-off. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…coverage-threshold-before-setcontent-565
…565 Feature-review pass over the Set-Content/threshold-assertion reorder fix. All three artifacts PASS with zero blocking findings; 6/6 spec.md acceptance criteria independently verified. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds artifacts/pr_body_565.md and its sibling SHA-256 receipt via the pr-author skill, and refreshes the PR context bundle (which, until now, still described a stale merge-base after main advanced past this branch's reconciliation point). Issue #565 was independently confirmed OPEN via `gh issue view` before authoring the single `- Closes #565` directive; the context collector's "author-asserted autoclose issues" list included noise (#441, #563, #733, and a non-issue "#ISO-8601" token) that this body does not close. Co-Authored-By: Claude Fable 5.1 <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.
Suggested title
fix(vscode): persist the post-processed Cobertura document before the coverage-threshold assertion (#565)
Summary
scripts/vscode/Invoke-MSTestWithCoverage.ps1previously calledAssert-CoberturaLineCoverageThresholdbeforeSet-Contentpersisted the post-processed Cobertura XML, so a failing (sub-threshold) run threw before the judged document was ever written to disk, leaving the raw, un-post-processeddotnet-coverageoutput at the-CoverageOutputpath instead.Invoke-MSTestWithCoverageMain:Set-Contentnow runs immediately after$processedXmlContentis computed and beforeAssert-CoberturaLineCoverageThresholdis called. No logic, threshold value, or message text changed.tests/scripts/vscode/Invoke-MSTest.RunSettings.Tests.ps1provingSet-Contentis invoked exactly once before the threshold assertion can throw on a sub-threshold run.main) refactored this same file, splittingAssert-CoberturaLineCoverageThresholdout into a new file,scripts/vscode/Invoke-MSTestWithCoverage.Threshold.ps1. The branch was reconciled against the currentmain, the defect was re-confirmed still present at the drifted line numbers, and the fix was executed and verified against the reconciled tree.Invoke-MSTestWithCoverage.Helpers.ps1and the relocatedInvoke-MSTestWithCoverage.Threshold.ps1(empty diffs againstmainfor both files).spec.mdverified and checked off; zero blocking findings in policy-audit, code-review, and feature-audit.Why
Only the failure path was affected — a passing run always wrote the correct document. But the failure path is exactly when someone reads the artifact on disk to diagnose a coverage shortfall, and what they found was a document with different numbers than the one that produced the failure message (absolute paths, unmerged third-party packages, duplicate classes, and the double-counted line totals that issue #441 had already corrected). A failed gate also left behind an artifact that, if fed to any downstream consumer, silently reported the pre-#441 inflated denominator. Issue #563 (a separate, unrelated contradiction in the threshold value) is explicitly out of scope for this fix, which touches statement order only.
What Changed
Core logic:
scripts/vscode/Invoke-MSTestWithCoverage.ps1— swapped theSet-ContentandAssert-CoberturaLineCoverageThresholdcalls insideInvoke-MSTestWithCoverageMain(net +2/-2 lines).Tests:
tests/scripts/vscode/Invoke-MSTest.RunSettings.Tests.ps1— added one newItto the existingDescribe 'Invoke-MSTestWithCoverageMain'block (net +8 lines), inserted between the pre-existing'fails when the search root cannot be found'test and the sibling-issue-Bug: coverage-cobertura-mstest-powershell-tooling-defects #733-added'.claude worktree'exclusion test.Docs/evidence:
docs/features/active/2026-09-02-invoke-mstestwithcoverage-threshold-before-setcontent-565/— issue, spec, research, atomic plan, full Phase 0-6 evidence trail, and policy-audit/code-review/feature-audit artifacts.Architecture / How It Fits Together
Invoke-MSTestWithCoverageMaincollects coverage viadotnet-coverage, post-processes the raw Cobertura XML for Koverage compatibility (ConvertTo-KoverageCoberturaXml), and previously validated the resulting line-rate before writing it to disk. The fix only reorders when the write happens relative to the validation;Assert-CoberturaLineCoverageThresholdremains a pure read-and-throw function with no side effect that could observe or be observed bySet-Content, so the reorder is behaviorally safe under both the passing and failing case.Verification
Completed (from evidence trail):
Set-Contentinvoked 0 times before the throw); post-fix run showed 28/28 tests passed in the target file.scripts/vscode/Invoke-MSTestWithCoverage.ps1: 90.09% before and after (no regression).git diffagainstmainconfirmed empty for bothInvoke-MSTestWithCoverage.Helpers.ps1andInvoke-MSTestWithCoverage.Threshold.ps1(threshold value/message untouched).Recommended (CI):
scripts/vscode/**andtests/scripts/vscode/**.Backward Compatibility / Migration Notes
None. No function signature, parameter, output format, or configuration surface changed. Passing runs (coverage at or above 80%) are unaffected because both statements always executed in that case; only the failing-run artifact-on-disk behavior changes, and only for the better (it now matches the document that produced the failure).
Risks and Mitigations
Review Guide
Suggested order:
scripts/vscode/Invoke-MSTestWithCoverage.ps1— the actual fix (4-line diff).tests/scripts/vscode/Invoke-MSTest.RunSettings.Tests.ps1— the new regression test (8-line diff).docs/features/active/2026-09-02-invoke-mstestwithcoverage-threshold-before-setcontent-565/spec.md— acceptance criteria and their check-off state.Follow-ups
GitHub Auto-close