Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
edf3d34
docs(epic): add build-ci-coverage-gate-fidelity epic manifest
drmoisan Aug 10, 2026
634ab28
docs(394): prepare utilitiescs-test-cs2002-duplicate-compile-entry
drmoisan Aug 10, 2026
bdfedbb
docs(memory): record direct-csproj build facts and CR detection
drmoisan Aug 10, 2026
868b438
Merge prepared feature: utilitiescs-test-cs2002-duplicate-compile-ent…
drmoisan Aug 10, 2026
78abd67
docs(epic): back-fill resolved feature_folder for #394
drmoisan Aug 10, 2026
616bd3c
docs(cobertura-coverage-arithmetic-441): preserve in-progress prepara…
drmoisan Aug 10, 2026
9fc39ae
docs(excludefromcodecoverage-nested-lambdas-457): preserve in-progres…
drmoisan Aug 10, 2026
4968f2c
docs(csharp-toolchain-gate-fidelity-512): preserve in-progress prepar…
drmoisan Aug 10, 2026
594386e
docs(coverage-threshold-policy-reconciliation-494): preserve in-progr…
drmoisan Aug 10, 2026
c5c8d1d
Merge remote-tracking branch 'origin/epic/build-ci-coverage-gate-fide…
drmoisan Aug 10, 2026
f26bbca
Merge remote-tracking branch 'origin/epic/build-ci-coverage-gate-fide…
drmoisan Aug 10, 2026
070955f
Merge remote-tracking branch 'origin/epic/build-ci-coverage-gate-fide…
drmoisan Aug 10, 2026
80fc179
Merge remote-tracking branch 'origin/epic/build-ci-coverage-gate-fide…
drmoisan Aug 10, 2026
a474f39
docs(cobertura-coverage-arithmetic-441): preserve round-2 plan revisions
drmoisan Aug 11, 2026
35254ec
docs(excludefromcodecoverage-nested-lambdas-457): preserve round-2 pl…
drmoisan Aug 11, 2026
e8287a6
docs(csharp-toolchain-gate-fidelity-512): preserve round-2 plan revis…
drmoisan Aug 11, 2026
cc64756
docs(coverage-threshold-policy-reconciliation-494): preserve round-2 …
drmoisan Aug 11, 2026
93d24b5
docs(coverage-threshold-policy-reconciliation-494): clear atomic-exec…
drmoisan Aug 11, 2026
c325fa9
docs(agent-memory): record halt-removal branch-propagation lesson fro…
drmoisan Aug 11, 2026
155cf30
Merge prepared feature: coverage-threshold-policy-reconciliation-494
drmoisan Aug 11, 2026
e385b1d
docs(epic): back-fill resolved feature_folder for #494
drmoisan Aug 11, 2026
fcf07ae
docs(cobertura-coverage-arithmetic-441): clear atomic-executor preflight
drmoisan Aug 11, 2026
fb96d67
chore(agent-memory): record Pester StrictMode XML attribute hazard
drmoisan Aug 11, 2026
de48d10
chore(agent-memory): record delegation_receipt required keys
drmoisan Aug 11, 2026
27be6ec
Merge prepared feature: cobertura-coverage-arithmetic-441
drmoisan Aug 11, 2026
cffa4eb
docs(epic): back-fill resolved feature_folder for #441
drmoisan Aug 11, 2026
a1c1279
docs(csharp-toolchain-gate-fidelity-512): clear atomic-executor prefl…
drmoisan Aug 11, 2026
78b6955
chore(agent-memory): record planner learnings from the #512 preflight
drmoisan Aug 11, 2026
0a1e35e
chore(agent-memory): record the model-routing hook checkpoint-path co…
drmoisan Aug 11, 2026
5447e80
Merge prepared feature: csharp-toolchain-gate-fidelity-512
drmoisan Aug 11, 2026
710c9cc
docs(epic): back-fill resolved feature_folder for #512
drmoisan Aug 11, 2026
5d1848a
docs(excludefromcodecoverage-nested-lambdas-457): clear atomic-execut…
drmoisan Aug 11, 2026
d1b5fe6
chore(agent-memory): record #457 preparation learnings
drmoisan Aug 11, 2026
abe7d02
Merge prepared feature: excludefromcodecoverage-nested-lambdas-457
drmoisan Aug 11, 2026
1fe8f1d
docs(epic): back-fill #457 feature_folder and add epic kickoff artifact
drmoisan Aug 11, 2026
7ca13d7
docs(epic): correct kickoff artifact to satisfy the epic-kickoff vali…
drmoisan Aug 11, 2026
a5e336e
docs(epic): seed epic-status.md projection for build-ci-coverage-gate…
drmoisan Aug 11, 2026
58f4d2a
docs(epic): record wave 0 launch in epic-status.md
drmoisan Aug 11, 2026
babda56
fix(UtilitiesCS.Test): remove duplicate PercentageFormatterTests comp…
drmoisan Aug 11, 2026
ed2ae5f
chore(394): remediation cycle 1 - drop unplanned evidence-tree PowerS…
drmoisan Aug 11, 2026
12037cc
chore(394): complete remediation cycle 1 verification gates
drmoisan Aug 11, 2026
28771e6
docs(394): record remediation cycle 1 exit reaudit (0 blocking findings)
drmoisan Aug 11, 2026
c1fe356
Merge pull request #533 from drmoisan/bug/utilitiescs-test-cs2002-dup…
drmoisan Aug 11, 2026
43671f3
chore(memory): record #394 lessons and compact the orchestrator index
drmoisan Aug 11, 2026
5604121
Merge pull request #534 from drmoisan/chore/orchestrator-memory-394
drmoisan Aug 11, 2026
143984a
docs(epic): record 394 merged and worktree removed; note child-PR CI gap
drmoisan Aug 11, 2026
9773d6f
fix(toolchain): make the documented C# gates execute truthfully
drmoisan Aug 11, 2026
a7ac497
fix(coverage): dedupe Cobertura line and branch arithmetic (#441, #478)
drmoisan Aug 11, 2026
039c931
docs(441): file the four follow-up issues and close out AC-20
drmoisan Aug 11, 2026
e94dfcf
docs(441): commit feature review artifacts and disposition findings
drmoisan Aug 11, 2026
fb257cd
Merge pull request #538 from drmoisan/bug/cobertura-coverage-arithmet…
drmoisan Aug 11, 2026
8a6f987
chore(memory): record two orchestrator lessons from the #441 child run
drmoisan Aug 11, 2026
1c22139
Merge pull request #539 from drmoisan/chore/orchestrator-memory-441
drmoisan Aug 11, 2026
fecef9c
docs(review): add policy, code, and feature audits for #512
drmoisan Aug 11, 2026
e2c2926
docs(epic): record 441 merged, wave 1 opened for 457
drmoisan Aug 11, 2026
22eaee8
Merge pull request #540 from drmoisan/bug/csharp-toolchain-gate-fidel…
drmoisan Aug 11, 2026
b4af682
chore(memory): record #512 toolchain-gate outcomes for the orchestrator
drmoisan Aug 11, 2026
bc1fb51
Merge pull request #541 from drmoisan/chore/orchestrator-memory-512
drmoisan Aug 11, 2026
809f977
docs(epic): wave 0 complete; record main-inherited flaky test blockin…
drmoisan Aug 11, 2026
0105e71
fix(coverage): exclude nested lambdas of exempt members from the deno…
drmoisan Aug 11, 2026
63a3ff1
docs(457): record feature review artifacts and promote two review fin…
drmoisan Aug 11, 2026
ee082ba
Merge pull request #542 from drmoisan/bug/excludefromcodecoverage-nes…
drmoisan Aug 11, 2026
ce94f22
chore(memory): record two orchestrator lessons from the #457 child run
drmoisan Aug 11, 2026
8d0d1fe
Merge pull request #543 from drmoisan/bug/excludefromcodecoverage-nes…
drmoisan Aug 11, 2026
c7d398c
docs(epic): 457 merged, wave 1 complete, wave 2 opened for 494
drmoisan Aug 11, 2026
d863a5c
docs(epic): record green integrated-tree CI and disposition the inher…
drmoisan Aug 11, 2026
1d0b2a4
(docs(coverage-policy)): refine #494 plan gates and baseline evidence
drmoisan Aug 11, 2026
382a376
docs(coverage-policy): record validation evidence and review blockers
drmoisan Aug 11, 2026
374714e
docs(coverage-policy): record post-review remediation halt
drmoisan Aug 11, 2026
b314927
fix(coverage): enforce 80% Cobertura line coverage threshold
drmoisan Aug 13, 2026
7120a91
docs(coverage): reconcile remediation scope for agent-memory records
drmoisan Aug 13, 2026
b7b6bc0
docs(coverage): record final issue #494 audit
drmoisan Aug 13, 2026
fb29523
docs(coverage-policy): define remediation scope and acceptance source
drmoisan Aug 13, 2026
4845174
docs(coverage-policy): add final feature review audits
drmoisan Aug 13, 2026
0264bc2
docs(coverage-policy): align audit verdict with analyzer baseline
drmoisan Aug 13, 2026
b8b4b16
docs(coverage-policy): clarify analyzer baseline disposition
drmoisan Aug 13, 2026
85ff0c3
Merge pull request #551 from drmoisan:bug/coverage-threshold-policy-r…
drmoisan Aug 15, 2026
fb8eff9
Merge branch 'main' into epic/build-ci-coverage-gate-fidelity-integra…
drmoisan Aug 15, 2026
6c0a0e8
docs(epic): refresh epic-status projection from git and gh
drmoisan Aug 15, 2026
22b5de0
chore(457): promote the three AC15 residual potential entries to issues
drmoisan Aug 15, 2026
3e61c67
docs(epic): record the composed integration-diff review and epic audit
drmoisan Aug 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 9 additions & 1 deletion .claude/agent-memory/atomic-executor/MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
## Plan validation & gates
- [Verify line citations with numbered output](feedback_verify_line_citations_with_numbered_output.md) — never hand-count from a `sed` window; a wrong #438 advisory got applied and corrupted 3 correct citations in plan + spec
- [Self-derived gate thresholds are blind](project_preflight_selfderived_gate_thresholds_are_blind.md) — a "count >= floor" gate whose floor comes from the runs it validates is deflation-blind + scope-incommensurable; use git-enumeration + `/ListTests` existence proofs
- [Multi-pattern gates detach shared qualifiers](project_multipattern_gate_shared_qualifier_detachment.md) — rewriting one clause re-scopes the trailing allowlist to the last pattern only; restate the carve-out per pattern + require per-pattern count identity
- [Merge-base diff gates need a commit cadence](project_preflight_mergebase_diff_gates_need_commit_cadence.md) — `<MERGE_BASE>..HEAD` gates are vacuous while HEAD == merge-base; plan an explicit commit task
- [Inserted plan tasks force renumbering](project_plan_task_ids_digit_only_forces_renumbering.md) — suffixed IDs (`P3-T5a`) fail validation; say "insert + renumber downstream", then verify defs-vs-mentions mechanically
- [Plan rationale clauses are evidence](project_418_plan_rationale_clauses_are_evidence.md) — #418 needed 3 preflight passes; all blockers were unmeasured world-state claims in prose, never in the fix
- [AC check-off "inline pointer" + artifacts/ tool-output paths](project_preflight_ac_checkoff_and_tooloutput_paths.md) — "record the evidence pointer inline" in an AC check-off task violates acceptance-criteria-tracking; artifacts/pester|csharp coverage XML is a producer path, not an evidence path
- [Exact-count gate vs remediation loop](project_exact_count_gate_vs_remediation_loop.md) — a pinned `TotalCount = 19` collides with an "add tests and restart" remediation path; use `B + N` and re-scan count gates whenever a restart clause is added
- [Tracked agent-memory breaks unscoped git gates](project_agent_memory_tracked_breaks_unscoped_git_gates.md) — `.claude/agent-memory/**` is tracked + dirty at branch head; every git diff/status/grep gate needs an explicit pathspec or it is unsatisfiable / false-positive
- [#418 500-line gate vs mandated plan content](project_418_500line_gate_vs_plan_content.md) — P1-T19 unsatisfiable (193 new lines into 146 headroom); per-block logging clauses block centralizing; delta = extract helpers to a new file
- [#207 Hook() redesign breaks AppEventsTests](project_207_hook_redesign_breaks_appeventstests.md) — needs a plan revision, not a test weakening
Expand All @@ -31,13 +34,18 @@
- [Evidence <TS> collision clobbers committed artifacts](project_evidence_timestamp_collision_clobbers_artifacts.md) — same-day remediation can silently overwrite implementation-cycle evidence; a ` M` under `evidence/` means clobber
- [csharpier pipe-files is a non-enforcing gate](project_csharpier_pipefiles_nonenforcing_gate.md) — use `csharpier check`/`format`; tests balloon past 500 lines under genuine format (size new files AFTER format)
- [PowerShell new files need UTF-8 BOM](powershell-bom-required.md) — PSScriptAnalyzer enforces PSUseBOMForUnicodeEncodedFile; prepend BOM after Write or restart the format loop
- [poshqc Pester MCP exits -1](project_poshqc_pester_mcp_exit_minus1.md) — run_poshqc_test exits -1 (no detail) here; run it for the record, pair with direct Invoke-Pester (pwsh7) for the numeric proof
- [poshqc test MCP carries no verdict and no numbers](project_poshqc_pester_mcp_exit_minus1.md) — run_poshqc_test returns only {ok,tool,workspace_root,summary}: no exit code, counts or coverage, so any EXIT_CODE/N-failures/expect-fail gate on it is vacuous; scan_folders accepts FILE paths; Pester 5 has no branch metric; pair with direct Invoke-Pester
- [poshqc analyze exits 1 on a Warning](project_poshqc_analyze_exit1_on_warning.md) — "EXIT_CODE 0 with zero error-severity" is self-contradictory; Helpers.ps1 carries a pre-existing PSUseSingularNouns; `Remove-*` needs SupportsShouldProcess
- [BOM breaks grep ^ anchor](project_bom_grep_anchor_false_negative.md) — bash grep `^#nullable` misses BOM-prefixed files; use the Grep tool for opt-in classification, never bash grep
- [StrictMode Latest + missing XML attribute throws](project_pester_strictmode_xml_attribute_property_access.md) — a fixture omitting `branch` (or `complexity` on a merge-path `<class>`) throws PropertyNotFoundStrict instead of the assertion diff; enumerate ALL bare `$node.attr` reads on the traversed path, not one attribute at a time
- [Pester 5 result shape: no container .Tests, no -CI + -CodeCoverage](project_pester5_result_shape_container_tests_and_ci_codecoverage.md) — `$_.Tests.Count` silently renders 0 per file (use `TotalCount`); `-CI` and `-CodeCoverage` are different parameter sets and cannot be combined
- [pwsh -Command needs single-quoted outer](project_pwsh_command_quoting_from_bash.md) — a double-quoted outer wrapper lets bash eat `$` → empty counts + inverted exit gates or a hard ParserError; `''` inside single quotes is not an escape

- [Compile-time red needs body-level refs](project_compile_red_needs_body_level_references.md) — a missing type in a method SIGNATURE suppresses body binding, so an `[expect-fail]` task requiring N named CS0246s reports only 1; construct the types inline in test bodies

## Test execution & isolation
- [Tests must mock GUI; no visible window](feedback_tests_must_mock_gui_no_visible_window.md) — use headless seams (mocked viewers, injected show/focus delegates), never Form.Show/Application.Run
- [#511 is a test-host crash, not N failing tests](project_511_is_a_testhost_crash_not_n_failing_tests.md) — load-driven abort with `Total tests: Unknown` (no readable verdict); `/InIsolation` loop gave 0 failed; never gate on a pinned failing-name count
- [WinFormsPumpHost tests are load-flaky](project_winformspumphost_tests_load_flaky.md) — QfcItemController_InitializationTests fail with "window handle has been created"/60s timeouts when the box is CPU-saturated; re-run when load drops, don't treat as a red baseline
- [vstest /InIsolation + FilePathHelper serialization](project_vstest_isolation_and_filepathhelper_serialization.md) — Moq assemblies need /InIsolation (else STTE Setup FileNotFound); FilePathHelper.FilePath is "" default but null after JSON deserialize
- [Invoke-MSTest.ps1 dies on a single test assembly](project_418_invoke_mstest_single_assembly_bug.md) — StrictMode + `.Count` on a scalar String throws before vstest runs; call vstest.console.exe directly with the script's arg list
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: 511-is-a-testhost-crash-not-n-failing-tests
description: Issue #511 is a load-driven test-host crash with "Total tests: Unknown", not a fixed set of failing tests; plans that pin a failing-name count cannot be evaluated
metadata:
type: project
---

Issue #511 on the 9-assembly single-process coverage run is an **intermittent test-host crash**, not a
deterministic set of failing tests. The authoritative in-repo record is
`docs/features/active/2026-08-10-cobertura-coverage-arithmetic-441/research/2026-08-10T14-20-cobertura-arithmetic-research.md:738-752`
and `.../441/spec.md:569-579`:

- symptom: `The active test run was aborted. Reason: Test host process crashed` / `Test Run Aborted. Total tests: Unknown`
- character: environmental, load-driven, concentrated in the `QuickFiler.Test` `WinFormsPumpHost`
message-pump family — explicitly "**not a test failure**"
- `Total tests: Unknown` means **no verdict can be read from the run**
- documented recovery: loop the 9 assemblies through `vstest.console.exe <dll> /InIsolation`, which on
#505 produced **6435 passed, 1 skipped, 0 failed**; that loop yields nine separate `.coverage` files
that need a `dotnet-coverage merge` before a repository-wide Cobertura figure exists

**Why:** a plan asserted "#511 leaves two `*ThroughThePumpHost*` MSTest cases failing", made a
per-failing-name #511 determination a gate, and declared "any third failing name" a halt. There are five
`*ThroughThePumpHost*` test methods, the two names are enumerated nowhere, and the real failure mode
produces zero named failures plus an unreadable total.
**How to apply:** never gate on a pinned count of #511 failures. Gate on the failing-name **pattern**,
require an artifact-existence check before reading the Cobertura file, and give the abort case an
explicit branch (re-run, or the `/InIsolation` + merge recovery). Related:
[[project_winformspumphost_tests_load_flaky]], [[project_timedout_mstest_leaves_detached_runner]].
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: exact-count-gate-vs-remediation-loop
description: A plan that pins an exact test TotalCount/PassedCount and also has a remediation path that adds tests is self-contradictory; check every add-tests-and-restart clause against every downstream count gate.
metadata:
type: project
---

When a plan hard-pins a test gate to an exact figure (`PassedCount` = `TotalCount` = **19**) and
elsewhere carries a remediation path that says "add further unit tests, then restart the QA loop
from P#-T#", the two clauses contradict each other the moment the remediation fires: the restarted
gate can only be satisfied by recording a false number.

**Why:** Exact counts are added to close the zero-discovery hole (`FailedCount = 0` is also true of
a run that discovered nothing — see [[project-poshqc-pester-mcp-exit-minus1]]). Remediation paths
are added to close a coverage-shortfall hole. Both fixes are correct in isolation; the collision is
only visible when you read them together. Found on the #441 Cobertura plan at preflight iteration 3,
where the fix for SF-6 (coverage remediation) collided with the fix for SF-3 (TotalCount pinning)
introduced in the same round.

**How to apply:** The safe formulation is `PassedCount` = `TotalCount` = **B + N**, where B is the
baseline figure and N is the number of tests added under the named remediation path (N = 0 on the
first pass), with the in-force N recorded in the artifact, plus "a `TotalCount` below B fails this
gate". That keeps the zero-discovery guard intact without forbidding the remediation. Whenever a
preflight round adds a remediation-restart clause, re-scan every downstream numeric acceptance the
restart replays — the executor cannot reconcile a numeric mismatch at runtime without replanning.

Related: [[project-preflight-selfderived-gate-thresholds-are-blind]],
[[project-418-plan-rationale-clauses-are-evidence]].
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
name: multipattern-gate-shared-qualifier-detachment
description: Rewriting one clause of a multi-pattern grep gate can silently detach a shared allowlist qualifier from the other patterns; re-read the whole acceptance sentence after every edit
metadata:
type: project
---

When a plan's acceptance criterion enumerates several grep patterns governed by one trailing
qualifier ("... and ... **outside the SD1 allowlist**"), any restructuring of that sentence risks
re-scoping the qualifier to only the last pattern, making the earlier patterns unconditional and the
gate unsatisfiable. This happened on #512 round 3: a rewrite of pattern (c) left patterns (a) and (b)
demanding zero hits repo-wide while 10 and 9 hits legitimately live in the protected SD1 mirrors.

**Why:** multi-pattern gates accumulate clauses across preflight rounds. Each round edits one clause
in isolation, so the shared qualifier's scope is never re-read as a whole. The failure mode is
invisible to a validator (the plan is well-formed) and only surfaces as an impossible gate at run
time.

**How to apply:** for any acceptance criterion naming two or more patterns, (1) confirm the
allowlist/exclusion qualifier is restated per pattern rather than shared, (2) enumerate the actual
world state with `git grep` per pattern and per exclusion set before declaring satisfiability, and
(3) check the inverse defect too — that the carve-out does not excuse an in-scope site. Pair the
carve-out with a per-pattern count-identity requirement against the Phase 0 before-state so the
allowlist cannot absorb a newly introduced or silently corrected site. Related:
[[verify-line-citations-with-numbered-output]], [[preflight-selfderived-gate-thresholds-are-blind]].
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: pester5-result-shape-container-tests-and-ci-codecoverage
description: Pester 5.6.1 container objects have no Tests property (so $_.Tests.Count is silently 0) and Invoke-Pester -CI cannot be combined with -CodeCoverage
metadata:
type: project
---

Two verified facts about direct `Invoke-Pester` (Pester 5.6.1, the version installed here) that turn
plausible-looking gates into gates that can never pass:

1. A container result object exposes
`Name,Type,Item,Data,Blocks,Result,Duration,FailedCount,PassedCount,SkippedCount,InconclusiveCount,NotRunCount,TotalCount,ErrorRecord,...`
— there is **no** `Tests` property. `"$($_.Tests.Count)"` therefore renders `0` for every file even
when tests ran and passed (no StrictMode error, because the run happens in a plain `-Command` scope).
Use `$_.TotalCount` (and `$_.FailedCount`) for the per-file inventory, or group the flattened
`$r.Tests` by `$_.ScriptBlock.File`.
2. `-CodeCoverage` lives only in the **Legacy** parameter set; `-CI` lives in **Simple**. Combining them
fails with "Parameter set cannot be resolved using the specified named parameters." For a scoped
per-file coverage figure, use a configuration object (`$c.CodeCoverage.Path = @('<one file>')`) and
read `$r.CodeCoverage.CoveragePercent`.

Also confirmed: `$r.CodeCoverage.CoveragePercent` is real; `$_.Item.FullName` is real; Pester discovers
test files under a dot-prefixed parent such as `tests/.claude/hooks/` without `-Force`; and the second
figure in the "Covered X% / Y%" console line is `CoveragePercentTarget`, not a branch metric.

**Why:** an atomic plan required an "executed-file inventory with a non-zero test count per named file"
and a `-CI -CodeCoverage` fallback; both were unsatisfiable as written across three tasks.
**How to apply:** before accepting any plan clause that reads a number off a Pester result object, run
the expression once against a throwaway fixture. See [[project_poshqc_pester_mcp_exit_minus1]] for the
MCP-route counterpart (no counts, no exit code at all).
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
name: pester-strictmode-xml-attribute-property-access
description: Under Set-StrictMode -Version Latest, $node.attr on an XmlElement lacking that attribute THROWS PropertyNotFoundStrict - a Cobertura fixture that omits branch="False" fails with the wrong error, breaking pinned fail-before values
metadata:
type: project
---

`tests/scripts/vscode/Invoke-MSTestWithCoverage.Helpers.Tests.ps1` line 1 is
`Set-StrictMode -Version Latest`, and that mode propagates into production functions
dot-sourced in `BeforeAll`. Under it, PowerShell property access on a *missing* XML
attribute throws `The property '<name>' cannot be found on this object`, it does not
return `$null`.

Measured 2026-08-10 with a Pester 5.6.1 probe against the real
`scripts/vscode/Invoke-MSTestWithCoverage.Helpers.ps1`:

- Cobertura fixture whose `<line>` elements omit `branch` -> the `It` fails with
`The property 'branch' cannot be found on this object` (thrown at
`Helpers.ps1:128`, `$line.branch -eq 'True'`).
- Identical fixture with `branch="False"` added -> the `It` fails with the intended
assertion text (`Expected: '3' But was: '6'`).

**Why:** every pre-existing fixture in that file carries `branch="False"` on every
`<line>`, so the hazard is invisible until someone authors a new fixture from a prose
spec that only lists `number` and `hits`. A plan that pins fail-before evidence to
exact numeric error text (e.g. "F1 reports 6/4") becomes unsatisfiable, because the
run produces a StrictMode error instead of the assertion diff. `FailedCount` is
unchanged, so a count-only gate does not catch it.

**The hazard is not specific to `branch`.** Measured 2026-08-10 (round 2): a two-class
same-`filename` merge fixture whose `<class>` elements omit `complexity` throws
`The property 'complexity' cannot be found on this object` at `Helpers.ps1:279`
(`$group | ForEach-Object { if ($_.complexity) ... }` inside
`Merge-CoberturaClassesByFilename`). Fixing only `branch` is therefore necessary but
not sufficient: any merge-path fixture also needs `complexity`. Single-class fixtures
never reach that line and are unaffected.

**How to apply:** when authoring or validating Cobertura/XML fixtures for this suite,
do not patch attributes one at a time. Walk every bare `$node.<attr>` read on the code
path the fixture will traverse and require each of those attributes in the fixture. For
this file that is: `branch` and `hits` on every `<line>` on BOTH the
`<methods>/<method>/<lines>` axis and the class-level `<lines>` axis; `complexity` and
`name` on every `<class>` in a merge-path fixture; `name` on every `<package>`. In
production helpers read the flag as `$node.GetAttribute('branch') -eq 'True'` (the
existing union builder at `Helpers.ps1:236` already does); `HasAttribute`/`GetAttribute`
are StrictMode-safe, bare property access is not. `$node.number` is safe only because
every fixture and every real generator emits it.

Related: [[project_poshqc_pester_mcp_exit_minus1]],
[[project_koverage_cobertura_postprocessing_shape]].
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: poshqc-analyze-exit1-on-warning
description: run_poshqc_analyze exits 1 on Warning-severity findings, so "EXIT_CODE 0 with zero error-severity diagnostics" is self-contradictory; Remove-* verbs need SupportsShouldProcess
metadata:
type: project
---

`mcp__drm-copilot__run_poshqc_analyze` exits **1 for any PSScriptAnalyzer finding, including Warning severity**. A plan acceptance clause phrased "`EXIT_CODE: 0` with zero error-severity diagnostics" is therefore self-contradictory whenever a Warning exists, and is a preflight defect.

Two concrete traps in `scripts/vscode/`:

1. **Pre-existing Warning in the module under change.** `scripts/vscode/Invoke-MSTestWithCoverage.Helpers.ps1` carries `PSUseSingularNouns` on `Get-CoberturaLineConditionCoverageParts`. Any plan that gates on `EXIT_CODE: 0` over that file is unsatisfiable unless the function is renamed — which usually blows a "exactly N edits to this file" scope lock. The correct gate is *diagnostic-set equality against the Phase 0 baseline*, not exit 0.

2. **`Remove-` verb needs `SupportsShouldProcess`.** A function named `Remove-*` declared with a bare `[CmdletBinding()]` raises `PSUseShouldProcessForStateChangingFunctions` (Warning). Verified fix that yields zero diagnostics: `[CmdletBinding(SupportsShouldProcess = $true)]` plus a single `if ($PSCmdlet.ShouldProcess('<target>', '<action>')) { ... }` guard around the mutation. The state-changing verb list is New/Set/Remove/Start/Stop/Restart/Resume/Suspend; `Merge-`, `Get-`, `Test-`, `ConvertTo-` do not trigger it.

**Why:** both were found at preflight on the #457 closure-filter plan, where P3-T3 demanded `EXIT_CODE: 0` and P2-T5 specified a bare `[CmdletBinding()]` on `Remove-CoberturaExemptClosureCoverage`.

**How to apply:** when validating or executing a PowerShell plan, run `Invoke-ScriptAnalyzer -Path <file>` directly to enumerate the baseline diagnostic set before accepting any exit-code gate, and check every planned `Remove-`/`Set-`/`New-` function name against the ShouldProcess rule. See [[poshqc-pester-mcp-no-numeric-detail]].
Loading
Loading