diff --git a/.claude/agent-memory/_shared_no_absolute_host_paths.md b/.claude/agent-memory/_shared_no_absolute_host_paths.md new file mode 100644 index 000000000..0f59298b1 --- /dev/null +++ b/.claude/agent-memory/_shared_no_absolute_host_paths.md @@ -0,0 +1,46 @@ +# Never embed absolute host paths in any file + +**Applies to:** every agent, every artifact — evidence records, plans, specs, research, +checkpoints, agent memory, commit messages, PR bodies. + +## Rule + +No file committed to this repository may contain an absolute host path or a host identifier. +Absolute paths leak the operator's account name, machine name, and directory layout, and they +are not reproducible on any other machine. + +Prohibited: `C:\Users\\...`, `C:/Users//...`, `/c/Users//...`, a bare +account name (for example in an `ls -l` owner column), and a bare machine name. + +## Required placeholders + +| Real value | Write this instead | +| --- | --- | +| repository root | `` | +| user profile directory (for caches outside the repo, e.g. NuGet) | `` | +| account name | `` | +| machine / host name | `` | + +Compose longer paths from the placeholder: `\.claude\worktrees\agent-\.dotnet-sdk`. +Prefer a repo-relative path (`packages/Foo/bar.dll`) whenever one is expressible — a placeholder is +the fallback for paths that genuinely sit outside the repository. + +## The vstest TRX trap + +`vstest.console.exe` names its TRX and `.coverage` output `__.trx` by +default, so raw test output embeds both identifiers **in the filename**. Any evidence artifact that +cites a TRX by name inherits them. + +Two mitigations, both required: +1. Pass an explicit `/ResultsDirectory:` plus a `--logger:trx;LogFileName=` that you control, or + rename the produced files before citing them. +2. When citing a TRX in a markdown evidence record, cite the sanitized filename. + +## Recurrence record + +Issue #511 (`winformspumphost-suite-determinism-511`) accumulated 140 untracked evidence paths +carrying a `__` filename prefix, 10 committed markdown files citing those names, and +91 absolute-path occurrences across 27 committed files. All were sanitized on 2026-08-23 at +maintainer instruction. Roughly 146 files in other and archived feature folders still carry the +prefix, and about 157 still carry the bare host name; that remainder is tracked as its own issue +because sanitizing it inside a bug-fix child would break the child's scope lock. diff --git a/.claude/agent-memory/atomic-executor/MEMORY.md b/.claude/agent-memory/atomic-executor/MEMORY.md index 65179214d..96e590de7 100644 --- a/.claude/agent-memory/atomic-executor/MEMORY.md +++ b/.claude/agent-memory/atomic-executor/MEMORY.md @@ -20,6 +20,7 @@ ## Build / toolchain environment - [pwsh/git/gh CLI gotchas](project_pwsh_git_gh_cli_gotchas.md) — jq NOT installed (only `gh --jq`); pwsh won't concatenate `$(git merge-base ...)..HEAD`; bare `packages.config` - [Project Build/Test Env](project_build_test_env.md) — git-bash quirks (MSBuild switches, MSYS_NO_PATHCONV), csharpier v1 syntax, legacy csproj Compile includes, IVT for Moq +- [Start-Process -ArgumentList array strips quoting](project_startprocess_arglist_array_strips_quoting.md) — a detached msbuild launch loses `"/p:Platform=Any CPU"` and dies MSB1008 having compiled nothing; pass ONE pre-quoted string - [VS18 build/test toolchain paths](project_vs18_build_toolchain_paths.md) — use VS **18** full-framework msbuild.exe (not .dotnet-sdk, dies on binary resx MSB3822); nuget.exe restore - [Repo-local SDK install + nullable Rebuild](project_repo_sdk_and_nullable_rebuild.md) — .dotnet-sdk install needs pwsh7; csharpier check/format subcommands; nullable debt scope NOT stable across sessions — - [vstest TestCaseFilter OR-vs-pipe + fresh-worktree bootstrap](project_vstest_testcasefilter_or_operator_and_env_setup.md) — vstest rejects `OR`, needs `|`; fresh worktree needs restore + global `dotnet-coverage` @@ -46,6 +47,7 @@ - [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 ## Test execution & isolation +- [Long runs need a detached process](project_long_runs_need_detached_process.md) — Bash `run_in_background` runners get killed after ~1h, taking `Start-Job` load generators with them; use `Start-Process -PassThru` + foreground `sleep 570` to advance real time - [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 - [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 @@ -87,6 +89,7 @@ - [Outlook `Action`/`Exception` ambiguity](project_outlook_action_ambiguity.md) — bare `Action` AND bare `Exception` are CS0104-ambiguous in Outlook-interop files; use ## Component-specific gotchas +- [WebView2 EndInit already creates child handles](project_webview2_endinit_creates_handles.md) — `new ItemViewer()` alone leaves BOTH WebView2 children handle-created, so a `IsHandleCreated == false` assertion is unsatisfiable; also 3 pre-existing UtilitiesCS.Test flakes (shared Console.Out) that break any all-assembly `failed == 0` gate - [#349 breadcrumb WebView2 gotchas](project_349_breadcrumb_webview2_gotchas.md) — retyped Designer field breaks reflection-injected tests; aggregate async d__ classes for >=90% - QuickFiler #227 cycle notes: [cycle-4 ToggleFocus](project_qfc227_cycle4_toggle_focus_genuine_test_gotchas.md), [cycle-3 Theme/FolderPredictor seam](project_theme_folderpredictor_seam_retrofit_gotchas.md) - [ObjectListView TreeListView headless selection](project_objectlistview_treelistview_headless_selection.md) — selection needs a native handle; cache the node via SelectionChanged @@ -97,4 +100,7 @@ - [IApplicationGlobals member forces implementers](project_iapplicationglobals_member_forces_implementers.md) — adding a member breaks 7 hand-written test-double stubs beyond scope lock; Moq mocks auto-implement - [TimeProvider seam gotchas](project_timeprovider_seam_gotchas.md) — Moq can't mock non-virtual GetLocalNow (use FakeTimeProvider); an optional TimeProvider param forces a Bcl.TimeProvider - [ScoDictionaryNew needs TryAdd not Add](project_scodictionarynew_tryadd_not_add.md) — retargeting Sco* tests: `.Add(k,v)` won't compile (CS1061); the base exposes `.TryAdd`; swap in the same edit -- [FluentAssertions Equal(params) has no because](project_fluentassertions_equal_params_no_because.md) — a trailing reason on `.Equal(...)` becomes an extra expected element; use `.Equal(new[]{...})` or move the reason to +- [FluentAssertions Equal(params) has no because](project_fluentassertions_equal_params_no_because.md) — a trailing reason on `.Equal(...)` becomes an extra expected element; use `.Equal(new[]{...})` or move the reason to `.HaveCount(n, reason)` + +## Artifact hygiene +- [Never embed absolute host paths](../_shared_no_absolute_host_paths.md) — no `C:\Users\\...`, bare account, or machine name in ANY artifact; use `` / `` / `` / ``. vstest names TRX `__.trx` by default, so control `/ResultsDirectory:` + `LogFileName=` or rename before citing. diff --git a/.claude/agent-memory/atomic-executor/project_build_test_env.md b/.claude/agent-memory/atomic-executor/project_build_test_env.md index a55a375d2..fe2355504 100644 --- a/.claude/agent-memory/atomic-executor/project_build_test_env.md +++ b/.claude/agent-memory/atomic-executor/project_build_test_env.md @@ -21,7 +21,7 @@ TaskMaster is a .NET Framework 4.8 C#/VSTO solution. Running the repo toolchain - QuickFiler.Test compiles as C# 7.3: `using var` and other C# 8+ features fail (CS8370). Use classic `using (...) {}` blocks in that project. TaskVisualization.Test is ALSO C# 7.3 — `is not null` / `is not` patterns fail there with CS8370 ("Feature 'not pattern' is not available in C# 7.3"); use `!= null`. Production projects (e.g. TaskVisualization.csproj) allow the newer patterns, so mirroring a production `is not null` into a `.Test` file breaks the analyzer build. This surfaces at the analyzer/type-check msbuild step, not at edit time. - COROLLARY (nullable gate order dependency): QuickFiler.Test.csproj sets NO `` (defaults to C# 7.3 for v4.8.1). The mandated nullable command `-p:Nullable=enable -p:TreatWarningsAsErrors=true` is solution-wide, so if QuickFiler.Test actually recompiles under it, it emits `CS8630: Invalid 'nullable' value 'Enable' for C# 7.3` and the build exits 1. This surfaces ONLY when you run the nullable build IN ISOLATION right after editing QuickFiler.Test sources. The fix is simply the mandated toolchain ORDER: run the analyzer build (`-p:EnableNETAnalyzers=true -p:EnforceCodeStyleInBuild=true`, which does NOT set Nullable) FIRST to compile QuickFiler.Test under its real 7.3 settings, then the nullable build finds it up-to-date and skips it, so CS8630 never arises. Do not "fix" CS8630 by editing the csproj — it is an isolation artifact, not a defect. - `dotnet-coverage` global tool (v18.5.2) converts `.coverage` -> Cobertura cleanly: `MSYS_NO_PATHCONV=1 dotnet-coverage merge -o out.cobertura.xml -f cobertura .coverage`. Root element is `` and `` blocks carry ``; `[ExcludeFromCodeCoverage]` classes (e.g. `QfcDatamodel`) are absent entirely. This is a working alternative to Microsoft.CodeCoverage.Console.exe. -- A FRESH worktree has no `packages/` dir. The first msbuild fails with CS0246 (`Fizzler`/`Svg`/`log4net` not found) in vendored SVGControl. Run `nuget restore TaskMaster.sln` first (packages.config-based, ~168 packages). nuget.exe is at `C:/Users/DanMoisan/AppData/Local/Microsoft/WinGet/Packages/Microsoft.NuGet_Microsoft.Winget.Source_8wekyb3d8bbwe/nuget.exe`. +- A FRESH worktree has no `packages/` dir. The first msbuild fails with CS0246 (`Fizzler`/`Svg`/`log4net` not found) in vendored SVGControl. Run `nuget restore TaskMaster.sln` first (packages.config-based, ~168 packages). nuget.exe is at `/AppData/Local/Microsoft/WinGet/Packages/Microsoft.NuGet_Microsoft.Winget.Source_8wekyb3d8bbwe/nuget.exe`. - Standalone project builds (`msbuild Foo.csproj`) fail with "BaseOutputPath/OutputPath is not set" when `-p:Platform="Any CPU"` (with space) is passed, because the solution maps the per-project platform. Either build via `TaskMaster.sln` (which has the `Any CPU` solution config) or pass `-p:Platform=AnyCPU` (no space) for the standalone project. The forced-nullable Rebuild of UtilitiesCS uses `-p:Platform=AnyCPU`. - Full UtilitiesCS.Test run (~3814 tests) has ONE pre-existing flaky failure: `AddEntry_UseUiThreadTrue_DequeuesEntryAndSuppressesDispatcherException` (UI-thread/dispatcher timing). It fails at baseline independent of any change; capture the baseline failure set so post-change runs can be compared as "same single pre-existing failure" rather than a new regression. - Coverage convert: latest `.coverage` is under `TestResults//*.coverage`; convert with `Microsoft.CodeCoverage.Console.exe merge -f xml -o out.xml`. Tool is at `C:/Program Files/Microsoft Visual Studio/18/Community/Common7/IDE/Extensions/Microsoft/CodeCoverage.Console/Microsoft.CodeCoverage.Console.exe`. The merged XML instruments ALL loaded modules (vendored/third-party too), so whole-process line coverage looks low (~54%); the policy 80% gate applies to first-party modules, e.g. `UtilitiesCS.dll` ~87%. Per-method coverage: async methods appear as `d__N.MoveNext` functions with `type_name` set, so resolve the method by `type_name` containing ``. diff --git a/.claude/agent-memory/atomic-executor/project_long_runs_need_detached_process.md b/.claude/agent-memory/atomic-executor/project_long_runs_need_detached_process.md new file mode 100644 index 000000000..cd191ca0e --- /dev/null +++ b/.claude/agent-memory/atomic-executor/project_long_runs_need_detached_process.md @@ -0,0 +1,39 @@ +--- +name: long-runs-need-detached-process +description: Bash-tool background tasks get killed on long runs, taking Start-Job load generators with them; launch multi-hour runners with Start-Process -PassThru instead +metadata: + type: project +--- + +A multi-hour runner launched via the Bash tool's `run_in_background` was **killed mid-run** by the +session's background-task lifecycle after roughly an hour, discarding three completed suite runs. +Relaunching the identical script through a detached `Start-Process` survived the full 2.5-hour +window. + +**Why:** `run_in_background` tasks are owned by the session and can be stopped. PowerShell +`Start-Job` workers are children of the runner process, so when the runner dies the load generator +dies with it — which is at least fail-safe (no orphan busy loops), but the window is lost and must +be restarted from scratch, because a load window's start/stop utilization samples must bracket a +single continuous run. + +**How to apply:** For anything over ~30 minutes, launch it detached and record the PID: + +```powershell +$p = Start-Process -FilePath 'pwsh' ` + -ArgumentList @('-NoProfile','-NonInteractive','-File', $script) ` + -RedirectStandardOutput $log -RedirectStandardError $err ` + -WindowStyle Hidden -PassThru +Set-Content -LiteralPath $pidFile -Value $p.Id +``` + +Then poll the log file. To make real wall-clock time pass, issue a FOREGROUND +`sleep 570` with `timeout: 600000`; it runs the full ~9.5 minutes before being moved to background. +Repeated `run_in_background` sleeps do NOT advance time reliably, because each completion notifies +you immediately and you resume within seconds. + +Have the runner append one line per iteration to its log and rewrite a rows JSON after each +iteration, so a kill loses at most the in-flight iteration and the completed ones stay auditable. + +Also verify after any kill: `Get-Process pwsh | Select Id,CPU,StartTime` and confirm no worker from +your start time survives. Do not kill processes whose `StartTime` predates your session — see +[[project-sibling-worktree-shared-tooling-hazard]]. diff --git a/.claude/agent-memory/atomic-executor/project_pwsh_command_quoting_from_bash.md b/.claude/agent-memory/atomic-executor/project_pwsh_command_quoting_from_bash.md index 1e9e57d01..9f4be32a2 100644 --- a/.claude/agent-memory/atomic-executor/project_pwsh_command_quoting_from_bash.md +++ b/.claude/agent-memory/atomic-executor/project_pwsh_command_quoting_from_bash.md @@ -27,6 +27,14 @@ execute it once before trusting it. `-File` invocations are unaffected (no shell `$` in the payload). Related: [[project_build_test_env]], [[project_poshqc_pester_mcp_exit_minus1]]. +**Backtick corollary (measured 2026-08-23):** inside a *double-quoted* PowerShell string the +backtick is the escape character, so a byte-exact string replacement whose literal contains a +Markdown or C# backtick silently finds **0 matches** rather than erroring. Replacing +``- [ ] `BuildPumpHarness_...` `` in a spec file reported `match=0` until the literal was moved +into a single-quoted string. Any exact-block replace against Markdown or C# must use +single-quoted PowerShell strings (doubling `''` for apostrophes), and must assert the +match count is exactly 1 before writing. + Corollary measured at the same time: Pester 5.6.1 creates `CodeCoverage.OutputPath`'s parent directory (`New-Item -Force -ItemType Container`), so redirecting coverage into a not-yet-existing evidence folder is safe. Pester also ignores `Run.Exit` by default, so a diff --git a/.claude/agent-memory/atomic-executor/project_startprocess_arglist_array_strips_quoting.md b/.claude/agent-memory/atomic-executor/project_startprocess_arglist_array_strips_quoting.md new file mode 100644 index 000000000..0b5232f2f --- /dev/null +++ b/.claude/agent-memory/atomic-executor/project_startprocess_arglist_array_strips_quoting.md @@ -0,0 +1,42 @@ +--- +name: startprocess-arglist-array-strips-quoting +description: Detaching msbuild via `Start-Process -ArgumentList @(...)` silently drops the quoting on `/p:Platform=Any CPU`, so the gate dies with MSB1008 having compiled nothing; pass ONE pre-quoted argument string instead. +metadata: + type: project +--- + +When launching `MSBuild.exe` (or `vstest.console.exe`) detached via +`Start-Process -PassThru -RedirectStandardOutput ...`, pass the arguments as a **single +pre-quoted string**, not as an array: + +```powershell +# WRONG - dies with MSB1008, compiles nothing, exit code 1 +$argList = @('TaskMaster.sln','/t:Rebuild','/m','/p:Configuration=Debug', + '/p:Platform=Any CPU','/p:EnableNETAnalyzers=true') + +# RIGHT +$argList = 'TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true' +``` + +**Why:** `Start-Process` joins the array elements with spaces to build the child's command +line and does NOT re-quote an element that contains a space. `/p:Platform=Any CPU` arrives +as two arguments, so MSBuild sees a second "project" and exits 1 with: + +``` +MSBUILD : error MSB1008: Only one project can be specified. + Full command line: '"...MSBuild.exe" TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug /p:Platform=Any CPU ...' +``` + +Measured 2026-08-23 on the #511 remediation cycle. The failure is quiet in the worst way: the +launcher itself succeeds, `$p.ExitCode` is a legitimate 1, and the log's own +`Full command line:` echo is the only place the missing quotes are visible. A gate that only +checked "did the process exit" would have recorded a red analyzer gate as a code defect. + +**How to apply:** this is the exact same class of defect as +[[bash-tool-mangles-msbuild-switches]] one layer further in — the Bash tool mangles `/m` into +`M:/`, and `Start-Process -ArgumentList @(...)` mangles `"/p:Platform=Any CPU"`. Whenever a +plan mandates a detached long-run mechanic (`Start-Process -PassThru` + poll + take +`ExitCode` from the process object), build the argument line as one string and grep the log +for `Full command line:` on the first launch to confirm the quotes survived. Related: +[[project_pwsh_command_quoting_from_bash]], [[project_long_runs_need_detached_process]], +[[project_build_test_env]]. diff --git a/.claude/agent-memory/atomic-executor/project_utilitiescs_test_parallelism_flakiness.md b/.claude/agent-memory/atomic-executor/project_utilitiescs_test_parallelism_flakiness.md index 9c6eb7d93..106731c3d 100644 --- a/.claude/agent-memory/atomic-executor/project_utilitiescs_test_parallelism_flakiness.md +++ b/.claude/agent-memory/atomic-executor/project_utilitiescs_test_parallelism_flakiness.md @@ -5,13 +5,13 @@ metadata: type: project --- -Running the full `UtilitiesCS.Test` + `QuickFiler.Test` suite via `vstest.console.exe` produces non-deterministic failures: a small set of timing-sensitive UtilitiesCS.Test cases (e.g. `TryAddValuesAsync_UpdatesExistingValue`, `TryGetFileStreamWriter_WhenWriterReturnsMemoryStream_ReturnsStream`, OneDrive download tests) time out at ~22s and fail. Each PASSES in isolation at ~65ms. The suite runs MSTest class-level parallelization at Workers=0 (= processor count, 24 on MEGALODON4) via an assembly `[Parallelize]` attribute. +Running the full `UtilitiesCS.Test` + `QuickFiler.Test` suite via `vstest.console.exe` produces non-deterministic failures: a small set of timing-sensitive UtilitiesCS.Test cases (e.g. `TryAddValuesAsync_UpdatesExistingValue`, `TryGetFileStreamWriter_WhenWriterReturnsMemoryStream_ReturnsStream`, OneDrive download tests) time out at ~22s and fail. Each PASSES in isolation at ~65ms. The suite runs MSTest class-level parallelization at Workers=0 (= processor count, 24 on ) via an assembly `[Parallelize]` attribute. - Raw `/EnableCodeCoverage` (built-in collector): ~1-2 flaky failures per run, failing set changes run to run. - `dotnet-coverage collect` instrumentation: amplifies to ~20 flaky failures regardless of worker count (instrumentation overhead is the dominant cause, not just parallelism). **Why:** The failures are parallel CPU-starvation timeouts, not defects; they are pre-existing and unrelated to whatever code is under test. -**How to apply:** For a deterministic green gate run, pass a runsettings that overrides `4ClassLevel` via vstest `/Settings:`. Under the built-in Code Coverage collector at 4 workers the full suite is deterministically clean (4661 tests, 0 failed). This is a settings adjustment only — it does not weaken assertions or add retries/sleeps. For numeric coverage, still use `dotnet-coverage collect --output-format cobertura` (the `.coverage` binary is not offline-convertible here — see [[project-qfc227-coverage-tooling]]); a few flaky failures in that instrumented run do not invalidate the coverage numbers. `dotnet-coverage` is a GLOBAL tool (`C:\Users\DanMoisan\.dotnet\tools\dotnet-coverage.exe`), not in the repo tool manifest, so `dotnet tool run dotnet-coverage` fails — call the exe directly, and pass the wrapped vstest.console.exe path in Windows form (`C:\...`) or dotnet-coverage's process launcher cannot find it. +**How to apply:** For a deterministic green gate run, pass a runsettings that overrides `4ClassLevel` via vstest `/Settings:`. Under the built-in Code Coverage collector at 4 workers the full suite is deterministically clean (4661 tests, 0 failed). This is a settings adjustment only — it does not weaken assertions or add retries/sleeps. For numeric coverage, still use `dotnet-coverage collect --output-format cobertura` (the `.coverage` binary is not offline-convertible here — see [[project-qfc227-coverage-tooling]]); a few flaky failures in that instrumented run do not invalidate the coverage numbers. `dotnet-coverage` is a GLOBAL tool (`\.dotnet\tools\dotnet-coverage.exe`), not in the repo tool manifest, so `dotnet tool run dotnet-coverage` fails — call the exe directly, and pass the wrapped vstest.console.exe path in Windows form (`C:\...`) or dotnet-coverage's process launcher cannot find it. CSharpier: the repo `dotnet tool run csharpier` resolves v1.2.6 which uses `check`/`format` subcommands (`csharpier check .`, `csharpier format .`); the legacy `--check` flag is rejected. See [[project-repo-sdk-and-nullable-rebuild]]. diff --git a/.claude/agent-memory/atomic-executor/project_webview2_endinit_creates_handles.md b/.claude/agent-memory/atomic-executor/project_webview2_endinit_creates_handles.md new file mode 100644 index 000000000..12e9545ea --- /dev/null +++ b/.claude/agent-memory/atomic-executor/project_webview2_endinit_creates_handles.md @@ -0,0 +1,49 @@ +--- +name: webview2-endinit-creates-handles +description: ItemViewer construction already creates both WebView2 child window handles (and thus the viewer's own), measured; plus three pre-existing UtilitiesCS.Test flakes that surface under contention +metadata: + type: project +--- + +`new QuickFiler.ItemViewer()` constructed on a pump thread already reports +`L0v2h2_WebView2.IsHandleCreated == true` AND `L0vhBreadcrumb_WebView2.IsHandleCreated == true`, +with no harness, no `SaveParameters`, and no `.Handle` read anywhere. The handles come from +`InitializeComponent`'s Designer-emitted `((ISupportInitialize)(...)).EndInit()` calls on the two +`Microsoft.Web.WebView2.WinForms.WebView2` children. Because WinForms creates a parent's handle when +a child's handle is created, this is also why the `ItemViewer`'s own `IsHandleCreated` is already +`true` on every run. + +**Why:** #511/#571 planning predicted, from static reading, that the children would be handle-less +and that a `viewer.Handle` read (non-recursive) versus `CreateControl()` (Visible-gated, recursive) +would be observable through those two properties. Measured over four configurations, it is not: both +children are handle-created before either instrument runs. A plan task asserting +`IsHandleCreated == false` on them is unsatisfiable and its test fails for a reason unrelated to the +change under test. Full measurement in +`docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md`. + +**How to apply:** Before authoring or accepting any assertion about `ItemViewer` child-control handle +state, measure it — the WebView2 source is not in this repository, so static reading cannot settle +it. Do not treat a `viewer.Handle` insertion as the cause when such an assertion fails; comment the +insertion out and re-run to attribute it. See [[project-418-plan-rationale-clauses-are-evidence]] for +the general class: plan prose stating unmeasured world state. + +## Companion finding: three pre-existing `UtilitiesCS.Test` flakes under load + +Across 30 post-fix full-suite runs, three distinct `UtilitiesCS.Test` tests failed intermittently, +none related to QuickFiler or the pump harness: + +1. `Extensions.DfDeedle_COM_Tests.GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform` + — `NullReferenceException` under 100% CPU saturation. +2. `OutlookObjects.FilterDASL.DASLFilterParserTests.PrintTree_WritesIndentedTreeToConsole` + — `Expected writer.ToString() "" to contain "AND"`. +3. `ReusableTypeClasses.StackGeek_Tests.Main_RunsSampleScenarioWithoutThrowing` + — `Expected writer.ToString() "" to contain "Middle Element :"`. + +Items 2 and 3 share a root cause: both assert on a redirected `Console.Out` writer that comes back +EMPTY, the signature of a shared-`Console.Out` race between parallel test classes. + +**How to apply:** A plan gate demanding `failed == 0` across all nine assemblies on every one of N +consecutive runs is sensitive to these, and will fail for reasons a QuickFiler-scoped change cannot +influence. Expect roughly 1 failure per 10 full-suite runs under contention from this population. +Scope such a gate to the assemblies the change touches, or state the known-flaky carve-out +explicitly. diff --git a/.claude/agent-memory/atomic-executor/project_winformspumphost_tests_load_flaky.md b/.claude/agent-memory/atomic-executor/project_winformspumphost_tests_load_flaky.md index 6b9298363..b7c97926e 100644 --- a/.claude/agent-memory/atomic-executor/project_winformspumphost_tests_load_flaky.md +++ b/.claude/agent-memory/atomic-executor/project_winformspumphost_tests_load_flaky.md @@ -9,4 +9,10 @@ metadata: **Why:** The pump host creates a real WinForms control and drives a message loop. With MSTest `Workers: 0` (24 on this box, `scripts/vscode/TaskMaster.cli.runsettings`) plus `dotnet-coverage` instrumentation, handle creation can lose the race when the machine is CPU-saturated. Measured across five full-suite runs on a box at ~96% CPU (a `node` process at 207k CPU-seconds, several VS Code Insiders windows, a second `claude` session, Docker): run 1 hung outright, run 2 = 1 failure in 40.7s, run 3 = 7 timeout failures in 5.9min, runs 4-5 = the same 2 failures in ~40s. Three consecutive isolated runs of the class failed 2/9; a fourth, minutes later, passed 9/9. +**Idle MSBuild nodes alone are enough to flip it (2026-08-22, #511 Phase 1).** On an otherwise quiet box, the only difference between a failing and a passing `Invoke-MSTestWithCoverage.ps1` run was 17 leftover MSBuild node-reuse processes from prior `/m` builds. With them resident: 7 timeout failures (6430/6437). After `Get-Process MSBuild | Stop-Process -Force`: 6437/6437. **Kill idle MSBuild nodes before any pump-host test gate** — they are not visibly busy but still lose the race. Also note `Invoke-MSTestWithCoverage.ps1` throws at line ~236 the instant `dotnet-coverage` returns non-zero, which is *before* the Koverage post-processing step, so a failed run leaves a RAW Cobertura XML (forward-slash filenames, unmerged `` nodes) that must not be compared against a post-processed one. + +**A green pre-fix run does not exonerate the handle race.** Ten class-filtered plus ten full-suite pre-fix runs all passed 20/20 with `IsHandleCreated: true`, yet the failure mode was still reachable on the same machine minutes earlier. The handle is created inside `new ItemViewer()` via the WebView2 `ISupportInitialize` `BeginInit`/`EndInit` pair in `ItemViewer.Designer.cs` — outside the traced `ResolveControlGroups`/`SetupThemes`/`PopulateControls` path — so a probe asserting `harness.Viewer.IsHandleCreated` is the only instrument that reports handle state on a run where the end-to-end tests happen to pass. + +**On a genuinely idle box the whole nine-assembly suite is a ~50-second job, not a 20-minute one (measured 2026-08-23).** With the 17 idle MSBuild nodes stopped and average processor load at 15%, `vstest.console.exe <9 assemblies> /EnableCodeCoverage /InIsolation /TestCaseFilter:"TestCategory!=LiveOutlook"` finished in **51.7 s with 6459/6459 passed, 0 failed**, and `Invoke-MSTestWithCoverage.ps1` finished in **47 s with 6459/6459**. The three pre-existing `UtilitiesCS.Test` flakes tracked as **#594** did NOT fire in either run. Plans that budget "roughly 20 minutes over 6,437 tests" are quoting a loaded-machine figure; do not read a fast completion as a truncated or partial run — verify instead that the TRX `TestDefinitions` reference all nine assemblies and that `total` is in the 6,400s. + **How to apply:** Do not classify these as a pre-existing red baseline on the first red run. Check machine load (`Get-CimInstance Win32_Processor | Measure-Object LoadPercentage -Average`) and re-run when it drops. A `FullyQualifiedName~QfcItemController` scoped gate includes this class, so a plan gate demanding EXIT 0 on that filter inherits the flakiness — narrow the filter or re-run. Related: [[project_utilitiescs_test_parallelism_flakiness]], [[project_uithread_dispatcher_static_swap_race]], [[project_configcontroller_sta_pump_deadlock]], and the GUI-seam rule in [[tests-must-mock-gui-no-visible-window]]. diff --git a/.claude/agent-memory/atomic-planner/MEMORY.md b/.claude/agent-memory/atomic-planner/MEMORY.md index 08efeb8f8..d0835004d 100644 --- a/.claude/agent-memory/atomic-planner/MEMORY.md +++ b/.claude/agent-memory/atomic-planner/MEMORY.md @@ -3,6 +3,9 @@ - [Agent worktrees need SDK + NuGet + analyzer-backfill bootstrap](agent-worktrees-need-sdk-and-nuget-bootstrap.md) — no `.dotnet-sdk`, no `packages/`, and a clean restore still misses the skewed analyzer versions (CS0006, not a warning); three Phase 0 tasks - [/Logger:trx needs /ResultsDirectory](trx-needs-resultsdirectory.md) — TRX lands in `TestResults\` relative to cwd; TRX-existence-under-evidence acceptance is unsatisfiable without it, and the clean-tree gate won't catch it - [Per-task TRX subdirectory](trx-needs-resultsdirectory.md) — a shared `/ResultsDirectory:` makes "ten distinct TRX files" ambiguous once `[expect-fail]` runs deposit earlier TRX there; give each task a `p#-t#` segment +- [Spec corrections sweep sibling sections](feedback_spec_corrections_sweep_sibling_sections.md) — falsified-premise fixes must cover Scope/Out-of-scope/Rollout, not AC only; denial text must dodge closing-keyword scans (#511 R1 Part 6) +- [#511 R1 preflight delta seams](project_511_r1_preflight_delta_seams.md) — mid-cycle raw-evidence deletion breaks resolves gates; git-log scans post-commit only; absolute MSBuild path; Start-Process mechanic for 20-min runs; per-class coverage noise -0.50pp +- [CSharpier "Formatted N files" is processed count](csharpier-formatted-n-is-processed-count.md) — restart-on-rewrite loops keyed on it never terminate; define rewritten-count via before/after SHA-256 - [Terminal-phase planner traps](terminal-phase-planner-traps.md) — sweep the last phase for an unowned "a follow-up issue should carry it", artifacts written after the clean-tree commit task, and a false "clarification against the spec's wording" - [#553 CI parallel-split plan seams](project_553_ci_parallel_split_plan_seams.md) — workflow-only scope: no C# toolchain; Phase 0 snapshot for byte-identity; ruleset PUT + gh pr create orchestrator-gated; no jq (ConvertTo-Json -Depth 20); pathspec anchoring; BRANCH/SCRATCH conventions @@ -55,7 +58,7 @@ - [STA last-resort control-identity plan pattern](project_sta_last_resort_control_identity_pattern.md) — epic #295: measure control-identity partials via companion interface (real Label/Control) + *.StaTests.cs ([STATestClass], MSTest 4.2.2); never construct Form; handle/pump residue stays method-level exempt - [#307 F2 ScoCollection deletion gate](project_307_f2_scocollection_deletion_gate.md) — full first-party ScoCollection/ScoStack reference set incl. tests beyond spec §7; ISubjectMapSco/IScoCollection F5 boundary; FS/Prompt seams live in ScoCollection.cs - [#328 store-exclusion seams](project_328_store_exclusion_seams.md) — StoresWrapper(469)/TreeOfToDoItems(481) near 500-limit, ToDoEvents(594) pre-existing over-limit; new test .cs need csproj wiring; four inclusion surfaces lockstep; adopted persisted StoreWrapper.StoreId -- [C# coverage gate expects JaCoCo](project_csharp_coverage_gate_jacoco_format.md) — validate-feature-review-coverage.ps1 reads artifacts/csharp/coverage.xml as JaCoCo, not Cobertura; plan a conversion scoped to first-party +- [C# coverage gate: JaCoCo hook, Cobertura also accepted](project_csharp_coverage_gate_jacoco_format.md) — hook parses JaCoCo, but #230/#438/#511-R1 shipped Cobertura (reviewer parses directly); follow the format the delta names - [Durable script copy into feature folder](durable-script-copy-into-feature-folder.md) — copy scratchpad-supplied scripts into `/scripts/` before referencing them in plan tasks (session-scoped temp paths aren't durable) - [#351 QuickFiler breadcrumb plan seams](project_351_quickfiler_breadcrumb_plan_seams.md) — JSON code in UtilitiesCS only (QuickFiler lacks Newtonsoft); P2-T1 blocked-if-9101-absent; evidence/repro/ rejected; coordinator pattern - [Dispatcher repro hang trap](dispatcher-repro-hang-trap.md) — a repro that touches Dispatcher.CurrentDispatcher on a pooled worker hangs on awaited InvokeAsync instead of failing; use an owned pumping STA thread @@ -72,3 +75,6 @@ - [One AC per check-off task](feedback_ac_checkoff_one_per_task.md) — preflight rejects batched AC check-offs; one checkbox + own evidence pointer per task (#230 B4) - [Post-format file-size audit + async-tail asymmetry](feedback_postformat_file_size_audit.md) — 500-line audit goes AFTER final csharpier format; awaited vs fire-and-forget tails decide completion-vs-fault test shape (#230 B2/B3) - [Wiring gates must be wiring-sensitive](feedback_wiring_gates_must_be_wiring_sensitive.md) — count floors deflate with the defect they guard; use static [TestMethod] enumeration vs /ListTests discovery (#230 rev3) + +## Artifact hygiene +- [Never embed absolute host paths](../_shared_no_absolute_host_paths.md) — no `C:\Users\\...`, bare account, or machine name in ANY artifact; use `` / `` / `` / ``. vstest names TRX `__.trx` by default, so control `/ResultsDirectory:` + `LogFileName=` or rename before citing. diff --git a/.claude/agent-memory/atomic-planner/csharpier-formatted-n-is-processed-count.md b/.claude/agent-memory/atomic-planner/csharpier-formatted-n-is-processed-count.md new file mode 100644 index 000000000..8b02a2326 --- /dev/null +++ b/.claude/agent-memory/atomic-planner/csharpier-formatted-n-is-processed-count.md @@ -0,0 +1,21 @@ +--- +name: csharpier-formatted-n-is-processed-count +description: CSharpier 1.x "Formatted N files" is a processed-file count, not a rewrite count — a restart-loop keyed on it never terminates; define rewritten-count via before/after SHA-256 +metadata: + type: feedback +--- + +A format task whose restart rule reads "if the rewritten-file count is greater than 0, restart the +loop" must define that count as the number of target files whose SHA-256 (`Get-FileHash -Algorithm +SHA256`) differs between a capture immediately before and immediately after the `csharpier format` +invocation — and must state explicitly that the console line `Formatted N files` is NOT that count. + +**Why:** CSharpier 1.x prints `Formatted N files` as the count of files it *processed*, whether or +not it changed any bytes. A three-file scoped format therefore always prints 3, so a naive reading +makes the restart condition permanently true and the toolchain loop never terminates. Caught as +#511 R1 preflight BLOCKING delta 7 (2026-08-23). + +**How to apply:** In every scoped-format task with a restart-on-rewrite rule: (1) require the six +hashes (before/after per file) in the evidence artifact, (2) define rewritten-count as the hash-diff +count, (3) add the explicit prohibition on using `Formatted N files`. Related: +[[csharpier-format-not-pipe-files-gate]], [[csharpier-repowide-format-breaks-zero-diff-acs]]. diff --git a/.claude/agent-memory/atomic-planner/feedback_spec_corrections_sweep_sibling_sections.md b/.claude/agent-memory/atomic-planner/feedback_spec_corrections_sweep_sibling_sections.md new file mode 100644 index 000000000..9944be182 --- /dev/null +++ b/.claude/agent-memory/atomic-planner/feedback_spec_corrections_sweep_sibling_sections.md @@ -0,0 +1,12 @@ +--- +name: spec-corrections-sweep-sibling-sections +description: When a finding falsifies a spec premise, sweep the WHOLE spec (Scope & Non-Goals, Out-of-scope, Rollout) for the same premise, not just the Acceptance Criteria section +metadata: + type: feedback +--- + +When a remediation finding falsifies a premise stated in a spec's `## Acceptance Criteria`, plan revision tasks for EVERY spec section that asserts the same premise — `## Scope & Non-Goals` "In scope" bullets, out-of-scope bullets that say a follow-up issue "requires its own issue" (name the now-existing issue number instead), and `## Rollout & Follow-up`. + +**Why:** In #511 R1 the first remediation plan revised only AC 6; the spec's three "In scope" bullets still claimed deterministic handle creation, "#571 in full", and a handle race. The orchestrator had to amend the requirements doc (Part 6 addendum + exit criterion 7) and force a plan revision, because an AC-only fix leaves the spec internally contradictory and the feature audit raises it as blocking. + +**How to apply:** Before finalizing a Finding-E-style spec-wording task, grep the spec for the falsified claim's key tokens across all sections and add one atomic replacement task per contiguous edit site. Also: (a) revision denial text must avoid closing-keyword stems immediately before prohibited issue refs (write "is not delivered by", never "does not fix #571") when a `(fix|clos|resolv)[a-z]* #N` zero-scan gates the branch; (b) assert retention of the accurate bullets with exactly-1 literals; (c) re-derive every downstream exit-criteria count (six vs seven) named in Phase 0 read tasks and the final handoff index. See [[zero-hit-grep-gates-need-carveouts]] and [[terminal-phase-planner-traps]]. diff --git a/.claude/agent-memory/atomic-planner/project_511_r1_preflight_delta_seams.md b/.claude/agent-memory/atomic-planner/project_511_r1_preflight_delta_seams.md new file mode 100644 index 000000000..80692c88f --- /dev/null +++ b/.claude/agent-memory/atomic-planner/project_511_r1_preflight_delta_seams.md @@ -0,0 +1,49 @@ +--- +name: project-511-r1-preflight-delta-seams +description: "#511 R1 revision lessons: mid-cycle raw-evidence deletion breaks resolves-to-existing gates; git-log scan legs must run post-commit; absolute MSBuild path under pwsh -NoProfile; detached Start-Process mechanic for ~20-min runs; per-class dotnet-coverage noise tolerance -0.50pp" +metadata: + type: project +--- + +Eight blocking + seven warning preflight deltas on the #511 remediation plan (2026-08-23), most of +them generalizable planner traps: + +1. **Raw evidence deleted between plan-writing and execution invalidates every + "cited path resolves to an existing file" gate.** When a maintainer deletes raw TRX/.coverage + mid-cycle, sweep the whole plan for citations of the deleted directories (`p4-t2/` appeared in a + check-off task, a rationale task, AND prose); re-point gates at the distilled Markdown records + plus the disposition record, and mark prose mentions "named in prose only, must not be asserted + to exist". Reword prospective deletion clauses into the past tense. +2. **A `git log --format=%B $MergeBase..HEAD` closing-keyword scan placed before the plan's commit + tasks can never fail** (0 messages from this plan are visible yet). Put the git-log leg in the + commit task itself (post-commit) and repeat it after any later commit; keep only file legs in the + pre-commit handoff index. Cousin of [[diff-gates-need-a-commit-task]]. +3. **Bare `msbuild` does not resolve under `pwsh -NoProfile`** (no VS developer environment; + `command -v msbuild` empty). Use the verified absolute path + `C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe` via `&`, + and require each artifact to record the resolved path. Extends + [[project-csharp-phase0-toolchain-bootstrap]]. +4. **Plans must mandate a detached-launch mechanic for long commands**: nine-assembly + `/InIsolation` vstest and dotnet-coverage runs are ~20 min over 6,437 tests vs a 600,000 ms tool + ceiling. Phase preamble must require `Start-Process -PassThru` + `-RedirectStandardOutput/-Error` + to a log, PID recorded, log polled with short waits, `EXIT_CODE:` from the process object's + `ExitCode`, and kill-the-whole-tree (pwsh runner + testhost + vstest.console + dotnet-coverage) + before any retry. +5. **Per-class `dotnet-coverage` line-rates are not bit-stable.** On a comments-only diff, keep the + package-level delta gate strict `>= 0` but allow per-class deltas `>= -0.50` percentage points, + recorded as measurement noise with both raw rates cited. A no-tolerance per-class `>= 0` gate + fails for measurement reasons. +6. **A coverage-run escape hatch must be bounded and signature-scoped**: the baseline records + Invoke-MSTestWithCoverage failing once under load with 60,000 ms `PumpTimeoutMs` expiries (#592, + out of scope) and throwing before post-processing. Authorize re-running that one task up to twice + on that signature only, logging each attempt + machine load; any other failure restarts the loop. +7. **Verify-don't-recreate an existing `.gitignore`**: the dictated create-with-exactly-N-lines task + would have deleted `Deploy_*/` — the vstest deployment scratch dir whose default name embeds + account+host (a host-identifier leak, see [[_shared_no_absolute_host_paths]]). Convert to + verify-lines + append-only. +8. **G6 line-wrap fix by shortening the literal to the head fragment**: the spec sentence wrapped at + `...record the` / `number here.`, so assert `File this as its own issue and record the` (1 line + today, 0 after the edit) instead of the full sentence (0 both ways). + +**How to apply:** treat 1-4 as a standing sweep whenever raw artifacts were disposed mid-cycle or a +plan carries msbuild/vstest commands; 5-6 whenever a coverage-delta gate rides a comments-only diff. diff --git a/.claude/agent-memory/atomic-planner/project_csharp_coverage_gate_jacoco_format.md b/.claude/agent-memory/atomic-planner/project_csharp_coverage_gate_jacoco_format.md index 97f746443..5fcf401bd 100644 --- a/.claude/agent-memory/atomic-planner/project_csharp_coverage_gate_jacoco_format.md +++ b/.claude/agent-memory/atomic-planner/project_csharp_coverage_gate_jacoco_format.md @@ -1,6 +1,6 @@ --- name: project-csharp-coverage-gate-jacoco-format -description: The feature-review coverage hook expects JaCoCo XML at artifacts/csharp/coverage.xml, but executors emit Cobertura — a conversion is required, not Cobertura-as-is +description: The feature-review hook parses artifacts/csharp/coverage.xml as JaCoCo, but repo precedent also accepts Cobertura there (hook nulls out, reviewer parses Cobertura directly) — follow whichever format the remediation delta names metadata: type: project --- @@ -15,8 +15,18 @@ attributes), and feature evidence is stored as `*.cobertura.xml`. The hook canno missing/absent `artifacts/csharp/coverage.xml` is graded a mandatory coverage FAIL even when coverage was in fact produced (this triggered the #328 R1 remediation). -**How to apply:** When a coverage-artifact remediation asks to "place coverage at the canonical path," -plan a Cobertura -> JaCoCo **conversion**, not a copy. Scope the JaCoCo aggregate to first-party +**Both formats are accepted precedent — check what the caller/delta names.** #503 shipped JaCoCo at +the canonical path (hook-readable). #230 and #438 shipped **Cobertura** there: their policy audits +explicitly record that the hook's JaCoCo query computes null and "does not itself gate the +percentages," and the reviewer's direct Cobertura parse (root `line-rate`/`branch-rate`) is the +authoritative measurement. #511 R1 (2026-08-23) had an executor preflight delta that mandated the +Cobertura copy with `line-rate >= 85` / `branch-rate >= 75` acceptance — do not "correct" such a +delta to JaCoCo; the Cobertura route is valid because the reviewer, not the hook, computes the figures. + +**How to apply:** When a coverage-artifact remediation asks to "place coverage at the canonical path" +and does not name a format, plan a Cobertura -> JaCoCo **conversion**, not a copy, so the hook itself +can read it. When the delta names Cobertura and cites `line-rate`/`branch-rate` gates, plan the copy +verbatim. Scope the JaCoCo aggregate to first-party production packages (exclude vendored Deedle/FSharp.Core/Swordfish/SVGControl and `*.Test` assemblies) so the readable repo-wide line number reflects the first-party denominator, not the nondeterministic whole-process denominator (the whole-process line-rate mixes vendored modules and reads ~62-63%). diff --git a/.claude/agent-memory/atomic-planner/project_csharp_phase0_toolchain_bootstrap.md b/.claude/agent-memory/atomic-planner/project_csharp_phase0_toolchain_bootstrap.md index 2bedc70ac..b90ea6e70 100644 --- a/.claude/agent-memory/atomic-planner/project_csharp_phase0_toolchain_bootstrap.md +++ b/.claude/agent-memory/atomic-planner/project_csharp_phase0_toolchain_bootstrap.md @@ -10,7 +10,7 @@ Every C# atomic plan in this repo must resolve its toolchain explicitly in Phase **Verified 2026-08-08 (issue #508 preflight, agent worktree):** 1. `dotnet tool run csharpier` is **broken and must not be planned**. There is no `.config/dotnet-tools.json` (the manifest sits at repo root as `dotnet-tools.json`, which `dotnet tool run` does not read), and `global.json` pins an SDK under an absent `.dotnet-sdk`, so every `dotnet` SDK command fails with the missing-SDK error. -2. Prefer the **global tools**, which were confirmed on PATH: `C:\Users\DanMoisan\.dotnet\tools\csharpier.exe` (1.3.0) and `C:\Users\DanMoisan\.dotnet\tools\dotnet-coverage.exe` (18.5.2). CSharpier 1.x needs the `format` / `check` subcommand; bare `csharpier .` is invalid. +2. Prefer the **global tools**, which were confirmed on PATH: `\.dotnet\tools\csharpier.exe` (1.3.0) and `\.dotnet\tools\dotnet-coverage.exe` (18.5.2). CSharpier 1.x needs the `format` / `check` subcommand; bare `csharpier .` is invalid. 3. `vstest.console.exe` is NOT on PATH; resolve via `C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe`. 4. A **NuGet restore task is mandatory** in a fresh agent worktree: `packages/` does not exist and there is no `bin\Debug` output, so analyzer and nullable baselines are vacuous (or fail CS0006) without it. Use `pwsh -File scripts/vscode/Invoke-Restore.ps1` (`msbuild /t:Restore /p:RestorePackagesConfig=true`, no .NET SDK required); fall back to the WinGet `nuget.exe restore TaskMaster.sln`. Watch for analyzer version skew between `` HintPaths and the `packages.config` pins — that is an environment issue, not a plan defect. Parameters confirmed 2026-08-10: `-SolutionPath` (default `TaskMaster.sln`), `-Configuration`, `-Platform`. 5. **The restore task is required by any plan that runs `msbuild /t:Build`, not just C# plans.** Re-confirmed 2026-08-10 on the #457 PowerShell-only feature: it changes no `.cs` file but still builds to produce `*.Test.dll` for a coverage run, and its `EXIT_CODE: 0` build acceptance was unreachable without restore (`UtilitiesCS.csproj` carries `..\packages\AngleSharp.*` HintPaths and a `..\packages\Meziantou.Analyzer.*\build\...` ``). Route on "does any task invoke msbuild", not on "is this a C# feature". diff --git a/.claude/agent-memory/epic-planner/reference_epic_plan_tooling_not_vendored.md b/.claude/agent-memory/epic-planner/reference_epic_plan_tooling_not_vendored.md index 1a73e73de..5b4f2fedb 100644 --- a/.claude/agent-memory/epic-planner/reference_epic_plan_tooling_not_vendored.md +++ b/.claude/agent-memory/epic-planner/reference_epic_plan_tooling_not_vendored.md @@ -8,7 +8,7 @@ metadata: The `epic-plan` and `epic-orchestrate` skills cite `scripts/dev_tools/epic_wave_computation.py` as the tested wave-assignment reference and imply an epic-manifest schema validator. In the TaskMaster repo (worktrees under -`C:/Users/DanMoisan/repos/TaskMaster-wt/`) neither is vendored: `find scripts -name "*epic*"` +`-wt/`) neither is vendored: `find scripts -name "*epic*"` returns nothing, and the MCP validator's `artifact_type` enum has no epic-manifest type (only `epic-planner-state`, `epic-orchestrator-state`, `epic-kickoff`, `plan`, etc.). diff --git a/.claude/agent-memory/feature-review/MEMORY.md b/.claude/agent-memory/feature-review/MEMORY.md index 794b86811..36afca094 100644 --- a/.claude/agent-memory/feature-review/MEMORY.md +++ b/.claude/agent-memory/feature-review/MEMORY.md @@ -61,3 +61,7 @@ - [build-ci-coverage-gate-fidelity epic outcome](project_build-ci-coverage-gate-fidelity-epic-outcome.md) — 80-vs-85 contradiction NOT removed; runner gate 80 vs hook 85; C# 85.55%, PS branch nonexistent - [PowerShell coverage is nondeterministic](project_powershell-coverage-nondeterministic-vsbuild-tests.md) — Invoke-VSBuild.Tests.ps1 runs vswhere + Sync-PackageReferences for real; measure PS coverage in-session, never quote a stored figure - [449-review-residuals](project_449-review-residuals.md) — PASS/0 blocking; untracked #584 promotion doc owed a non-child route; unused usings in base test file; AC-supersession-via-plan-provision pattern validated +- [511-rescope-review-residuals](project_511-rescope-review-residuals.md) — 2026-08-24 re-audit PASS/0 blocking; residuals CR-1 stale RCA narrative + CR-2 AC-vs-deleted-TRX wording; PR must not close #511/#571 (#592/#594/#597 carry the real defects) + +## Artifact hygiene +- [Never embed absolute host paths](../_shared_no_absolute_host_paths.md) — no `C:\Users\\...`, bare account, or machine name in ANY artifact; use `` / `` / `` / ``. vstest names TRX `__.trx` by default, so control `/ResultsDirectory:` + `LogFileName=` or rename before citing. diff --git a/.claude/agent-memory/feature-review/project_511-rescope-review-residuals.md b/.claude/agent-memory/feature-review/project_511-rescope-review-residuals.md new file mode 100644 index 000000000..f19a9e5eb --- /dev/null +++ b/.claude/agent-memory/feature-review/project_511-rescope-review-residuals.md @@ -0,0 +1,36 @@ +--- +name: 511-rescope-review-residuals +description: 'winformspumphost-511 re-audit (2026-08-24): PASS/0 blocking under re-scoped claims; residuals CR-1 stale spec RCA narrative, CR-2 AC wording vs maintainer-deleted raw TRX; PR must not close #511/#571' +metadata: + type: project +--- + +Re-audit of `winformspumphost-suite-determinism-511` after remediation cycle 1 closed with 14/14 +AC PASS and 0 blocking findings (artifacts stamped `2026-08-24T00-01`). The feature was re-scoped +by maintainer decision (`decision-record.2026-08-23T20-40.md`): the fixture-hardening remedy was a +measured no-op, so the branch keeps the hardening + two regression tests pinning the measured +WebView2 handle-inheritance state, and claims no repair. #511/#571 are CLOSED NOT_PLANNED, +superseded by #592 (real cause: load-induced 60 s PumpTimeoutMs cascade); #594 = UtilitiesCS.Test +flakes; #597 = analyzer skew. + +**Why:** future reviews of related branches (PR for this branch, #592/#594/#597 work) need the +accepted-residual list so they are not re-raised as new findings, and must verify no closing +keyword for #511/#571 appears in the PR body. + +**How to apply:** +- Accepted non-blocking residuals: CR-1 — spec `## Root Cause Analysis` still asserts the + falsified pre-measurement claims ("IsHandleCreated is false for the whole test"; "children never + obtain a handle") with no revision marker; annotation owed in a follow-up. CR-2 — AC 1/AC 3 + still say "ten TRX results stored under evidence/regression-testing/" though the raw TRX were + deleted at maintainer instruction after fidelity verification + (`evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`). CR-5 — AC 10 line ref + `:139` drifted to `:148`. +- Maintainer-ratified pattern confirmed again: committed disposition record supersedes AC literal + wording (raw-artifact deletion), and an absolute-zero suite gate narrows to owned classes with + the residual promoted (#594) — same precedent as [[441-review-residuals-and-494-handoff]]. +- The remediation-inputs carve-out is binding: `remediation-inputs.2026-08-23T20-57.md` contains + three closing-keyword regex matches inside negations and is exempt by design; also + `plan.2026-08-21T18-10.md:26` (pre-existing file content). Do not re-raise either. +- pr_context summary again misclassified the 3 changed `.cs` files as docs-only (see + [[pr-context-summary-misclassifies-cs]]); corrected in place with `- path (+N/-N)` bullets so + the hook enumerates CSharp. diff --git a/.claude/agent-memory/orchestrator/MEMORY.md b/.claude/agent-memory/orchestrator/MEMORY.md index 229719e3c..9c8b7a0e9 100644 --- a/.claude/agent-memory/orchestrator/MEMORY.md +++ b/.claude/agent-memory/orchestrator/MEMORY.md @@ -83,3 +83,9 @@ - [C# agent worktree needs three bootstrap steps](csharp-agent-worktree-needs-three-bootstrap-steps.md) — no `.dotnet-sdk`, no `packages/`, and a clean restore still hits `error CS0006` on skewed analyzer versions; green CI is cache-explained, not tolerance - [potential_to_issue keeps ONLY the Summary section](potential-to-issue-keeps-only-summary-section.md) — every other section becomes "(not provided in potential file)"; verify the issue body, post the rest as a comment - [Epic kickoff facts need independent measurement](epic-kickoff-facts-need-independent-measurement.md) — a kickoff predicted a 500-line cap finding from a conflated file; the named file was 323 lines, not 1,065 +- [WebView2 EndInit creates handles at construction](webview2-endinit-creates-handles-at-construction.md) — a bare ItemViewer already has both child handles AND its own; any "force the handle" remedy is a measured no-op +- [blocked_reason enum can't express a substantive halt](blocked-reason-enum-cannot-express-substantive-halt.md) — 7 mechanical members only; use "none" plus free-form halt/blocking_findings keys, never a wrong member + +## Artifact hygiene +- [Never embed absolute host paths](../_shared_no_absolute_host_paths.md) — no `C:\Users\\...`, bare account, or machine name in ANY artifact; use `` / `` / `` / ``. vstest names TRX `__.trx` by default, so control `/ResultsDirectory:` + `LogFileName=` or rename before citing. +- [Closing keyword fires inside a negation](closing-keyword-fires-inside-negation.md) — `does NOT fix #511` still auto-closes #511; scan commit messages and PR bodies, never file contents diff --git a/.claude/agent-memory/orchestrator/bash-tool-mangles-msbuild-switches.md b/.claude/agent-memory/orchestrator/bash-tool-mangles-msbuild-switches.md index e80c7cae1..9398e72d3 100644 --- a/.claude/agent-memory/orchestrator/bash-tool-mangles-msbuild-switches.md +++ b/.claude/agent-memory/orchestrator/bash-tool-mangles-msbuild-switches.md @@ -13,7 +13,7 @@ Running msbuild directly through the Bash tool fails with `MSBUILD : error MSB10 - msbuild: `C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe` - vstest: `C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe` -- csharpier: `C:\Users\DanMoisan\.dotnet\tools\csharpier.exe` (global tool; there is no `.config/dotnet-tools.json`, so `dotnet tool run csharpier` does not work) +- csharpier: `\.dotnet\tools\csharpier.exe` (global tool; there is no `.config/dotnet-tools.json`, so `dotnet tool run csharpier` does not work) - test + coverage: `pwsh -NoProfile -File scripts/vscode/Invoke-MSTestWithCoverage.ps1 -Configuration Debug` **A fresh worktree needs `nuget restore TaskMaster.sln` first.** Without it the build fails with CS0246 on `log4net` and `SvgDocument` — misleading errors that look like broken source rather than a missing restore. diff --git a/.claude/agent-memory/orchestrator/blocked-reason-enum-cannot-express-substantive-halt.md b/.claude/agent-memory/orchestrator/blocked-reason-enum-cannot-express-substantive-halt.md new file mode 100644 index 000000000..27d309371 --- /dev/null +++ b/.claude/agent-memory/orchestrator/blocked-reason-enum-cannot-express-substantive-halt.md @@ -0,0 +1,35 @@ +--- +name: blocked-reason-enum-cannot-express-substantive-halt +description: checkpoint blocked_reason is a 7-member enum covering only mechanical delegation/validator failures; a halt because the plan's premise was falsified has no valid member +metadata: + type: reference +--- + +`artifacts/orchestration/orchestrator-state.json`'s `blocked_reason` is validated against a fixed +vocabulary (`VALID_BLOCKED_REASONS`, in `.claude/lib/orchestrator-state/OrchestratorState.psm1` +around line 96): + +``` +none, spawn_agent_unavailable, delegation_launch_failed, delegate_no_receipt, +delegate_contract_incomplete, validator_failed, user_requested_stop +``` + +Free text is rejected with `Checkpoint has invalid blocked_reason: `. + +**Every member describes a mechanical failure** — an agent that would not spawn, a delegation that +would not launch, a missing or malformed receipt, a validator that failed, or an explicit user stop. +There is **no member for a substantive halt**: the case where every delegation succeeded, every +validator passed, and the orchestrator stopped because the work's own evidence falsified the plan's +premise. + +**How to apply:** record `blocked_reason: "none"` to keep the checkpoint schema-valid, and put the +real reason in free-form sibling keys (a `halt` object and a `blocking_findings` object both +validate fine — the schema checks required keys, not unknown ones). Do **not** reach for a +mechanical member such as `validator_failed` to make the field look populated; it misrepresents what +happened and will mislead whoever resumes. Say plainly in the report that the enum could not express +the halt. The gap is worth promoting to an issue. + +Related: the validator also demands a fuller `delegation_receipts[]` shape than is obvious — +`step`, `agent_id`, `skill_source`, `started_at`, `completed_at`, `result_signal`, `artifact_paths` +are all required per receipt. See [[completion-gate-receipt-shapes]] and +[[orchestrator-state-flat-keys-and-enum]]. diff --git a/.claude/agent-memory/orchestrator/closing-keyword-fires-inside-negation.md b/.claude/agent-memory/orchestrator/closing-keyword-fires-inside-negation.md new file mode 100644 index 000000000..0588495aa --- /dev/null +++ b/.claude/agent-memory/orchestrator/closing-keyword-fires-inside-negation.md @@ -0,0 +1,34 @@ +--- +name: closing-keyword-fires-inside-negation +description: GitHub parses "fix #N"/"close #N" in commit messages and PR bodies even inside a negation like "does NOT fix #511" - scan and rewrite before merging to the default branch +metadata: + type: feedback +--- + +GitHub's auto-close parser matches `close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved` +followed by `#N`. It does **not** understand negation. A commit message reading +`this commit does NOT fix #511 or #571` contains the literal `fix #511` and will close #511 when +the commit lands on the default branch. + +**Why:** On #511 two commits already on the branch said `does not claim to close #511` and +`does NOT fix #511 or #571`. Both were written specifically to disclaim a repair. Merging them to +`main` would have auto-closed #511 and could have flipped its `state_reason` from `NOT_PLANNED` to +`COMPLETED` — the exact false claim the whole branch existed to avoid. Caught only by an explicit +regex scan of the commit messages before the PR was opened. + +**How to apply:** + +- Scan before opening any PR: `git log f..HEAD --format=%B | grep -Ein '(clos(e|es|ed)|fix(|es|ed)|resolv(e|es|ed))[[:space:]:]*#[0-9]+'`, and scan the PR body the same way. +- Write `is not delivered by`, `makes no repair claim for`, or `#N is not addressed here`. Never + put a keyword stem immediately before the reference, even negated. +- **Scope:** GitHub parses commit messages and PR/issue bodies only. File CONTENTS are never + parsed, so a `Fix #571` sitting in a committed plan or spec is harmless and does not need editing. + Do not waste a cycle "fixing" prose inside files. +- To repair history non-interactively (interactive rebase is unavailable in this environment): + `FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --msg-filter 'sed -e "s/old/new/g"' ..HEAD`, + then verify the tree is byte-identical with `git diff --stat HEAD` before force-pushing. +- `collect_pr_context` makes this worse, not better: its "Author-asserted autoclose issues" list is + scraped from text and listed #511 and #571 for a PR that must not close either. Never copy that + list into a body; when GitHub validation is unavailable the skill's own fallback is a `None` bullet. + +See [[project-epic-child-prs-no-ci]] for the related base-branch decision. diff --git a/.claude/agent-memory/orchestrator/csharp-agent-worktree-needs-three-bootstrap-steps.md b/.claude/agent-memory/orchestrator/csharp-agent-worktree-needs-three-bootstrap-steps.md index 5fcfb1a66..9bc4c95aa 100644 --- a/.claude/agent-memory/orchestrator/csharp-agent-worktree-needs-three-bootstrap-steps.md +++ b/.claude/agent-memory/orchestrator/csharp-agent-worktree-needs-three-bootstrap-steps.md @@ -13,7 +13,7 @@ blocking, because every `EXIT_CODE: 0` acceptance downstream is unreachable with `rollForward: latestFeature` and `paths: [".dotnet-sdk", "$host$"]`. A fresh worktree has none, and the host SDK (10.0.302) cannot satisfy it. `dotnet --version` from the worktree root prints the `global.json` `errorMessage` instead of a version. Fix: `scripts/vscode/Install-RepoDotNetSdk.ps1`, - or mirror `C:\Users\DanMoisan\repos\TaskMaster\.dotnet-sdk`. Ignored by `.gitignore:350` (`.dotnet*/`). + or mirror `\.dotnet-sdk`. Ignored by `.gitignore:350` (`.dotnet*/`). 2. **`packages/` is absent.** Every project declares `EnsureNuGetPackageBuildImports` whose `` fires at `BeforeTargets="PrepareForBuild"`, so msbuild hard-fails. Fix: `nuget restore TaskMaster.sln` (what CI does at `.github/workflows/_build-analyzers.yml:45`). Restored content is ignored by diff --git a/.claude/agent-memory/orchestrator/feedback_commit_review_artifacts_and_step8_preflight.md b/.claude/agent-memory/orchestrator/feedback_commit_review_artifacts_and_step8_preflight.md index 7f882bdc8..6a5304ca1 100644 --- a/.claude/agent-memory/orchestrator/feedback_commit_review_artifacts_and_step8_preflight.md +++ b/.claude/agent-memory/orchestrator/feedback_commit_review_artifacts_and_step8_preflight.md @@ -11,4 +11,4 @@ Two process facts confirmed on issue #270 / PR #272 (small-path bug, rebase-then 2. **PR-creation-ready preflight requires `step8_status` to be non-pending.** `Invoke-OrchestratorStatePreflight` (the `--require-pr-creation-ready` equivalent in `.claude/lib/orchestrator-state/OrchestratorState.psm1`) fails with "step8_status is pending" even when everything else is ready. Set `step8_status` to `delegated` (PR authoring underway) BEFORE running the preflight; flip to `verified` after `gh pr create` succeeds. Steps 5-8 must all be non-pending/non-blocked. **Why:** step8 is the PR-creation step; the gate treats a pending step8 as "not started." See [[pr-author-hook-blocks-gh-in-this-repo]] for the in-thread pr-author body+SHA-256 receipt flow (Agent(pr-author) is still not a registered agent type here). -3. **`git fetch origin main:main` is refused in a linked worktree.** `main` is checked out in the primary worktree (`C:/Users/DanMoisan/repos/TaskMaster`), so the fetch-into-checked-out-branch is refused. Achieve the same intent with `git fetch origin` (updates `origin/main`) then `git -C merge --ff-only origin/main`. +3. **`git fetch origin main:main` is refused in a linked worktree.** `main` is checked out in the primary worktree (``), so the fetch-into-checked-out-branch is refused. Achieve the same intent with `git fetch origin` (updates `origin/main`) then `git -C merge --ff-only origin/main`. diff --git a/.claude/agent-memory/orchestrator/feedback_plan_phase0_paths_are_stale_in_epic_children.md b/.claude/agent-memory/orchestrator/feedback_plan_phase0_paths_are_stale_in_epic_children.md index e048e9e57..0694c3b39 100644 --- a/.claude/agent-memory/orchestrator/feedback_plan_phase0_paths_are_stale_in_epic_children.md +++ b/.claude/agent-memory/orchestrator/feedback_plan_phase0_paths_are_stale_in_epic_children.md @@ -5,7 +5,7 @@ metadata: type: feedback --- -Epic-child atomic plans are authored during epic planning in a different (planning-time) git worktree. Their Phase 0 policy-read tasks (P0-T1..T4) hard-code that worktree's absolute paths, e.g. `C:\Users\DanMoisan\repos\TaskMaster-wt-2026-07-07-13-21\CLAUDE.md`, which do not exist when the feature is later executed in a fresh session worktree. +Epic-child atomic plans are authored during epic planning in a different (planning-time) git worktree. Their Phase 0 policy-read tasks (P0-T1..T4) hard-code that worktree's absolute paths, e.g. `-wt-2026-07-07-13-21\CLAUDE.md`, which do not exist when the feature is later executed in a fresh session worktree. **Why:** the plan is frozen at planning time; the execution worktree is created later with a different `agent-` path. An executor that reads the cited paths verbatim fails P0 and can wrongly report BLOCKED. diff --git a/.claude/agent-memory/orchestrator/project_epic_child_prs_no_ci.md b/.claude/agent-memory/orchestrator/project_epic_child_prs_no_ci.md index 0527e1d3d..d11685def 100644 --- a/.claude/agent-memory/orchestrator/project_epic_child_prs_no_ci.md +++ b/.claude/agent-memory/orchestrator/project_epic_child_prs_no_ci.md @@ -10,3 +10,25 @@ In this repo's epic model, child-feature PRs target the epic integration branch **Why:** CI is consolidated at the eventual integration->main PR (the epic-orchestrator's gate), avoiding N redundant CI runs across parallel child worktrees. Confirmed 2026-07-08 (#262 / PR #274 -> integration). **How to apply:** For an epic child at the S9 CI gate, do not block waiting for checks that will never appear. Treat "CI-green" as vacuously satisfied when (a) the base is the integration branch, (b) ci.yml does not trigger on it, and (c) the PR is MERGEABLE/CLEAN with blocking_count==0. Merge with `gh pr merge --merge` and record `epic_merge`. Any CI-relevant concern (e.g. the LiveOutlook `TestCategory` filter observation on ci.yml) is deferred to the integration->main gate, not this PR. `gh pr checks --watch` exits immediately (exit 0) when no checks are configured — do not misread that as green required checks. + +## Corollary: once the epic is finished, retarget `main` + +The zero-checks rule holds only while the integration branch is *live*. When the epic has already +completed and its integration branch has been merged, that branch is **spent**, and a leftover +child must not target it. + +Test it directly: `git merge-base --is-ancestor origin/ origin/main`. If the +integration branch is a strict ancestor of `main` (and `git log ..main` is non-empty +while `git log main..` is empty), it is fully merged. + +On #511 the integration branch was 7 commits behind `main` and already merged by PR #595. Targeting +it would have produced an 85-file diff carrying 7 unrelated `main` commits into a branch nothing +merges from, and **zero CI checks**. Retargeting `main` gave a 100-file additions-only diff and five +real required checks (actionlint, format-check, build-analyzers, build-nullable, mstest-coverage), +all of which passed. + +When you retarget: set `epic_mode: false` with the rationale recorded (there is no live integration +branch to merge into, so the epic-mode merge-on-green gate no longer applies), flip +`ci_gate.applicable` to `true`, and verify the diff is additions-only +(`git diff --name-status origin/main..HEAD` showing no `D` or `R` rows) before pushing — a branch +cut from an older base silently deletes what `main` gained meanwhile. diff --git a/.claude/agent-memory/orchestrator/webview2-endinit-creates-handles-at-construction.md b/.claude/agent-memory/orchestrator/webview2-endinit-creates-handles-at-construction.md new file mode 100644 index 000000000..f63358464 --- /dev/null +++ b/.claude/agent-memory/orchestrator/webview2-endinit-creates-handles-at-construction.md @@ -0,0 +1,37 @@ +--- +name: webview2-endinit-creates-handles-at-construction +description: ItemViewer construction already creates both WebView2 child handles AND the viewer's own handle via Designer ISupportInitialize.EndInit, so any "force the handle" remedy for QuickFiler pump tests is a measured no-op +metadata: + type: project +--- + +`QuickFiler.ItemViewer`'s constructor runs `InitializeComponent()`, and +`QuickFiler/Viewers/ItemViewer.Designer.cs` routes `_l0v2h2_WebView2` and `_l0vhBreadcrumb_WebView2` +through the `ISupportInitialize` `BeginInit`/`EndInit` protocol. `EndInit` on the third-party +`Microsoft.Web.WebView2.WinForms.WebView2` control **creates the child window handle**. WinForms +creates a parent's handle whenever a child's handle is created, so **the `ItemViewer`'s own handle +also exists the moment construction returns**. + +Measured four ways during issue #511/#571 execution (see +`docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md`): +a bare `new QuickFiler.ItemViewer()` on the pump thread — no harness, no `SaveParameters`, no +`.Handle` read — already reports **both** children as `IsHandleCreated == true`. + +**Why this matters:** it falsifies the whole premise of "the viewer can reach the act with no window +handle." Any remedy of the shape +`_ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false)` forces a handle that already +exists and changes nothing observable. It also explains why the two named pump tests passed on +20 of 20 pre-fix runs. + +**Do not confuse the two failure signatures.** A genuinely missing handle makes `Control.Invoke` +throw `InvalidOperationException` *immediately*. The failures actually observed in #511 are +**60,000 ms `PumpTimeoutMs` expiries under machine load** (reproduced with ~17 idle MSBuild +node-reuse processes present; clearing them restored green). A timeout is a different root cause +from an absent handle, and a handle-forcing change cannot address it. + +**How to apply:** before accepting any "force/establish the window handle" plan for the QuickFiler +pump fixtures, measure `IsHandleCreated` on a bare `ItemViewer` first. If it is already `true`, the +plan's premise is dead and the plan needs re-scoping, not execution. Also weigh post-fix green runs +against the pre-fix base rate: at roughly 1 failing run in 21, thirty consecutive green runs has +about a 23% chance of occurring with no fix at all, so it is not evidence of efficacy. +See [[project_winformspumphost_tests_load_flaky]]. diff --git a/.claude/agent-memory/parallel-planner/reference_drm_copilot_upstream.md b/.claude/agent-memory/parallel-planner/reference_drm_copilot_upstream.md index 886fb9e34..4d16ddd9d 100644 --- a/.claude/agent-memory/parallel-planner/reference_drm_copilot_upstream.md +++ b/.claude/agent-memory/parallel-planner/reference_drm_copilot_upstream.md @@ -1,11 +1,11 @@ --- name: drm-copilot-is-claude-governance-upstream -description: C:\Users\DanMoisan\repos\drm-copilot is the upstream source for TaskMaster's .claude governance surface (rules, skills, agents, hooks, orchestration libraries) and the MCP server +description: \repos\drm-copilot is the upstream source for TaskMaster's .claude governance surface (rules, skills, agents, hooks, orchestration libraries) and the MCP server metadata: type: reference --- -`C:\Users\DanMoisan\repos\drm-copilot` is the upstream repository for TaskMaster's `.claude` +`\repos\drm-copilot` is the upstream repository for TaskMaster's `.claude` governance surface and for the `drm-copilot` MCP server itself. Useful locations there when a TaskMaster governance file seems missing or stale: diff --git a/.claude/agent-memory/task-researcher/MEMORY.md b/.claude/agent-memory/task-researcher/MEMORY.md index 917ec4601..a1a904aa2 100644 --- a/.claude/agent-memory/task-researcher/MEMORY.md +++ b/.claude/agent-memory/task-researcher/MEMORY.md @@ -33,3 +33,6 @@ - [coverage-threshold-reconciliation-494](project_coverage_threshold_reconciliation_494.md) — #494: 85/75 is foreign-import leakage reintroduced after #178 rejected it; the only numeric coverage gate is evadable by withholding its input; repo-wide coverage has a +/-15pt run-to-run spread (2026-08-10) - [cobertura-root-attrs-raw-vs-postprocessed](project_cobertura_root_attrs_raw_vs_postprocessed.md) — #441/#478: raw dotnet-coverage root totals are class-level-only; the Koverage post-processor overwrites them with a doubled both-axes sum — never compare the two (2026-08-10) - [toolchain-gate-fidelity-512](project_toolchain_gate_fidelity_512.md) — #512/#492/#509/#522: AGENTS.md/.agents/.github-instructions are externally owned (generator absent); Invoke-VSBuild.ps1 is an unenumerated executable carrier; ~1.2s vs ~17s = vacuity tell (2026-08-10) + +## Artifact hygiene +- [Never embed absolute host paths](../_shared_no_absolute_host_paths.md) — no `C:\Users\\...`, bare account, or machine name in ANY artifact; use `` / `` / `` / ``. vstest names TRX `__.trx` by default, so control `/ResultsDirectory:` + `LogFileName=` or rename before citing. diff --git a/QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs b/QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs index de5f6ede6..1716d2d62 100644 --- a/QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs +++ b/QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs @@ -84,6 +84,15 @@ bool darkMode QuickFiler.ItemViewer viewer = await host.InvokeAsync(() => new QuickFiler.ItemViewer()) .ConfigureAwait(false); + // #571 (measured 2026-08-22): both WebView2 children — and therefore the parent + // ItemViewer — are already handle-created when construction returns, because + // InitializeComponent runs the Designer-emitted ISupportInitialize.EndInit() calls on + // both children and WinForms creates a parent's handle when a child's is created. This + // read is therefore redundant today; it is retained deliberately as a defensive + // measure so the fixture does not silently depend on a third-party side effect this + // repository neither controls nor observes. + _ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false); + Mock kbd; Mock explorer; CancellationTokenSource cts; diff --git a/QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs b/QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs index a8f291356..1ff9e2a6f 100644 --- a/QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs +++ b/QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs @@ -286,5 +286,113 @@ await act.Should() await host.StopAsync().ConfigureAwait(false); } } + + /// + /// #511/#571 regression probe: the shared pump harness must hand back an + /// ItemViewer whose window handle already exists, created on the pump thread. + /// Every pump-hosted test in this class marshals work through the viewer, and + /// Control.Invoke throws on a handle-less control, so a harness that returns a + /// viewer with no handle makes those tests fail. This probe reports the harness viewer's + /// handle state directly, so a run in which the end-to-end tests happen to pass still + /// records whether the handle was present. + /// + [TestMethod] + [Timeout(PumpTimeoutMs)] + public async Task BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread() + { + // Arrange + WinFormsPumpHost host = new WinFormsPumpHost(); + PumpHarness harness = null; + try + { + harness = await BuildPumpHarnessAsync(host, darkMode: false).ConfigureAwait(false); + + // Act — read the marshalling predicate on the pump thread that owns the viewer. + bool invokeRequiredOnPumpThread = await host.InvokeAsync(() => + harness.Viewer.InvokeRequired + ) + .ConfigureAwait(false); + + // Assert — the handle exists, so Control.Invoke cannot throw for want of one. + harness + .Viewer.IsHandleCreated.Should() + .BeTrue( + because: "the harness must create the viewer's window handle on the pump thread" + ); + invokeRequiredOnPumpThread + .Should() + .BeFalse( + because: "the pump thread owns the viewer's handle, so no marshalling is required there" + ); + } + finally + { + if (harness != null) + { + harness.Restore(); + } + + await host.StopAsync().ConfigureAwait(false); + } + } + + /// + /// #571 minimality pin: the harness must not itself create either + /// Microsoft.Web.WebView2.WinForms.WebView2 child's window handle. It forces only the + /// viewer's own handle, by reading .Handle, which is non-recursive. + /// + /// + /// Measured, not predicted. A bare new ItemViewer() constructed on the pump with no + /// harness, no SaveParameters, and no .Handle read already reports both + /// children as handle-created, so the handles originate in InitializeComponent's + /// third-party ISupportInitialize.EndInit() call, not in the harness. That is also + /// why the viewer's own handle was already present on every pre-fix run: WinForms creates a + /// parent's handle when a child's handle is created. This test therefore pins the state the + /// harness inherits rather than a state it produces, and it fails if a future change makes + /// the children handle-less at construction and so invalidates that assumption. + /// + [TestMethod] + [Timeout(PumpTimeoutMs)] + public async Task BuildPumpHarness_DoesNotCreateTheWebViewChildHandles() + { + // Arrange + WinFormsPumpHost host = new WinFormsPumpHost(); + PumpHarness harness = null; + try + { + harness = await BuildPumpHarnessAsync(host, darkMode: false).ConfigureAwait(false); + + // Act - read both child handle states on the pump thread that owns the viewer. + bool bodyWebViewHandleCreated = await host.InvokeAsync(() => + harness.Viewer.L0v2h2_WebView2.IsHandleCreated + ) + .ConfigureAwait(false); + bool breadcrumbWebViewHandleCreated = await host.InvokeAsync(() => + harness.Viewer.L0vhBreadcrumb_WebView2.IsHandleCreated + ) + .ConfigureAwait(false); + + // Assert - both children carry the handle state ItemViewer construction gave them. + bodyWebViewHandleCreated + .Should() + .BeTrue( + because: "ItemViewer construction creates the body WebView2 child's handle through ISupportInitialize.EndInit, so the harness inherits it rather than creating it" + ); + breadcrumbWebViewHandleCreated + .Should() + .BeTrue( + because: "ItemViewer construction creates the breadcrumb WebView2 child's handle through ISupportInitialize.EndInit, so the harness inherits it rather than creating it" + ); + } + finally + { + if (harness != null) + { + harness.Restore(); + } + + await host.StopAsync().ConfigureAwait(false); + } + } } } diff --git a/QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs b/QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs index 9a8623c5e..d769fa71a 100644 --- a/QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs +++ b/QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs @@ -433,6 +433,13 @@ public async Task ResolveControlGroupsAsync_ThroughThePumpHost_PopulatesTipsAndC new QuickFiler.ItemViewer() ) .ConfigureAwait(false); + // #571 (measured 2026-08-22): both WebView2 children, and therefore the parent + // ItemViewer, are already handle-created when construction returns, via the + // Designer-emitted ISupportInitialize.EndInit() calls. This read is redundant + // today and is retained deliberately as a defensive measure, so the fixture does + // not silently depend on a third-party side effect this repository does not + // control. + _ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false); HarnessController controller = new HarnessController(); QfcItemControllerTestSupport.SetField(controller, "_itemViewer", viewer); controller.Token = CancellationToken.None; diff --git a/docs/features/active/winformspumphost-suite-determinism-511/code-review.2026-08-24T00-01.md b/docs/features/active/winformspumphost-suite-determinism-511/code-review.2026-08-24T00-01.md new file mode 100644 index 000000000..3a94fc413 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/code-review.2026-08-24T00-01.md @@ -0,0 +1,77 @@ +# Code Review — winformspumphost-suite-determinism-511 + +- Timestamp: 2026-08-24T00-01 (UTC) +- Branch: `bug/winformspumphost-suite-determinism-511-exec` +- Base: `main` @ merge base `f85a36faebaaec29fe5233c9d9f69d223d80e4c5` +- Head: `b4d47adc369d021f6fb4eff092f419dc49e9a5e5` +- Scope: full branch diff (3 C# test files, 68 feature-folder docs/evidence files, 26 agent-memory files) + +## Executive Summary + +This is remediation cycle 1's re-review. The executable-code diff is small and test-only: two +corrected comment blocks (Part2.cs, ViewerSetupTests.cs) and two new regression tests (Part3.cs, ++108 lines). The code quality of the additions is good: both tests follow the established +pump-host pattern, use MSTest + FluentAssertions with explicit `because:` messages, carry XML doc +summaries that state the measured mechanism accurately, clean up in `finally`, and preserve the +`UiThreadDispatcherGate` serialization. The two corrected comment blocks now state the measured +truth and the deliberate redundancy of the retained `viewer.Handle` read, exactly as remediation +Finding D required. + +**Blockers: 0.** Five non-blocking findings are recorded: two Minor documentation-consistency +residuals in `spec.md` (a stale Root Cause Analysis narrative and AC wording that predates the +maintainer-instructed raw-TRX deletion) and three Informational observations. None requires a code +change before the pull request. + +## Findings Table + +| ID | Severity | File | Location | Finding | Recommendation | Rationale | Evidence | +| --- | --- | --- | --- | --- | --- | --- | --- | +| CR-1 | Minor | docs/features/active/winformspumphost-suite-determinism-511/spec.md | `## Root Cause Analysis`, "Confirmed root cause of #571" and "visible-window" subsections | The section still asserts pre-measurement claims — "`IsHandleCreated` is `false` for the whole test" and "The `ItemViewer`'s two WebView2 children never obtain a handle" — that the committed measurement (`evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md`) and the revised AC 6 / Scope sections contradict. The section's own "Unresolved question" hedge names the mechanism later confirmed (explanation 1, `ISupportInitialize.EndInit`), but the flat assertions carry no revision marker. | In a follow-up (or in the PR body), add a dated annotation to `## Root Cause Analysis` stating that the measurement confirmed explanation 1 and superseded the two static-reading assertions. Do not rewrite history; annotate it. | Remediation-inputs Part 6 deliberately scoped the spec revision to the AC and Scope sections, so this is outside the ratified cycle scope; but a future reader of the unannotated section could take the falsified static reading as current fact. | `spec.md` "Confirmed root cause" text vs. measured record; revised AC 6 in the same file | +| CR-2 | Minor | docs/features/active/winformspumphost-suite-determinism-511/spec.md | AC 1 and AC 3 wording | AC 1 promises "the ten TRX results stored under `evidence/regression-testing/`" and AC 3 "the evidence stored under `evidence/regression-testing/`", but the 56 raw TRX (and 42 `.coverage`) files were deleted at explicit maintainer instruction after the orchestrator verified the committed distillation reproduces them exactly. The literal storage claim is no longer true on disk. | Align the AC wording with the recorded disposition (cite `evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`), or state the supersession in the PR body. | The maintainer-instructed, committed disposition record governs; the distilled markdown is the evidence of record and was fidelity-checked against the raw TRX before deletion. The residual is a wording drift, not an evidence gap. | `raw-vstest-artifact-disposition.2026-08-23T21-40.md`; `find`/`git ls-files` confirm zero TRX under the evidence tree | +| CR-3 | Info | QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs | `:301-335` (`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`) | The test name ("Forces") and the first `because:` message ("the harness must create the viewer's window handle on the pump thread") frame the harness as the creator, while the measured mechanism is inheritance from `ItemViewer` construction. The asserted invariant (handle exists; no marshalling required on the pump thread) is accurate either way, and the sibling test's `` states the inheritance mechanism explicitly. | None required. The name is pinned verbatim by spec AC 5; renaming would break the AC. Optionally soften the `because:` message to "must hand back a handle-created viewer" in a future touch. | The contract asserted is the fixture invariant, not the mechanism; the companion test documents the mechanism. | Diff hunk at `Part3.cs:289-335`; AC 5 text in `spec.md` | +| CR-4 | Info | docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md | Phases 5-6 (29 unchecked tasks) | The original plan's Phase 5/6 checkboxes remain `[ ]`. That work was carried, adjusted, and completed by `remediation-plan.2026-08-23T20-57.md` (42/42 tasks checked), whose header records the supersession ("this plan carries the remaining work as adjusted by the remediation inputs"). | None required; recorded so a later reader does not misread the original plan as abandoned mid-phase. | The remediation plan is the authoritative record of the executed final QC loop and check-offs. | `remediation-plan.2026-08-23T20-57.md` header; 42/42 checked | +| CR-5 | Info | docs/features/active/winformspumphost-suite-determinism-511/spec.md | AC 10 (`SwapUiThreadDispatcher (:139)`) | The cited line number predates the 9-line insertion in Part2.cs; the helper's definition now sits at `:148` (first use at `:138`). The structural claim (acquire-and-release intact) holds. | Optionally refresh the line citation in a future spec touch. | Line-number drift only; the epic's "re-derive every line number" constraint anticipated exactly this class of drift. | `grep -n SwapUiThreadDispatcher Part2.cs` → 138/148/348; gate at `:51` unchanged | + +## Detailed Review — Changed Code + +### QfcItemController.InitializationTests.Part3.cs (+108) + +- `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` (`:301`): Arrange builds the shared + harness; Act reads `Viewer.InvokeRequired` on the pump thread through `host.InvokeAsync`; Assert + checks `IsHandleCreated == true` and `invokeRequiredOnPumpThread == false`. Cleanup restores the + swapped dispatcher and stops the host in `finally`. Correct use of `ConfigureAwait(false)` + throughout, consistent with the file's existing style. +- `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` (`:356`): reads both WebView2 children's + `IsHandleCreated` on the pump thread and asserts both true, with a `` block that states + the measured provenance ("Measured, not predicted") and the exact falsification logic. This is + the strongest artifact in the diff: it converts the falsified premise into a pinned, loudly + failing invariant if a future WebView2 or Designer change alters handle-creation behavior. +- Both tests reuse `BuildPumpHarnessAsync`, so the `UiThreadDispatcherGate` acquire/release and + dispatcher swap/restore semantics are inherited from the existing, proven fixture. No new + synchronization primitives, no timing constructs. + +### QfcItemController.InitializationTests.Part2.cs (+9) and QfcItemController.ViewerSetupTests.cs (+7) + +- Comment-only rewrites above the retained `_ = await host.InvokeAsync(() => viewer.Handle)` + statements. Both now state: (a) the measured truth (children and parent are handle-created at + construction via Designer-emitted `ISupportInitialize.EndInit()`); (b) that the read is + therefore redundant today; and (c) that it is retained deliberately as a defensive measure + against an uncontrolled third-party side effect. This satisfies remediation Finding D's full + requirement, including the mandatory redundancy statement, and is consistent with the corrected + assertions in Part3.cs. The discard (`_ =`) form is appropriate for a side-effect-motivated read. + +### Documentation and evidence tree + +- The spec's AC and Scope sections are internally consistent with the measured record and with the + code (CR-1 is the one remaining stale narrative, in a section outside the ratified revision + scope). +- Evidence artifacts are consistently structured (`Timestamp:` / `Command:` / `EXIT_CODE:` / + `Output Summary:`), use portable path placeholders, and contain no host identifiers in added + lines. +- Commit messages in range are truthful about non-repair ("NOT a fix") and carry no closing + keywords for #511/#571. + +## Verdict + +Approve. Zero blocking findings; CR-1 and CR-2 are documentation follow-ups that do not gate the +pull request. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/decision-record.2026-08-23T20-40.md b/docs/features/active/winformspumphost-suite-determinism-511/decision-record.2026-08-23T20-40.md new file mode 100644 index 000000000..076e2fa7c --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/decision-record.2026-08-23T20-40.md @@ -0,0 +1,78 @@ +# Decision Record — re-scope #511 after its premise was falsified + +Recorded: 2026-08-23T20:40 UTC +Decided by: maintainer, interactive `/orchestrate` session +Canonical issue number: 511 (secondary: 571) + +The orchestrator checkpoint at `artifacts/orchestration/orchestrator-state.json` is gitignored +(`.gitignore:57`), so this file is the committed record of the decision it holds. + +## Why the child halted + +Execution of Phases 0 through 4 completed, every delegation returned, and every validator +passed — but measurement falsified the plan's central premise. Six findings were recorded; three +were independently re-verified against the working tree and the evidence tree on 2026-08-23. + +| ID | Severity | Finding | +| --- | --- | --- | +| A | blocking | The remedy is a measured no-op. The inserted `_ = await host.InvokeAsync(() => viewer.Handle)` forces a window handle that already exists. | +| B | blocking | The only genuine pre-fix failure observed was a 60,000 ms `PumpTimeoutMs` expiry under machine load — a different root cause, which the remedy does not address. | +| C | blocking | The 30-of-30 post-fix green record is statistically consistent with the remedy having no effect (about a 1-in-4 chance of arising with no fix at all). | +| D | blocking | Two inserted comments assert the opposite of what was measured, and contradict a corrected assertion in the same commit. | +| E | blocking | Spec acceptance criterion 6 is unsatisfiable as worded. | +| F | resolvable | P4-T2's absolute-zero gate spans all nine assemblies, so it trips on pre-existing flakes this diff cannot reach. | + +Provenance for A: `evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md` +records four configurations. Run 2 (Phase 2 statement commented out) is identical to run 1 on the +measured value, and run 4 shows a bare `new ItemViewer()` on the pump thread — no harness, no +`SaveParameters`, no `.Handle` read — already reporting both WebView2 children handle-created. The +handles originate in `InitializeComponent`'s third-party `ISupportInitialize.EndInit()` calls; +WinForms creates a parent's handle when a child's is created, which is why the viewer already had +one on every pre-fix run. + +## Decision + +**Re-scope #511.** Keep the fixture hardening and the mechanism finding as durable value. + +1. Correct the four false comments so they state the measured truth + (`QfcItemController.InitializationTests.Part2.cs` lines 87-90; + `QfcItemController.ViewerSetupTests.cs` lines 436-438). CLAUDE.md C#6.3 requires comments to + stay synchronized with behavior. +2. Revise spec acceptance criterion 6 to assert the measured inherited state, and reconcile the + three other unchecked criteria against the re-scoped claim. +3. Narrow P4-T2's zero condition to the classes this child owns, per the ratified precedent for an + absolute-zero gate over a sibling-owned assembly. +4. File follow-up issues for the load-induced pump-timeout cascade and the three sibling-assembly + flakes. +5. **Open a pull request that does NOT claim to close #511.** Findings A, B and C are accepted as + accurate and are addressed by re-scoping the claim, not by changing code. + +Rejected alternatives: re-planning against the measured root cause (the epic's hard constraints — +no production edits, no timeout changes, no sleeps or retries, no injectable +synchronization-context seam — may leave no in-scope remedy); and abandoning the child, which +would discard the fixture hardening and the mechanism finding. + +## Host-identifier sanitization + +Performed the same session at maintainer instruction, on the standing rule that **no file may ever +embed an absolute host path or host identifier**: + +- 140 untracked evidence paths renamed to strip the `vstest.console.exe` default + `__` filename prefix. +- 10 tracked markdown evidence files stripped of that prefix; the references point at the renamed + files, so accuracy is preserved. +- 91 absolute-path occurrences across 27 tracked files replaced with the portable placeholders + ``, ``, `` and ``, applied longest-first. +- Convention recorded at `.claude/agent-memory/_shared_no_absolute_host_paths.md` and indexed from + five agent memory indexes, including the vstest default-naming trap that caused it. + +Not done, deliberately: roughly 146 tracked files in other and archived feature folders still carry +the prefix, and about 157 still carry the bare host name, including `.claude/settings.json` and +`.vscode/settings.json`. Sanitizing them here would break this child's scope-lock acceptance +criterion, so the remainder is tracked as its own issue. + +## Resume point + +`next_step: S6_remediation_R1_planning`. Resolved delegation models for band C3 under +`fable_policy: preferred` — atomic-planner `fable`, atomic-executor `opus`, feature-review `fable`, +pr-author `opus`. The ordered next actions are in the checkpoint's `resume_instructions`. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/.gitignore b/docs/features/active/winformspumphost-suite-determinism-511/evidence/.gitignore new file mode 100644 index 000000000..2ef9974f9 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/.gitignore @@ -0,0 +1,20 @@ +# Raw vstest.console.exe output is never committed under this evidence tree. +# +# The evidence of record is the distilled per-run markdown alongside these paths. The raw +# artifacts are large (a single ten-run pass produced roughly 1.2 GB) and the repository's +# standing policy is against committing raw machine test and coverage output. Repository-root +# .gitignore already excludes *.coverage; *.trx was not excluded, so a `git add -A` in this +# worktree would otherwise stage hundreds of megabytes of TRX. +# +# See other/raw-vstest-artifact-disposition.2026-08-23T21-40.md for the recorded disposition. + +*.trx +*.coverage +*.coveragexml + +# vstest per-run scratch directories. The date-stamped form is the default results layout; +# the Deploy_* form is the deployment scratch directory, whose default name embeds the +# account and host and is therefore also a host-identifier leak. +Deploy_*/ +20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_*/ +r1-p*-t*/ diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-gate.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-gate.2026-08-21T18-10.md new file mode 100644 index 000000000..e459a70d7 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-gate.2026-08-21T18-10.md @@ -0,0 +1,76 @@ +# Baseline — Analyzer Gate + +Timestamp: 2026-08-22T09-24 + +Command: + +``` +pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true' +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. `msbuild` was +invoked through its absolute resolved path +`C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe` +(resolved with `vswhere -latest -products * -find 'MSBuild\**\Bin\MSBuild.exe'`), and the full build +log was captured to `coverage\analyzer-baseline.log` (4,724 lines). The invocation went through +`pwsh -NoProfile` rather than the Bash tool because the Bash tool mangles MSBuild switches (`/m` +becomes `M:/`, producing MSB1008). + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | +| --- | --- | +| Exit code | **0** | +| Warning count | **5** | +| Error count | **0** | +| Log lines matching `Skipping target "CoreCompile"` | **0** | +| Log lines matching `CoreCompile:` (target actually executed) | 34 | +| `Done Building Project` lines | 20 | +| Occurrences of `CS0006` | **0** | +| Log file | `coverage\analyzer-baseline.log` (4,724 lines) | +| Wall time | 00:00:21.11 | + +## Acceptance conditions + +1. **`EXIT_CODE: 0`** — met. +2. **`Skipping target "CoreCompile"` count is exactly 0** — met. This is the load-bearing proof that + the analyzers actually ran rather than being skipped by MSBuild incrementality. It is corroborated + positively by 34 `CoreCompile:` target executions in the same log; the plan's guidance not to + assert a `csc.exe` count was followed, because that count is zero even on a real compile and would + gate nothing. + +## Warning inventory + +The plan makes no prediction about the warning count, so the observed count is recorded as-is. + +All **5** warnings are the same pre-existing diagnostic, emitted once per affected project by +`packages\System.Reactive.7.0.0\build\System.Reactive.PackagesConfigCheck.targets(31,5)`: + +> warning : The project contains a packages.config file, which is not supported by System.Reactive +> v7.0 or later. Please migrate to PackageReference. (You can suppress this message by setting the +> RxUseUnsupportedPackagesConfig property to true, but be aware this is an unsupported scenario.) + +The five emitting projects are: + +- `QuickFiler.csproj` +- `TaskMaster.csproj` +- `ToDoModel.csproj` +- `UtilitiesCS.csproj` +- `UtilitiesCS.Test.csproj` + +Filtering the log for any warning line **not** originating from System.Reactive returned zero +results, so there are no analyzer-rule warnings at baseline. This is a **pre-existing condition** +attributable to the System.Reactive 7.0 packages.config incompatibility, entirely unrelated to this +child, and it is recorded rather than repaired here. It does not break the gate because these are +warnings and this command does not pass `/p:TreatWarningsAsErrors=true`. + +## Analyzer version skew — back-fill confirmed effective + +The `CS0006` occurrence count in the log is **0**. Before the P0-T10 back-fill, the five skewed +`` paths naming `Meziantou.Analyzer.3.0.156` and `Roslynator.Analyzers.4.16.0` did +not resolve, and csc would have reported `error CS0006` with a non-zero exit in all 16 first-party +projects. The zero `CS0006` count together with `0 Error(s)` and `EXIT_CODE: 0` confirms the +back-fill took effect. No return to P0-T10 was required, and **no project file was edited**. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-package-backfill.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-package-backfill.2026-08-21T18-10.md new file mode 100644 index 000000000..c893f2b18 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-package-backfill.2026-08-21T18-10.md @@ -0,0 +1,110 @@ +# Baseline — Analyzer Package Back-Fill + +Timestamp: 2026-08-22T09-20 + +Command: + +``` +# 1. Skew confirmation (run from the worktree root) +sed -n '470,482p' QuickFiler.Test/QuickFiler.Test.csproj +ls -d packages/Meziantou.Analyzer.* packages/Roslynator.Analyzers.* +grep -rl "Meziantou.Analyzer.3.0.156" --include=*.csproj . | wc -l + +# 2. Back-fill +pwsh -NoProfile -Command 'nuget install Meziantou.Analyzer -Version 3.0.156 -OutputDirectory packages' +pwsh -NoProfile -Command 'nuget install Roslynator.Analyzers -Version 4.16.0 -OutputDirectory packages' + +# 3. Post-state confirmation (run from the worktree root) +ls -l packages/Meziantou.Analyzer.3.0.156/analyzers/dotnet/roslyn5.0/cs/Meziantou.Analyzer.dll +ls -l packages/Roslynator.Analyzers.4.16.0/analyzers/dotnet/roslyn4.7/cs/Roslynator.CSharp.Analyzers.dll +ls packages/Roslynator.Analyzers.4.16.0/analyzers/dotnet/roslyn4.7/cs/ +git status --porcelain +``` + +EXIT_CODE: 0 + +Both `nuget install` invocations reported `NUGET_EXIT=0`. + +Output Summary: + +## Skew confirmed empirically before the back-fill + +The condition the plan predicts was measured, not assumed: + +- **16 of 16** first-party `.csproj` files carry an unconditional `` naming + `Meziantou.Analyzer.3.0.156` (`grep -rl ... --include=*.csproj | wc -l` → `16`). +- The P0-T9 `nuget restore` installed only the newer pins: + `ls -d packages/Meziantou.Analyzer.* packages/Roslynator.Analyzers.*` → + `packages/Meziantou.Analyzer.3.0.174/` and `packages/Roslynator.Analyzers.4.16.1/`. +- The representative `` block at `QuickFiler.Test/QuickFiler.Test.csproj` reads + (line numbers re-derived in this worktree; the block spans lines 472 through 481, with the five + skewed entries at lines 474 through 478): + + ``` + + + + + + + + ``` + + The five skewed paths name `3.0.156` (one entry) and `4.16.0` (four entries). Before the back-fill + none of the five resolved, so every msbuild task in this plan would have reported `error CS0006` + and a non-zero exit before producing any diagnostic. + +## Resulting folder names + +``` +packages/Meziantou.Analyzer.3.0.156/ +packages/Roslynator.Analyzers.4.16.0/ +``` + +These sit **beside** the restore-installed `packages/Meziantou.Analyzer.3.0.174/` and +`packages/Roslynator.Analyzers.4.16.1/` folders. The accumulation is exactly the state the plan's +Binding Constraints note describes on CI and in the main checkout. + +## Post-state — acceptance conditions + +1. **Both commands record `EXIT_CODE: 0`.** Confirmed; each printed + `Successfully installed ' ' to ...packages` and `NUGET_EXIT=0`. +2. **Both named DLL files exist:** + + ``` + -rwxr-xr-x 1 197121 2749952 Aug 14 20:39 packages/Meziantou.Analyzer.3.0.156/analyzers/dotnet/roslyn5.0/cs/Meziantou.Analyzer.dll + -rwxr-xr-x 1 197121 382464 Aug 8 12:24 packages/Roslynator.Analyzers.4.16.0/analyzers/dotnet/roslyn4.7/cs/Roslynator.CSharp.Analyzers.dll + ``` + + The remaining three Roslynator `4.16.0` DLLs the project files name are also present, so all five + skewed `` paths now resolve: + + ``` + Roslynator.CSharp.Analyzers.CodeFixes.dll + Roslynator.CSharp.Analyzers.dll + Roslynator_Analyzers_Roslynator.Common.dll + Roslynator_Analyzers_Roslynator.Core.dll + Roslynator_Analyzers_Roslynator.CSharp.dll + Roslynator_Analyzers_Roslynator.CSharp.Workspaces.dll + Roslynator_Analyzers_Roslynator.Workspaces.Common.dll + Roslynator_Analyzers_Roslynator.Workspaces.Core.dll + ``` + +3. **`git status --porcelain` reports zero entries whose path begins with the packages directory + name.** Full output, unchanged from before the back-fill: + + ``` + M docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md + ?? docs/features/active/winformspumphost-suite-determinism-511/evidence/ + ``` + + `.gitignore:191` (`**/[Pp]ackages/*`) ignores the tree. + +## Scope preservation + +This back-fill installs into the untracked `packages` tree and edits **no tracked file**. No +`.csproj` and no `packages.config` was modified. Binding Constraint 1 (no +`QuickFiler.Test/QuickFiler.Test.csproj` edit) and the P6-T11 scope lock (zero paths ending `.csproj` +in the diff) are both preserved. The underlying repository-wide skew — realigning the `` paths with `packages.config` across all 16 projects — remains out of scope for this child +and is the subject of the follow-up issue that P6-T20 files. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md new file mode 100644 index 000000000..e2ecc2492 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md @@ -0,0 +1,146 @@ +# Baseline — Numeric Coverage + +Timestamp: 2026-08-22T09-47 + +Command: + +``` +pwsh -NoProfile -File .\scripts\vscode\Invoke-MSTestWithCoverage.ps1 -SearchRoot . -CoverageOutput coverage\baseline.cobertura.xml +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. The script wraps the +same nine assemblies with `dotnet-coverage` and emits Cobertura XML; `vstest.console.exe +/EnableCodeCoverage` alone emits a binary `.coverage` file, not a percentage, which is why this +script is the source of numeric coverage in this plan. + +EXIT_CODE: 0 + +Output Summary: + +``` +Discovered 9 test assemblies. +Test Run Successful. +Total tests: 6437 + Passed: 6437 +Code coverage results: ...\coverage\baseline.cobertura.xml. +Done. Coverage artifact: ...\coverage\baseline.cobertura.xml +``` + +### The four required figures, as numeric percentages to two decimal places + +| Figure | Cobertura attribute | Raw | Percent | +| --- | --- | --- | --- | +| Repository headline line rate | root `line-rate` | `0.855531` | **85.55%** | +| Repository headline branch rate | root `branch-rate` | `0.790312` | **79.03%** | +| `QuickFiler` package line rate | `QuickFiler` package `line-rate` | `0.8092566619915849` | **80.93%** | +| Changed-module rate (`QuickFiler\Controllers\QfcItemController*` classes, aggregated) | per-`` count across the 10 matched classes | 1410 / 1633 | **86.34%** | + +Supporting root counters: `lines-covered="53386"`, `lines-valid="62401"`, +`branches-covered="12547"`, `branches-valid="15876"`. The `QuickFiler` package branch rate is +`0.7491152182461659` (**74.91%**). + +No coverage field above is empty and none carries the token `UNVERIFIED`. + +### All nine packages + +| Package | line-rate | Percent | +| --- | --- | --- | +| QuickFiler | 0.8092566619915849 | 80.93% | +| UtilitiesCS | 0.8955850144092219 | 89.56% | +| TaskVisualization | 0.8984326018808777 | 89.84% | +| SVGControl | 0.47303128371089537 | 47.30% | +| ToDoModel | 0.5731056563500534 | 57.31% | +| Tags | 0.9268929503916449 | 92.69% | +| TaskMaster | 0.7335945151811949 | 73.36% | +| TaskTree | 0.9548387096774194 | 95.48% | +| VBFunctions | 1 | 100.00% | + +### Per-class figures for the changed module + +Ten Cobertura classes have a `filename` beginning `QuickFiler\Controllers\QfcItemController` +(`MATCH_COUNT=10`). Filenames use backslashes because the script's Koverage post-processing rewrites +them; a forward-slash query matches nothing. + +| Filename | line-rate | Percent | branch-rate | +| --- | --- | --- | --- | +| `QuickFiler\Controllers\QfcItemController.cs` | 1 | 100.00% | 0.7857142857142857 | +| `QuickFiler\Controllers\QfcItemController.Initialization.cs` | 0.949612 | 94.96% | 0.90625 | +| `QuickFiler\Controllers\QfcItemController.ViewerSetup.cs` | 0.850829 | 85.08% | 0.677419 | +| `QuickFiler\Controllers\QfcItemController.Conversation.cs` | 0.882353 | 88.24% | 0.944444 | +| `QuickFiler\Controllers\QfcItemController.FolderHandling.cs` | 0.952381 | 95.24% | 0.7 | +| `QuickFiler\Controllers\QfcItemController.EventWiring.cs` | 0.815182 | 81.52% | 0.65 | +| `QuickFiler\Controllers\QfcItemController.EventHandlers.cs` | 0.7865168539325843 | 78.65% | 0.6111111111111112 | +| `QuickFiler\Controllers\QfcItemController.Navigation.cs` | 0.90678 | 90.68% | 0.818182 | +| `QuickFiler\Controllers\QfcItemController.FocusAndTheme.cs` | 0.793249 | 79.32% | 0.691176 | +| `QuickFiler\Controllers\QfcItemController.MailActions.cs` | 0.768 | 76.80% | 0.727273 | + +### Counting method (must be reproduced exactly at post-change comparison) + +The aggregate changed-module figure was computed by counting `` elements inside each matched +``, deduplicated by line `number` **within** each class, and summing across the ten classes: +1,633 total lines, 1,410 covered, **86.34%**. Cobertura repeats line entries under `` as well +as under the class-level `` element, so an all-descendant count without deduplication roughly +doubles the denominator and would fabricate a coverage delta. Any post-change comparison must use +this same per-class-deduplicated method against a **post-processed** XML produced by the same script. + +## Acceptance conditions + +1. **Artifact exists with all four fields** — met. +2. **The script reported exactly 9 discovered test assemblies** — met; the log line reads + `Discovered 9 test assemblies.` This was independently corroborated before the run by replaying the + script's own discovery filter (`*.Test.dll` under `\bin\Debug\`, excluding `\obj\` and `\ref\`), + which returned exactly the nine canonical assemblies and nothing else. +3. **No coverage field contains `UNVERIFIED` or an empty value** — met. + +Note on the `\.claude\` exclusion hazard: the script's filter (lines 296 through 302) does not exclude +`\.claude\`. All nine discovered paths do contain `\.claude\`, because this worktree itself lives +under `.claude\worktrees\`. That is expected and harmless: there is no nested `.claude/worktrees/` +inside this worktree (`ls -d .claude/worktrees` → no such file or directory), so no foreign or stale +agent-worktree assembly can be picked up. The count is exactly 9 and every path is one of the nine +canonical assemblies. + +## Two earlier invocations, recorded for completeness and as pre-fix data + +This figure came from the **third** invocation of the coverage script. The first two are recorded +rather than discarded, because the second carries directly relevant pre-fix evidence. + +**Invocation 1 — discarded, wrong output path.** The `-CoverageOutput coverage\baseline.cobertura.xml` +argument was passed through the Bash tool, which consumed the backslash and produced +`coveragebaseline.cobertura.xml` at the worktree root instead of `coverage\baseline.cobertura.xml`. +The run itself was clean (`Test Run Successful. Total tests: 6437, Passed: 6437`). The misplaced file +was deleted and the invocation was repeated through a `pwsh` script file so no shell escaping applies. +`git status --porcelain` was re-checked afterwards and showed no stray entry. + +**Invocation 2 — failed, and it is pre-fix evidence.** With the corrected path, the run reported +`Total tests: 6437, Passed: 6430, Failed: 7, Test Run Failed.` All seven failures were 60,000 ms +timeouts (`PumpTimeoutMs`), and all seven are WinFormsPumpHost-driven tests in the class this child +concerns: + +``` +Failed InitializeSequentialAsync_ThroughThePumpHost_CompletesAndInitializesState [1 m] +Failed CreateSequentialAsync_WithInjectedSeams_ReturnsAnInitializedController [1 m 1 s] +Failed InitializeGraphicsAsync_ThroughThePumpHost_CompletesAndAppliesDarkTheme [1 m] +Failed CreateAsync_WithFaultingWebViewSeam_FaultsWithThatExceptionAfterInitializing [1 m] +Failed InitializeBool_ThroughThePumpHost_CompletesAndInitializesState [1 m] +Failed InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates [1 m] +Failed InitializeAsync_ThroughThePumpHost_RunsToTheMockedWebViewSeamAndFaults [1 m] +``` + +**Both tests named by #511 and #571 are in that list.** The script threw at +`Invoke-MSTestWithCoverage.ps1:236` immediately after `dotnet-coverage` returned non-zero, which is +before the Koverage post-processing step, so that run's 17.6 MB XML was raw (forward-slash filenames, +unmerged `` nodes) and not comparable to a post-processed measurement. It was therefore +overwritten rather than read. + +The only environmental difference between invocation 2 and invocation 3 was machine load: 17 idle +MSBuild node-reuse processes left over from the P0-T13 and P0-T14 `/m` builds were still resident +during invocation 2 and were stopped before invocation 3. No stray `testhost`, `vstest.console`, or +`dotnet-coverage` process from any other agent was present at any point, so the failures were not +caused by a competing test runner. + +**Disposition:** invocation 2 is treated as data about the race window, not as a reason to change the +remedy, exactly as the plan's Phase 1 instruction directs. It is carried forward into the P1-T6 +intermittency analysis. It is **not** a pre-existing baseline failure in the sense of P0-T15: the +P0-T15 plain-`vstest` baseline recorded 6437/6437 with zero failures, and invocation 3 of this script +also recorded 6437/6437. The seven failures appear only intermittently and only under added load. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/csharpier-check.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/csharpier-check.2026-08-21T18-10.md new file mode 100644 index 000000000..485a60f03 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/csharpier-check.2026-08-21T18-10.md @@ -0,0 +1,36 @@ +# Baseline — CSharpier Check (read-only) + +Timestamp: 2026-08-22T09-22 + +Command: + +``` +dotnet tool run csharpier check . +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. Read-only: the +`check` subcommand reports formatting divergence and writes no file. + +EXIT_CODE: 0 + +Output Summary: + +Full command output, verbatim: + +``` +Checked 1517 files in 5398ms. +``` + +- **Files reported as unformatted: 0.** +- Files checked: 1,517. +- Exit code recorded verbatim: **0**. + +CSharpier emits one line per unformatted file when divergence exists; the output carries no such +line, so the count is zero. The baseline formatting state is clean and there is **no pre-existing +formatting condition** to record or defer. The task's provision for recording a non-zero baseline +exit code as a pre-existing condition rather than repairing it here did not need to be exercised. + +Version provenance: the invocation went through `dotnet tool run`, so it used the manifest-pinned +CSharpier `1.2.6` restored by P0-T11 (`dotnet-tools.json` sets `"rollForward": false`). This is the +same version `.github/workflows/ci.yml` runs, so this baseline agrees with CI. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/dotnet-sdk-bootstrap.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/dotnet-sdk-bootstrap.2026-08-21T18-10.md new file mode 100644 index 000000000..8a3a2b818 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/dotnet-sdk-bootstrap.2026-08-21T18-10.md @@ -0,0 +1,89 @@ +# Baseline — Worktree-Local .NET SDK Bootstrap + +Timestamp: 2026-08-22T09-16 + +Command: + +``` +# 1. Pre-state confirmation (run from the worktree root) +ls -d .dotnet-sdk +cat global.json +dotnet --version + +# 2. Provisioning (mirror method, authorized by the task text) +pwsh -NoProfile -Command "robocopy '\.dotnet-sdk' '\.claude\worktrees\agent-ad37a256a0fb60243\.dotnet-sdk' /E /MT:16 /NFL /NDL /NJH /NP" + +# 3. Post-state confirmation (run from the worktree root) +dotnet --version +dotnet --list-sdks +git status --porcelain +``` + +EXIT_CODE: 0 + +The `robocopy` invocation itself reported exit code `1`, which is a **success** code in robocopy's +exit-code scheme ("one or more files were copied successfully"). Robocopy reserves exit codes `>= 8` +for failures. Copy statistics: 880 of 880 directories copied, 5,266 of 5,266 files copied, 733.22 MB +transferred, 0 mismatched, 0 FAILED, 0 extras. The provisioning step therefore succeeded and the +recorded `EXIT_CODE: 0` reflects the task outcome. + +Output Summary: + +## Pre-state (confirmed first, as the task requires) + +- `ls -d .dotnet-sdk` → `ls: cannot access '.dotnet-sdk': No such file or directory`. The directory + did **not** exist in this worktree. +- `global.json` pins `sdk.version` to `8.0.205` with `"rollForward": "latestFeature"`, + `"allowPrerelease": false`, and a `paths` list of `[".dotnet-sdk", "$host$"]` — `.dotnet-sdk` ahead + of the host fallback. +- `dotnet --version` run from the worktree root printed the `global.json` `errorMessage` instead of a + version: + + ``` + The command could not be loaded, possibly because: + * You intended to execute a .NET application: + The application '--version' does not exist or is not a managed .dll or .exe. + * You intended to execute a .NET SDK command: + The repo-local .NET SDK is missing. Run ./scripts/vscode/Install-RepoDotNetSdk.ps1 from the repository root, then retry dotnet format TaskMaster.sln. + ``` + + Every `dotnet` and CSharpier task in this plan was therefore unrunnable before this task. + +## Provisioning method used + +**Mirror**, not the install script. The task authorizes either +`pwsh -NoProfile -File .\scripts\vscode\Install-RepoDotNetSdk.ps1` or mirroring the already-populated +`.dotnet-sdk` tree from the main checkout at ``. The mirror was +chosen because the source tree was already present and complete (747 MB, containing +`.dotnet-sdk\sdk\8.0.205\`), so the mirror avoids a network download and produces a byte-identical +tree. `robocopy /E /MT:16` was used to perform the recursive copy. + +## Post-state + +- `dotnet --version` run from the worktree root → **`8.0.205`**. Acceptance condition met. +- `dotnet --list-sdks` run from the worktree root: + + ``` + 8.0.205 [\.claude\worktrees\agent-ad37a256a0fb60243\.dotnet-sdk\sdk] + 10.0.302 [C:\Program Files\dotnet\sdk] + ``` + + An entry whose path ends `.dotnet-sdk\sdk` is present, and it is the worktree-local one. Acceptance + condition met. The host fallback offers only `10.0.302`, which cannot satisfy the `8.0.205` pin + under `latestFeature`, confirming the pre-state diagnosis. +- `git status --porcelain` reports **no entry** for `.dotnet-sdk`. `.gitignore:350` carries the + pattern `.dotnet*/`, which ignores the tree. The full porcelain output is the two lines produced by + this Phase 0 execution itself: + + ``` + M docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md + ?? docs/features/active/winformspumphost-suite-determinism-511/evidence/ + ``` + + Acceptance condition met: provisioning the SDK did not dirty the tree. + +## CI scope note + +CI is unaffected by this condition. The `windows-latest` image preinstalls an 8.0.x SDK that +satisfies the `$host$` fallback under `rollForward: latestFeature`. This was a worktree-provisioning +gap only, not a repository defect. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/file-size-budget.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/file-size-budget.2026-08-21T18-10.md new file mode 100644 index 000000000..151d3031e --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/file-size-budget.2026-08-21T18-10.md @@ -0,0 +1,32 @@ +# Baseline — File-Size Budget of the Three Touched Files + +Timestamp: 2026-08-22T09-15 + +Command: + +``` +pwsh -NoProfile -Command "@('QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs','QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs','QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs') | ForEach-Object { $c = @(Get-Content -LiteralPath $_); Write-Output ('{0} = {1}' -f $_, $c.Count) }" +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. `Get-Content +-LiteralPath` was invoked once per file and the returned lines were counted, as the task specifies. + +EXIT_CODE: 0 + +Output Summary: + +| File | Pre-change line count | Plan-expected | Match | Headroom to 500 | +| --- | --- | --- | --- | --- | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` | 409 | 409 | yes | 91 | +| `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | 467 | 467 | yes | 33 | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` | 290 | 290 | yes | 210 | + +All three recorded counts equal the values the task's acceptance condition names (409, 467, 290). +**No drift.** No count required verbatim recording as a deviation. + +Two files named in Binding Constraint 5 as off-limits for additions were not measured here because +the task does not ask for them, and neither is touched by this child: +`QuickFiler.Test/Controllers/WinFormsPumpHostTests.cs` (443 per the plan) and +`QuickFiler.Test/Controllers/QfcItemController.FocusAndThemeTests.cs` (497 per the plan, three lines +of headroom). diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/git-identity.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/git-identity.2026-08-21T18-10.md new file mode 100644 index 000000000..509eb7a40 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/git-identity.2026-08-21T18-10.md @@ -0,0 +1,57 @@ +# Baseline — Git Identity + +Timestamp: 2026-08-22T09-14 + +Command: + +``` +git rev-parse --abbrev-ref HEAD +git rev-parse HEAD +git merge-base origin/epic/quickfiler-suite-determinism-foundation-integration HEAD +git status --porcelain +``` + +All four commands were run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. + +EXIT_CODE: 0 + +Output Summary: + +- **Branch:** `bug/winformspumphost-suite-determinism-511-exec` +- **HEAD sha:** `c551eabab0aa0a6b1a284252811a2e1de819634e` +- **Merge-base sha:** `c551eabab0aa0a6b1a284252811a2e1de819634e` (40 hex characters) +- **Merge-base command used:** `git merge-base origin/epic/quickfiler-suite-determinism-foundation-integration HEAD`. The + primary command succeeded, so the `origin/main` fallback the task authorizes was **not** used. +- **`git status --porcelain` line count:** 2 + +The two porcelain lines are both products of this Phase 0 execution and neither is a pre-existing +dirty-tree condition: + +``` + M docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md +?? docs/features/active/winformspumphost-suite-determinism-511/evidence/ +``` + +The modified plan file carries the P0-T1 through P0-T5 check-offs written in this execution. The +untracked `evidence/` directory holds the Phase 0 artifacts. The worktree was clean before Phase 0 +began. + +## Branch-name correction recorded + +The plan header and tasks P6-T18 and P6-T21 name the branch +`bug/winformspumphost-suite-determinism-511`. That name is checked out in a separate, framework-locked +leftover worktree and is unusable. The live branch for this execution is +`bug/winformspumphost-suite-determinism-511-exec`, which is checked out here and tracks +`origin/epic/quickfiler-suite-determinism-foundation-integration`. Every task in this plan that names +the branch is satisfied against the `-exec` name. + +## Observation recorded for later phases (not a Phase 0 finding) + +The merge-base sha and the HEAD sha are **identical**. Any later acceptance condition of the form +`git diff ..HEAD` is therefore vacuous — it returns an empty diff — until a commit is +made on this branch. This is recorded as provenance for the phases that carry those conditions; it +is not acted on here, because Phase 0 and Phase 1 make no commit and no scope-lock assertion. + +Per the task text, the HEAD sha is recorded as provenance only. No later task in this plan gates on a +pinned sha; the scope-lock tasks gate on tree invariants measured against the recorded merge base. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/no-python-toolchain.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/no-python-toolchain.2026-08-21T18-10.md new file mode 100644 index 000000000..74dbe4e21 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/no-python-toolchain.2026-08-21T18-10.md @@ -0,0 +1,101 @@ +# Baseline — Python Toolchain Absence Finding + +Timestamp: 2026-08-22T09-49 + +Command: + +``` +ls -d scripts/dev_tools +ls -l pyproject.toml +ls scripts/ +ls -l poetry.lock +git ls-files "*.py" +ls .claude/lib/ +``` + +All run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. + +EXIT_CODE: 0 + +Output Summary: + +## Both required negative existence checks + +1. **`scripts/dev_tools/` does not exist.** + + ``` + ls: cannot access 'scripts/dev_tools': No such file or directory + ``` + + The `scripts/` directory exists but contains only PowerShell: + + ``` + dev-tools/ (contains only run-actionlint.ps1) + temp-extract-coverage.ps1 + vscode/ + ``` + + Note the hyphen: the repository has `scripts/dev-tools/`, not the underscored + `scripts/dev_tools/` that Python module paths of the form `scripts.dev_tools.*` would require. The + hyphenated directory holds one PowerShell script and no Python. + +2. **No `pyproject.toml` exists at the worktree root.** + + ``` + ls: cannot access 'pyproject.toml': No such file or directory + ``` + + `poetry.lock` is likewise absent: + + ``` + ls: cannot access 'poetry.lock': No such file or directory + ``` + + There is therefore no Poetry manifest and no `poetry run` environment to resolve. + +Supporting evidence: `git ls-files "*.py"` returns only two tracked Python files, both inside an +archived feature folder and neither part of any toolchain: + +``` +docs/features/archive/2026-07-18-stale-app-config-binding-redirects-354/scripts/fix_binding_redirects.py +docs/features/archive/2026-07-18-stale-app-config-binding-redirects-354/tests/scripts/test_fix_binding_redirects.py +``` + +## Finding + +**There is no Python toolchain in this repository.** Any skill step, rule citation, or process +instruction naming a Python dev-tools module — for example a command of the form +`poetry run python -m scripts.dev_tools.` — is **unrunnable by absence** in this repository. +Such a step is reported as unrunnable-by-absence. It is never fabricated and never silently skipped. + +This applies to every Python validator named in the `.claude/rules/` files read in Phase 0, including +`scripts/dev_tools/validate_orchestrator_state.py`, +`scripts/dev_tools/validate_orchestration_artifacts.py`, +`scripts/dev_tools/plan_gate_discrimination.py`, and the parallel-surface validators. Those rule files +describe enforcement mechanisms that exist in a different repository snapshot; in this checkout the +Python modules they name are not present. The rule files remain the **policy** this fix is measured +against — they are cited, not edited, and this child edits nothing under `.claude/`. + +The PowerShell equivalents that do exist live under `.claude/lib/`: + +``` +bash/ +blast-radius/ +codex-routing/ +discovery-validation/ +mermaid/ +model-routing/ +orchestrator-state/ +``` + +Consistent with this finding, the plan itself contains no Python command anywhere (Binding +Constraint 8), and no step in Phase 0 or Phase 1 required one. No Python step was skipped, because +none was scheduled. + +## Acceptance conditions + +1. **Artifact exists with all four fields** (`Timestamp:`, `Command:`, `EXIT_CODE:`, + `Output Summary:`) — met. +2. **Records both negative existence checks** — met: `scripts/dev_tools/` absent and root + `pyproject.toml` absent, each with the verbatim command output. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nuget-restore.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nuget-restore.2026-08-21T18-10.md new file mode 100644 index 000000000..29f22689e --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nuget-restore.2026-08-21T18-10.md @@ -0,0 +1,85 @@ +# Baseline — NuGet Restore + +Timestamp: 2026-08-22T09-18 + +Command: + +``` +# 1. Pre-state confirmation (run from the worktree root) +ls -d packages + +# 2. Restore +pwsh -NoProfile -Command 'nuget restore TaskMaster.sln' + +# 3. Post-state confirmation (run from the worktree root) +ls -d packages +ls packages | wc -l +git status --porcelain +``` + +EXIT_CODE: 0 + +Output Summary: + +## Pre-state (confirmed first, as the task requires) + +`ls -d packages` → `ls: cannot access 'packages': No such file or directory`. The directory did +**not** exist at the worktree root before the restore. This is the condition the task predicts for a +fresh agent worktree. + +## Installed-package count + +**172 packages installed to `packages.config` projects.** NuGet's own closing line: + +``` +Installed: + 172 package(s) to packages.config projects +``` + +The resulting `packages` directory holds **172** top-level package folders, matching the reported +install count. + +Feeds used, as reported by NuGet: + +``` + \.nuget\packages\ + https://api.nuget.org/v3/index.json + C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\ +``` + +## Post-state — acceptance conditions + +1. **`EXIT_CODE: 0`** — the restore completed with no error and reported 172 installs. +2. **The `packages` directory exists at the worktree root** — `ls -d packages` → `packages/`. +3. **`git status --porcelain` reports zero entries whose path begins with the restored packages + directory name.** The full porcelain output is the two lines produced by this Phase 0 execution + itself: + + ``` + M docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md + ?? docs/features/active/winformspumphost-suite-determinism-511/evidence/ + ``` + + `.gitignore:191` carries the pattern `**/[Pp]ackages/*`, which ignores the tree's contents. The + surrounding block reads: + + ``` + # NuGet Packages + *.nupkg + # The packages folder can be ignored because of Package Restore + **/[Pp]ackages/* + # except build/, which is used as an MSBuild target. + !**/[Pp]ackages/build/ + ``` + + Restoring therefore does not dirty the tree and does not endanger the clean-tree acceptance in + P6-T18. + +## Why this task is load-bearing + +Every project declares an `EnsureNuGetPackageBuildImports` target whose `Error` fires at +`BeforeTargets="PrepareForBuild"` when the `packages` tree is missing +(`QuickFiler.Test/QuickFiler.Test.csproj:452-460` is the representative instance). Without the +restore, every msbuild task in this plan hard-fails before compilation and every `Reference` hint path +under the `packages` tree is unresolvable. This step mirrors the CI step at +`.github/workflows/_build-analyzers.yml:45`. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nullable-gate.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nullable-gate.2026-08-21T18-10.md new file mode 100644 index 000000000..2b327ba64 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nullable-gate.2026-08-21T18-10.md @@ -0,0 +1,68 @@ +# Baseline — Nullable Gate + +Timestamp: 2026-08-22T09-26 + +Command: + +``` +pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true' +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. `msbuild` was +invoked through its absolute resolved path +`C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe`, and the full +log was captured to `coverage\nullable-baseline.log` (10,547 lines). + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | +| --- | --- | +| Exit code | **0** | +| Error count | **0** | +| Warning count | 5 | +| Log lines matching `Skipping target "CoreCompile"` | **0** | +| Log lines matching `CoreCompile:` (target actually executed) | 53 | +| Log file | `coverage\nullable-baseline.log` (10,547 lines) | +| Wall time | 00:00:20.71 | + +## Acceptance conditions + +1. **`EXIT_CODE: 0`** — met. +2. **`Skipping target "CoreCompile"` count is exactly 0** — met, corroborated positively by 53 + `CoreCompile:` target executions. The compiler and nullable-flow diagnostics genuinely ran; the + gate was not vacuous. + +## Confirmation that no `/p:Nullable=enable` was passed + +The exact argument vector handed to `MSBuild.exe` was captured and printed before the invocation: + +``` +ARGS: TaskMaster.sln | /t:Rebuild | /m | /p:Configuration=Debug | /p:Platform=Any CPU | /p:TreatWarningsAsErrors=true +CONTAINS_NULLABLE_ENABLE_SWITCH: False +``` + +The vector was additionally matched against the pattern `Nullable`, which returned `False`. **The +command carried no `/p:Nullable=enable`.** This is character-for-character the command in +`.github/workflows/ci.yml` (step "Build with nullable warnings treated as errors"). Adding the switch +is prohibited: no project in this repository carries a `` element and there is no +`Directory.Build.props`, so the property is a solution-wide opt-in that conscripts every file which +never adopted the `#nullable enable` pragma. + +## Warning inventory + +All **5** warnings are the same pre-existing System.Reactive 7.0 `packages.config` incompatibility +notice recorded in the P0-T13 analyzer-gate artifact, emitted once each by `QuickFiler.csproj`, +`TaskMaster.csproj`, `ToDoModel.csproj`, `UtilitiesCS.csproj`, and `UtilitiesCS.Test.csproj`. + +Note on why they did not fail this gate despite `/p:TreatWarningsAsErrors=true`: the diagnostic is +emitted by an MSBuild target (`System.Reactive.PackagesConfigCheck.targets(31,5)`) and carries no +compiler diagnostic code. `TreatWarningsAsErrors` promotes **compiler** warnings, not warnings raised +by arbitrary MSBuild tasks, so the five remain warnings and the error count stays 0. This is a +pre-existing condition, unrelated to this child, recorded rather than repaired. + +There were **zero** `CS86xx` nullable-flow diagnostics at baseline. Nullable enforcement in this +repository is per-file opt-in via the `#nullable enable` directive, and no opted-in file currently +carries a violation. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/phase0-instructions-read.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/phase0-instructions-read.md new file mode 100644 index 000000000..c7537516a --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/phase0-instructions-read.md @@ -0,0 +1,142 @@ +# Phase 0 — Policy Instructions Read + +Timestamp: 2026-08-22T09-12 + +Policy Order: + +1. `CLAUDE.md` (standing instructions, always loaded) +2. `.claude/rules/general-code-change.md` (cross-language code change policy) +3. `.claude/rules/general-unit-test.md` (cross-language unit test policy) +4. `.claude/rules/csharp.md` (C#-specific toolchain and coding standards) + +Files read, in the order read: + +- `CLAUDE.md` — read end to end (P0-T1) +- `.claude/rules/general-code-change.md` — read end to end (P0-T2) +- `.claude/rules/general-unit-test.md` — read end to end (P0-T3) +- `.claude/rules/csharp.md` — read end to end, 96 lines (P0-T4) + +All four paths are relative to the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. + +--- + +## P0-T1 — `CLAUDE.md` + +The four numbered policy sections `CLAUDE.md` embeds directly, each of which applies to every +session without requiring an explicit skill load: + +1. General Code Change Policy +2. General Unit Test Policy +3. C# Code Change Policy +4. C# Unit Test Policy + +Quoted Policy Compliance Order list, verbatim from `CLAUDE.md`: + +> ## Policy Compliance Order +> +> The four core policies below are embedded directly in this file and apply to every session without requiring explicit skill loads. Apply them in this order: +> +> 1. This file (CLAUDE.md) — all sections +> 2. General Code Change Policy (§ below) +> 3. General Unit Test Policy (§ below) +> 4. For C#: C# Code Change Policy (§ below) and C# Unit Test Policy (§ below) + +--- + +## P0-T2 — `.claude/rules/general-code-change.md` + +Quoted 500-line file-size limit, verbatim: + +> ## File Size Limit +> +> - No production code, test code, or reusable script file may exceed **500 lines**. +> - Exceptions: temporary throwaway scripts created and deleted within an agent session; raw text fixtures for language-processing test data; Markdown documentation files. + +Quoted mandatory toolchain loop, verbatim: + +> ## Mandatory Toolchain Loop +> +> Run the full seven-stage toolchain in this exact order and repeat until all stages pass in a single pass: +> +> 1. **Formatting** (e.g., Black, Prettier, CSharpier, Invoke-Formatter) +> 2. **Linting** (e.g., Ruff, ESLint, PSScriptAnalyzer, .NET analyzers) +> 3. **Type checking** (e.g., Pyright, TSC, nullable analysis; skip for PowerShell) +> 4. **Architecture-boundary tests** (e.g., dependency-cruiser, NetArchTest.Rules) +> 5. **Unit tests** (e.g., Pytest, Jest, MSTest, Pester) including property-based tests where applicable per `quality-tiers.md` +> 6. **Contract / schema compatibility checks** (e.g., oasdiff, schema-snapshot diff) +> 7. **Integration tests** +> +> **Restart from step 1** if any stage fails or auto-fixes any files. Do not stop the loop until all seven stages complete without errors in a single pass. +> +> Mutation testing and golden tests run in pre-merge or nightly pipelines, not the per-commit loop. + +Relevance to this child: Binding Constraint 5 of the plan applies the 500-line cap to each of the +three touched test files. Pre-change counts are recorded in P0-T7. + +--- + +## P0-T3 — `.claude/rules/general-unit-test.md` + +Quoted coverage thresholds, verbatim: + +> ## Coverage Requirements +> +> - **Line coverage must remain >= 85% across all tiers (T1–T4).** +> - **Branch coverage must remain >= 75% across all tiers (T1–T4) for languages whose coverage tooling measures branch coverage.** PowerShell (Pester) and bash (kcov) are the exceptions: neither tool measures branch coverage in any output format, so only the line threshold applies to them and there is no branch-coverage gate. This is a threshold exemption only; PowerShell and bash production files remain in the coverage denominator under the Coverage Exclusion Policy below. +> - Code changes or refactors must not reduce coverage for the lines that were changed. +> - Tier-specific lower coverage thresholds are not used in this repository. See `.claude/rules/quality-tiers.md` for the full tier system. +> - Coverage is a supporting metric, not the sole quality gate. Untested critical behavior is not acceptable even if the overall percentage looks good. +> - Configure coverage tooling to exclude test files (e.g., `tests/`) so metrics reflect application code, not tests. +> - Type-only / interface-only modules with no executable behavior may be omitted from coverage measurement. Examples: Python `Protocol`-only modules consumed only under `TYPE_CHECKING`, TypeScript interface/type-only files, and C# interface-only files. Such modules legitimately report 0% executable coverage and may be excluded from measurement. This is a clarification only; it does not lower any coverage threshold. + +Recorded threshold divergence, without reconciliation: `CLAUDE.md` and `.claude/rules/csharp.md` +both state a repository-wide line-coverage floor of `>= 80%` and a `>= 90%` floor for new modules, +classes, and methods, while this rule file states `>= 85%` line and `>= 75%` branch uniformly across +tiers. Both are recorded because this child changes no production file and, per the plan's coverage +note, `QuickFiler/Viewers/ItemViewer.cs` carries a whole-type `[ExcludeFromCodeCoverage]`, so the +operative requirement for this child is **no regression** in `QfcItemController` coverage rather +than clearing any absolute floor. + +Quoted Determinism Infrastructure banned-API list, verbatim: + +> ## Determinism Infrastructure +> +> All test code must be deterministic. The following infrastructure requirements apply uniformly: +> +> - **Controllable clock** — use a `Clock` interface (TypeScript) or `TimeProvider` (.NET) injected into code under test. Do not read wall-clock time directly in production code under test. +> - **Seeded RNG** — randomness must be supplied via a seedable interface; on test failure the seed must be printed so the failure is reproducible. +> - **Banned APIs in test code** — `setTimeout`, `Thread.Sleep`, `Task.Delay`, real wall-clock waits, and `Date.now()` outside the clock interface are prohibited in tests. +> - **Virtual scheduler / fake timers / `FakeTimeProvider`** — async tests must use the framework's fake-timer facility (`jest.useFakeTimers()` for Jest, `FakeTimeProvider` for .NET) to advance simulated time deterministically. + +Relevance to this child: the banned-API list plus Binding Constraint 6 forbid any sleep, retry, +`SpinWait`, timing tolerance, or raised timeout constant in the fix. `PumpTimeoutMs = 60000` and +`TimeoutMs = 30000` retain their current values. + +--- + +## P0-T4 — `.claude/rules/csharp.md` + +Quoted four toolchain commands, verbatim: + +> ## Toolchain +> +> 1. **Formatting — CSharpier**: All C# source files must be formatted with CSharpier. Do not use `dotnet format`. Run `dotnet tool restore` first when the manifest tool has not been restored. Apply formatting with `dotnet tool run csharpier format .` and verify read-only with `dotnet tool run csharpier check .`. Always invoke through `dotnet tool run` so the manifest-pinned CSharpier version is used. +> 2. **Linting — .NET Analyzers**: C# code must pass Roslyn/.NET analyzer diagnostics. Command: `msbuild .sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true`. `/t:Rebuild` is intentional for a warm local worktree: `/t:Build` can skip `CoreCompile` through MSBuild incrementality and exit 0 without running analyzers. CI may retain `/t:Build` on a cold checkout. +> 3. **Type Checking — Nullable Analysis**: Compiler and nullable-flow diagnostics must pass with warnings as errors. Command: `msbuild .sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true`. `/t:Rebuild` is required locally so compiler and nullable-flow diagnostics actually run. Projects opt into nullable per file with `#nullable enable`; do not pass `/p:Nullable=enable`, which opts every unannotated file in at once. +> 4. **Testing — MSTest + Moq + FluentAssertions**: Run tests with: `vstest.console.exe /EnableCodeCoverage` +> +> Run the toolchain in order: format → lint → type-check → test. Restart from step 1 if any step fails or changes files. + +Quoted six "Prohibited Behaviors" bullets, verbatim: + +> ## Prohibited Behaviors +> +> - Broad refactors across unrelated projects or files. +> - Introducing heavy generic abstraction frameworks without need. +> - Creating analyzer debt and deferring cleanup. +> - Weakening assertions or relaxing test expectations to make tests pass. +> - Adding sleeps, retries, or timing hacks to mask flaky behavior. +> - Reporting success without running the required toolchain. + +All six bullets are present in the file and all six are quoted above. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/suite-run.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/suite-run.2026-08-21T18-10.md new file mode 100644 index 000000000..81c43de4d --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/suite-run.2026-08-21T18-10.md @@ -0,0 +1,105 @@ +# Baseline — Full Nine-Assembly Suite Run + +Timestamp: 2026-08-22T09-28 + +Command: + +``` +"C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe" ^ + QuickFiler.Test\bin\Debug\QuickFiler.Test.dll ^ + SVGControl.Test\bin\Debug\SVGControl.Test.dll ^ + Tags.Test\bin\Debug\Tags.Test.dll ^ + TaskMaster.Test\bin\Debug\TaskMaster.Test.dll ^ + TaskTree.Test\bin\Debug\TaskTree.Test.dll ^ + TaskVisualization.Test\bin\Debug\TaskVisualization.Test.dll ^ + ToDoModel.Test\bin\Debug\ToDoModel.Test.dll ^ + UtilitiesCS.Test\bin\Debug\UtilitiesCS.Test.dll ^ + VBFunctions.Test\bin\Debug\VBFunctions.Test.dll ^ + /EnableCodeCoverage /InIsolation "/TestCaseFilter:TestCategory!=LiveOutlook" ^ + /Logger:trx ^ + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/p0-t15 +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243` through +`pwsh -NoProfile`. `vstest.console.exe` was resolved with +`vswhere -latest -products * -find 'Common7\IDE\Extensions\TestPlatform\vstest.console.exe'`. All +nine assembly paths came from the plan's canonical assembly list and all nine were confirmed present +on disk (built at 09:25 by the P0-T14 `/t:Rebuild`) before the run. + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | +| --- | --- | +| Total | **6437** | +| Passed | **6437** | +| Failed | **0** | +| Skipped / not executed | **0** | +| Exit code | 0 | +| Verdict line | `Test Run Successful.` | + +The TRX `` element corroborates the console summary exactly: + +``` + +``` + +## TRX path + +``` +docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/p0-t15/2026-08-22_09_27_19_net481.trx +``` + +The file exists (9,150,580 bytes) and is the **only** TRX file in that subdirectory. Directory +listing: + +``` +d76a53ba-c575-4bfc-94cd-7d71737150a5/ (holds the binary .coverage attachment) +2026-08-22_09_27_19/ (per-test attachment folder) +2026-08-22_09_27_19_net481.trx (the single TRX) +``` + +## Acceptance conditions + +1. **Artifact exists with all four fields** — met. +2. **Named TRX exists under `.../evidence/baseline/p0-t15/` and is the only TRX there** — met; TRX + count in that subdirectory is 1. +3. **Recorded total exceeds 1,000 tests** — met at **6,437**, confirming all nine assemblies loaded. + +## `/InIsolation` confirmation + +`/InIsolation` was supplied. The phantom-failure signature the plan warns about — roughly 1,695 +failures with empty messages and sub-millisecond durations, surfacing as a Moq +`TypeInitializationException` via `System.Threading.Tasks.Extensions` — did **not** appear. Failed +count is 0, so no correction re-run was required and nothing was "fixed". + +## Baseline state of the two named tests (data carried into Phase 1) + +Both tests that #511 and #571 concern **passed** on this baseline run: + +- `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` — `outcome="Passed"`, + duration `00:00:00.0915828` +- `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` — `outcome="Passed"` + +This is a single observation, not a failure-rate measurement. It is consistent with #571's report +that the tests pass on some runs, and it is exactly the condition Phase 1 exists to measure across +twenty runs. Per the plan's explicit instruction, a green pre-fix run is treated as **data about the +race window**, not as evidence the defect is absent. + +## Pre-existing baseline failures + +**None.** There is no pre-existing failing test in the nine-assembly suite at this baseline. Any +failure observed later in this execution is therefore either an `[expect-fail]` Phase 1 measurement +or a regression introduced by the change, and the two are distinguishable. + +## Note on artifact size + +`/EnableCodeCoverage` wrote a binary `.coverage` attachment of 20,525,261 bytes into the +`d76a53ba-c575-4bfc-94cd-7d71737150a5/` subfolder, making the `p0-t15` directory 48 MB in total. The +plan mandates this exact command shape with this exact `/ResultsDirectory`, so the attachment is +recorded here as produced. The binary `.coverage` file is not the source of numeric coverage in this +plan; P0-T16 produces numeric coverage separately via Cobertura XML. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/tool-restore.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/tool-restore.2026-08-21T18-10.md new file mode 100644 index 000000000..1daca6020 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/tool-restore.2026-08-21T18-10.md @@ -0,0 +1,52 @@ +# Baseline — `dotnet tool restore` + +Timestamp: 2026-08-22T09-21 + +Command: + +``` +dotnet tool restore +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`. + +EXIT_CODE: 0 + +Output Summary: + +Full command output: + +``` +Tool 'csharpier' (version '1.2.6') was restored. Available commands: csharpier + +Restore was successful. +``` + +- **Restored CSharpier version: `1.2.6`.** This matches the acceptance condition exactly. +- The version is confirmed against the manifest, which lives at the worktree root as + `dotnet-tools.json` (not under `.config/`): + + ```json + { + "version": 1, + "isRoot": true, + "tools": { + "csharpier": { + "version": "1.2.6", + "commands": [ + "csharpier" + ], + "rollForward": false + } + } + } + ``` + + `"rollForward": false` means the restored version cannot drift from the pin, so the restored + `1.2.6` is the version every subsequent `dotnet tool run csharpier` invocation in this plan will + use. This is the same version `.github/workflows/ci.yml` runs after its own `dotnet tool restore`, + so local formatter output agrees with CI. + +This task became runnable only after P0-T8 provisioned the worktree-local SDK; before that, +`dotnet tool restore` would have failed with the `global.json` error message. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/ac-status-summary.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/ac-status-summary.2026-08-23T20-57.md new file mode 100644 index 000000000..0adf487ee --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/ac-status-summary.2026-08-23T20-57.md @@ -0,0 +1,103 @@ +# Acceptance-Criteria Status Summary — Remediation Cycle 1 + +Timestamp: 2026-08-23T19-33 + +Acceptance-criteria source: `docs/features/active/winformspumphost-suite-determinism-511/spec.md`, +section `## Acceptance Criteria` (work mode `full-bug`, so `spec.md` only). + +Checkbox state in `spec.md` at the time of writing: **14 of 14 checked, 0 unchecked.** Every row +below reads `satisfied`, and the row states agree with the checkbox states in `spec.md`. + +All paths in the `Evidence artifact` column are relative to +`docs/features/active/winformspumphost-suite-determinism-511/`. + +| # | Criterion, verbatim first line | State | Evidence artifact | Revised this cycle | +| --- | --- | --- | --- | --- | +| 1 | `` `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` `` | satisfied | `evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md` | no | +| 2 | `` `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` `` | satisfied | `evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md` | no | +| 3 | `The ten consecutive full nine-assembly runs are executed under induced CPU load using` | satisfied | `evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md` | **yes — see note A** | +| 4 | `An empirical pre-fix baseline artifact exists under ``evidence/regression-testing/`` recording,` | satisfied | `evidence/regression-testing/prefix-baseline.2026-08-21T18-10.md` | no | +| 5 | `` `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` exists in `` | satisfied | `evidence/regression-testing/named-regression-tests.2026-08-21T18-10.md` | no | +| 6 | `` `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` exists in `` | satisfied | `evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md` | **yes — see note B** | +| 7 | `` `git diff` reports zero hunks in both `` | satisfied | `evidence/regression-testing/scope-lock-after-comment-fix.2026-08-23T20-57.md` | no | +| 8 | `All 21 pump-host call sites pass in the final run: the 13 self-tests in` | satisfied | `evidence/regression-testing/pumphost-selftests.2026-08-21T18-10.md` | no | +| 9 | `` `git diff --name-only` against the merge base lists exactly three code files, all under `` | satisfied | `evidence/regression-testing/scope-lock-after-comment-fix.2026-08-23T20-57.md` | no | +| 10 | `` `QfcItemController_SeamFactoryTests` and `QfcItemController_InitializationTests` both pass in `` | satisfied | `evidence/regression-testing/gate-structure-part2.2026-08-21T18-10.md` | no | +| 11 | `Every changed file is under 500 lines after the change:` | satisfied | `evidence/qa-gates/remediation-file-size-audit.2026-08-23T20-57.md` | no | +| 12 | `` `git diff` introduces no occurrence of `Thread.Sleep`, `Task.Delay`, `SpinWait`, a retry loop, `` | satisfied | `evidence/regression-testing/no-timing-hacks.2026-08-21T18-10.md` | no | +| 13 | `The five-step toolchain in ``## Test Strategy`` completes green in a single final pass, coverage` | satisfied | `evidence/qa-gates/remediation-clean-pass.2026-08-23T20-57.md` | no | +| 14 | `` `## Rollout & Follow-up` records #511's visible-window half as out of scope with its `` | satisfied | `evidence/other/discharged-issue-tasks.2026-08-23T20-57.md` | no | + +## Supporting evidence beyond the single artifact named per row + +Several criteria are corroborated by more than the one artifact the table names; the table names the +primary record so that every row resolves to exactly one existing file. + +- Criterion 3 is additionally supported by + `evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md`, + `evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md`, + `evidence/regression-testing/load-generator-start.2026-08-21T18-10.md`, + `evidence/regression-testing/load-generator-stop.2026-08-21T18-10.md`, + `evidence/regression-testing/p4-t2-narrowing-rationale.2026-08-23T20-57.md`, and + `evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`. +- Criterion 4 is additionally supported by + `evidence/regression-testing/intermittency-question.2026-08-21T18-10.md`, which disposes of the + open intermittency question against the same twenty-row measured table. +- Criterion 6 is additionally supported by + `evidence/regression-testing/named-regression-tests.2026-08-21T18-10.md` (the test passes). +- Criterion 8 is additionally supported by + `evidence/regression-testing/consumer-tests.2026-08-21T18-10.md` (8 consumer tests, 8 passed, + 0 failed) and `evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md` (a `QuickFiler.Test` + failed count of exactly 0 in the final run). +- Criterion 13 is additionally supported by + `evidence/qa-gates/remediation-coverage.2026-08-23T20-57.md` and + `evidence/qa-gates/remediation-coverage-delta.2026-08-23T20-57.md` (a `QuickFiler` package + `line-rate` delta of +0.15 percentage points, which is greater than or equal to the pre-fix + baseline). +- Criterion 14 is additionally supported by the P4-T5 edit to the spec's `## Rollout & Follow-up` + section, which names issue #592 as the filed follow-up. + +## Note A — criterion 3 was revised this cycle (remediation Finding F) + +**Falsified original wording, summarized:** the criterion required the ten consecutive full +nine-assembly runs to be "all green" suite-wide. Nine of the ten were suite-wide green; run 5 +recorded a single failure, +`UtilitiesCS.Test.Extensions.DfDeedle_COM_Tests.GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform`, +in a sibling-owned assembly this child's three-file `QuickFiler.Test/` diff cannot reach. An +absolute-zero gate spanning an assembly the child does not own is unsatisfiable by any work inside +the child's scope. + +**Revision:** the criterion now requires zero failures in the `QuickFiler.Test` assembly — the +assembly containing every class this child owns — with both named end-to-end tests and both named +regression tests passing in all ten runs, and records run 5's sibling-assembly failure explicitly +with its attribution to issue #594. This follows the ratified repository precedent that a child's +absolute-zero gate is scoped to the classes it owns and the residual is promoted as its own defect. +The revision was applied by remediation task P2-T2 and the matching plan-task narrowing by P2-T3. + +## Note B — criterion 6 was revised this cycle (remediation Finding E) + +**Falsified original wording, summarized:** the criterion required +`BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` to assert that "both WebView2 children remain +handle-less". Measurement on 2026-08-22, recorded in +`evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md`, proved the +opposite: `ItemViewer.InitializeComponent` runs the Designer-emitted `ISupportInitialize.EndInit()` +calls on both WebView2 children, which creates their handles, and WinForms creates a parent's handle +when a child's is created. The criterion asserted an unmeasured world-state that is false, so no +passing test could ever have satisfied it as worded. + +**Revision:** the criterion now requires the test to assert the measured **inherited** state — both +children are already handle-created by `ItemViewer` construction, so the harness inherits the handles +rather than creating them. The revision was applied by remediation task P2-T1. The same measured +truth was propagated into the two comment blocks by P1-T1 and P1-T2 and into the spec's +`## Scope & Non-Goals` section by P2-T7 and P2-T8. + +## Summary in the acceptance-criteria-tracking format + +``` +### Acceptance Criteria Status +- Source: docs/features/active/winformspumphost-suite-determinism-511/spec.md +- Total AC items: 14 +- Checked off (delivered): 14 +- Remaining (unchecked): 0 +- Items remaining: none +``` diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/discharged-issue-tasks.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/discharged-issue-tasks.2026-08-23T20-57.md new file mode 100644 index 000000000..fd63e8ad4 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/discharged-issue-tasks.2026-08-23T20-57.md @@ -0,0 +1,34 @@ +# Discharged Issue-Creation Tasks — Remediation Cycle 1 + +Timestamp: 2026-08-23T19-08 + +Orchestrator Decision 4 of `remediation-inputs.2026-08-23T20-57.md` verified against GitHub on +2026-08-23T20-57 that every residual this feature would otherwise have filed already has an open +issue. The original plan's two `gh issue create` tasks (P6-T1 and P6-T20) are therefore recorded as +already-satisfied with the issue number cited, and are not re-executed. No `gh issue create` is +executed anywhere in this cycle. + +| Residual | Issue | State | +| --- | --- | --- | +| Load-induced 60,000 ms `PumpTimeoutMs` expiry cascade under machine load — the genuine defect behind the #511 report | #592 | OPEN | +| Three pre-existing `UtilitiesCS.Test` flakes blocking any suite-wide zero gate | #594 | OPEN | +| Repository-wide analyzer version skew (original plan task P6-T20) | #597 | OPEN | + +Issues #511 and #571 are both CLOSED as NOT_PLANNED (2026-08-23T19:07), superseded by #592, with the +premise-correction comments already posted to both. This cycle makes no repair claim for either +superseded issue, files no duplicate, and creates no GitHub issue of any kind. + +Task mapping: + +- Original plan `[P6-T1]` — file the follow-up issue for #511's visible-window half. Discharged by + the pre-existing issue #592. Recorded in + `docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md` by + remediation task P2-T5. +- Original plan `[P6-T20]` — file the follow-up issue for the repository-wide analyzer version skew. + Discharged by the pre-existing issue #597. Recorded in the same plan file by remediation task + P2-T5. + +Two further residuals recorded in Decision 4 remain unfiled and are promoted through the MCP +promotion lifecycle by the orchestrator, outside this plan's execution scope: the orchestrator +checkpoint `blocked_reason` enum's inability to express a substantive halt, and repository-wide +host-identifier sanitization of the files outside this feature. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-artifact-deletion.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-artifact-deletion.2026-08-23T20-57.md new file mode 100644 index 000000000..855674846 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-artifact-deletion.2026-08-23T20-57.md @@ -0,0 +1,83 @@ +# Raw vstest Artifact Deletion — Remediation Cycle 1, Final Task + +Timestamp: 2026-08-23T19-42 + +Command: +```bash +E=docs/features/active/winformspumphost-suite-determinism-511/evidence +find $E -name '*.trx' -type f # enumerate +find $E -name '*.coverage' -type f # enumerate +find $E -name '*.trx' -type f -delete +find $E -name '*.coverage' -type f -delete +find $E -type d -empty -not -path "*/.*" -print -delete # prune emptied scratch directories +find $E -name '*.trx' | wc -l # verify +find $E -name '*.coverage' | wc -l # verify +``` + +EXIT_CODE: 0 + +Output Summary: + +### Deleted-file counts by extension + +| Extension | Deleted by this task | Recursive count under `evidence/` after deletion | Required | +| --- | --- | --- | --- | +| `*.trx` | **1** | **0** | exactly 0 | +| `*.coverage` | **2** | **0** | exactly 0 | +| **Total** | **3** | **0** | — | + +### What was deleted + +All three files were produced by this cycle's own P3-T6 suite run and lived under the per-run scratch +directory `evidence/qa-gates/r1-p3-t6/`. Account and host name segments in the default +`vstest.console.exe` filenames are redacted as `` and `` per the repository's +host-identifier hygiene rule. + +| # | Path (relative to `evidence/`) | Extension | +| --- | --- | --- | +| 1 | `qa-gates/r1-p3-t6/__2026-08-23_19_20_16_net481.trx` | `.trx` | +| 2 | `qa-gates/r1-p3-t6/1fb74b86-ee3f-4956-baa8-eef44537b3b4/__2026-08-23.19_21_00.coverage` | `.coverage` | +| 3 | `qa-gates/r1-p3-t6/__2026-08-23_19_20_16/In//__2026-08-23.19_21_00.coverage` | `.coverage` | + +### Emptied scratch directories pruned + +Five directories, deepest-first: + +``` +qa-gates/r1-p3-t6/1fb74b86-ee3f-4956-baa8-eef44537b3b4 +qa-gates/r1-p3-t6/__2026-08-23_19_20_16/In/ +qa-gates/r1-p3-t6/__2026-08-23_19_20_16/In +qa-gates/r1-p3-t6/__2026-08-23_19_20_16 +qa-gates/r1-p3-t6 +``` + +After pruning, the evidence tree contains zero empty directories and exactly five subdirectories: +`baseline/`, `other/`, `qa-gates/`, `regression-testing/`, and `remediation-baseline/`. + +### Relationship to the earlier maintainer deletion + +The 2026-08-23 maintainer deletion recorded in +`docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md` +had already removed the 56 pre-existing `.trx` and 42 `.coverage` files (roughly 1,180.6 MB) and +pruned 188 empty scratch directories. This task therefore deleted only the raw artifacts newly +produced by the Phase 3 loop, principally the P3-T6 TRX. + +### Why deletion is safe + +All three deleted files were untracked or ignored — the `r1-p*-t*/` line appended to +`evidence/.gitignore` by P0-T9 covers the whole `r1-p3-t6/` subtree, and the repository-root +`.gitignore` already excludes `*.coverage`. None was ever staged or committed, so no committed +content is lost. + +The distilled Markdown records are the evidence of record, per remediation-inputs Part 1 row 8, which +verified the committed distillation faithful against the raw TRX before their deletion. The P3-T6 run +is fully recorded in +`docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md`, +including the `ResultSummary/Counters` block verbatim, the per-assembly pass and fail counts for all +nine assemblies, and the outcome of each of the four owned named tests. Repository policy rejects +committed raw machine test and coverage artifacts. + +The post-processed Cobertura XML remains available outside the evidence tree for the downstream +review gate, at the gitignored producer paths `coverage\remediation.cobertura.xml` and +`artifacts/csharp/coverage.xml`; neither is under `evidence/` and neither is affected by this +deletion. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md new file mode 100644 index 000000000..cfb01303c --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md @@ -0,0 +1,80 @@ +# Disposition of the Raw vstest Artifacts + +Timestamp: 2026-08-23T21-40 +Decided by: orchestrator, at maintainer instruction during the resumed `/orchestrate` session +Canonical issue number for this feature is 511. + +## What was removed + +| Class | Files | Size | +| --- | --- | --- | +| `*.trx` (vstest TRX logs) | 56 | 358.3 MB | +| `*.coverage` (binary VS coverage attachments) | 42 | 822.2 MB | +| **Total** | **98** | **1,180.6 MB** | + +Per-directory TRX counts at deletion time: + +| Count | Directory (under `evidence/`) | +| --- | --- | +| 1 | `baseline/p0-t15` | +| 10 | `regression-testing/p1-t3` | +| 10 | `regression-testing/p1-t4` | +| 1 | `regression-testing/p2-t6` | +| 1 | `regression-testing/p3-t4` | +| 1 | `regression-testing/p3-t5` | +| 1 | `regression-testing/p3-t6` | +| 1 | `regression-testing/p3-t7` | +| 10 | `regression-testing/p4-t2` | +| 10 | `regression-testing/supplementary-node-contention` | +| 10 | `regression-testing/supplementary-node-contention-b` | + +No non-markdown file other than these two classes existed under the evidence tree, so nothing else +was affected. + +## Why they were removed rather than committed + +1. **They were never committable.** `.gitignore:140` already excludes `*.coverage` repository-wide. + `*.trx` was **not** excluded, which meant a `git add -A` would have staged roughly 358 MB of TRX + into a repository whose entire pack is about 126 MiB. The repository's demonstrated policy is + against committing raw machine test and coverage artifacts. + +2. **They carry no audit value that is not already committed.** The distilled per-run markdown + records are the evidence of record. Before deletion, the orchestrator independently re-derived + the decisive figures directly from the raw TRX XML and compared them against the committed + distillation `regression-testing/determinism-ten-runs.2026-08-21T18-10.md`: + + - per-run totals and failed counts for all ten `p4-t2` runs, which matched exactly; + - the identity of the single failure in run 5, + `GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform`, in the sibling-owned + `UtilitiesCS.Test` assembly, which matched; + - the per-run outcome of all four of this child's named tests, `Passed` in 10 of 10 runs, which + matched. + + The committed markdown is therefore a faithful distillation, not a lossy summary of the claim. + +3. **The deletion was explicitly instructed** by the maintainer, who directed that files which will + eventually be committed be committed and that the remainder be deleted. + +## What replaces them + +- `regression-testing/determinism-ten-runs.2026-08-21T18-10.md` carries the ten TRX paths, per-run + total and failed counts, per-run durations, the bracketing CPU-utilization samples, and the + pre-fix versus post-fix comparison. +- `regression-testing/named-tests-ten-runs.2026-08-21T18-10.md` and + `regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md` carry the per-run tables for + the four named tests. +- `regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md` carries the four + measured configurations that falsified the plan's premise. +- This artifact records what was deleted and why. + +## Recurrence prevention + +`evidence/.gitignore` now excludes `*.trx`, `*.coverage`, `*.coveragexml` and the +`vstest.console.exe` per-run scratch directories, so the remaining toolchain runs in this feature +cannot leak raw artifacts into a `git add -A`. That file is committed alongside this record. + +## Reversibility + +This deletion is not reversible from the repository. The runs that produced these artifacts are +reproducible by re-executing the commands recorded in each distilled markdown record, which carry +the exact `Command:` line and `Timestamp:` for every run. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/remediation-review-handoff.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/remediation-review-handoff.2026-08-23T20-57.md new file mode 100644 index 000000000..20b371d2e --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/other/remediation-review-handoff.2026-08-23T20-57.md @@ -0,0 +1,190 @@ +# Remediation Review-Handoff Index — Cycle 1 (R1) + +Timestamp: 2026-08-23T19-35 + +Feature root: `docs/features/active/winformspumphost-suite-determinism-511` (abbreviated `FEATURE` +below; every path in this index is written relative to that root). + +Branch: `bug/winformspumphost-suite-determinism-511-exec` +Merge base with `origin/main` (`$MergeBase`, recorded by P0-T6): +`f85a36faebaaec29fe5233c9d9f69d223d80e4c5` + +No pull request is created and no CI run is monitored by this plan; both are handled outside it, with +the pull request targeting `main` per orchestrator Decision 1. + +--- + +## Markdown evidence artifacts produced by this plan + +### Phase 0 — policy reads and remediation baseline + +| Path | Task | +| --- | --- | +| `evidence/remediation-baseline/phase0-instructions-read.md` | P0-T5 | +| `evidence/remediation-baseline/git-identity.2026-08-23T20-57.md` | P0-T6 | +| `evidence/remediation-baseline/touched-files-state.2026-08-23T20-57.md` | P0-T7 | +| `evidence/remediation-baseline/toolchain-precheck.2026-08-23T20-57.md` | P0-T8 | +| `evidence/remediation-baseline/evidence-gitignore.2026-08-23T20-57.md` | P0-T9 | + +### Phase 1 — comment corrections + +| Path | Task | +| --- | --- | +| `evidence/regression-testing/file-size-after-comment-fix.2026-08-23T20-57.md` | P1-T3 | +| `evidence/regression-testing/scope-lock-after-comment-fix.2026-08-23T20-57.md` | P1-T4 | + +### Phase 2 — spec and plan reconciliation + +| Path | Task | +| --- | --- | +| `evidence/regression-testing/p4-t2-narrowing-rationale.2026-08-23T20-57.md` | P2-T4 | +| `evidence/other/discharged-issue-tasks.2026-08-23T20-57.md` | P2-T6 | + +### Phase 3 — final QC loop + +| Path | Task | +| --- | --- | +| `evidence/qa-gates/remediation-tool-restore.2026-08-23T20-57.md` | P3-T1 | +| `evidence/qa-gates/remediation-csharpier-format.2026-08-23T20-57.md` | P3-T2 | +| `evidence/qa-gates/remediation-csharpier-check.2026-08-23T20-57.md` | P3-T3 | +| `evidence/qa-gates/remediation-analyzer-gate.2026-08-23T20-57.md` | P3-T4 | +| `evidence/qa-gates/remediation-nullable-gate.2026-08-23T20-57.md` | P3-T5 | +| `evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md` | P3-T6 | +| `evidence/qa-gates/remediation-coverage.2026-08-23T20-57.md` | P3-T7 | +| `evidence/qa-gates/remediation-coverage-delta.2026-08-23T20-57.md` | P3-T8 | +| `evidence/qa-gates/remediation-coverage-artifact.2026-08-23T20-57.md` | P3-T9 | +| `evidence/qa-gates/remediation-file-size-audit.2026-08-23T20-57.md` | P3-T10 | +| `evidence/qa-gates/remediation-clean-pass.2026-08-23T20-57.md` | P3-T11 | + +### Phase 4 — acceptance criteria, handoff, and evidence hygiene + +| Path | Task | +| --- | --- | +| `evidence/other/ac-status-summary.2026-08-23T20-57.md` | P4-T7 | +| `evidence/other/remediation-review-handoff.2026-08-23T20-57.md` (this index) | P4-T8 | +| `evidence/other/raw-artifact-deletion.2026-08-23T20-57.md` | P4-T10 — written **after** this index | + +This index lists Markdown evidence only. The raw P3-T6 TRX is named separately below. + +Verification of the resolves-to-existing condition was performed twice, because the last row above is +written by a later task than the one that writes this index. At P4-T8 time, all 22 listed Markdown +paths other than the P4-T10 row resolved to existing files. After P4-T10 wrote its artifact, the +check was re-run over all 23 listed Markdown paths and all 23 resolved. Both results are recorded in +the executor's task log. + +### Raw (non-Markdown) artifact, not subject to the resolves-to-existing condition + +`evidence/qa-gates/r1-p3-t6/` — one TRX file plus one binary `.coverage` file produced by the P3-T6 +suite run. **deleted by P4-T10.** The directory is excluded by the `r1-p*-t*/` line that P0-T9 +appended to `evidence/.gitignore`, so it was never stageable; the distilled Markdown record +`evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md` is the evidence of record. + +--- + +## The seven remediation exit criteria and the task that discharged each + +Source: `remediation-inputs.2026-08-23T20-57.md`, Part 5 (criteria 1 through 6) plus the Part 6 +addendum (criterion 7). + +| # | Exit criterion | Discharged by | Evidence | +| --- | --- | --- | --- | +| 1 | Both comment blocks state the measured truth, including the present redundancy of the read | P1-T1, P1-T2 | the two `.cs` files in the diff; `evidence/regression-testing/file-size-after-comment-fix.2026-08-23T20-57.md` | +| 2 | Spec AC 6 revised to the measured inherited state; AC 3 revised to the owned-class scope citing #594; AC 8, AC 13 and AC 14 satisfied and checked off with cited evidence | P2-T1, P2-T2, P4-T1 through P4-T4, P4-T6 | `spec.md` (14 of 14 checked); `evidence/other/ac-status-summary.2026-08-23T20-57.md` | +| 3 | P4-T2's zero condition narrowed to owned classes and recorded as satisfied on existing evidence | P2-T3, P2-T4 | `plan.2026-08-21T18-10.md`; `evidence/regression-testing/p4-t2-narrowing-rationale.2026-08-23T20-57.md` | +| 4 | The Phase 5 (here Phase 3) toolchain completes green in a single final pass with numeric coverage recorded | P3-T1 through P3-T11 | `evidence/qa-gates/remediation-clean-pass.2026-08-23T20-57.md`; `evidence/qa-gates/remediation-coverage.2026-08-23T20-57.md` | +| 5 | The evidence `.gitignore` exists and the raw `.trx` / `.coverage` files are removed | P0-T9, P4-T10 | `evidence/remediation-baseline/evidence-gitignore.2026-08-23T20-57.md`; `evidence/other/raw-artifact-deletion.2026-08-23T20-57.md` | +| 6 | No artifact claims this branch repairs #511 or #571, and no closing keyword for either appears in the branch or the pull-request body | P4-T8 (file scan), P4-T9 and P4-T10 (git-log scan) | the file-scan and git-log-scan results recorded in this index and in the two commit tasks | +| 7 | The spec's `## Scope & Non-Goals` "In scope" bullets no longer assert the falsified premise | **P2-T7 and P2-T8** | the exit-criterion-7 re-check recorded below | + +--- + +## Exit-criterion-7 spec-scope re-check + +`Select-String -SimpleMatch` against `spec.md` only, for each of the four falsified-premise literals: + +| Literal | Matching lines in `spec.md` | Required | +| --- | --- | --- | +| `Deterministic creation of the` | **0** | 0 | +| `#571 in full` | **0** | 0 | +| `removing the handle race removes` | **0** | 0 | +| `as requiring its own issue against` | **0** | 0 | + +All four falsified-premise literals are absent from `spec.md`. The two bullets that remained accurate +were retained and verified present: `Regression tests for the new fixture invariant` matches exactly +1 line and `An empirical pre-fix and post-fix determinism record captured as evidence.` matches +exactly 1 line. + +--- + +## Closing-keyword file scan + +Scan: `Select-String` with the case-insensitive regex `(fix|clos|resolv)[a-z]* #(511|571)` against +five files. + +| # | Scanned file | Matches | Required | +| --- | --- | --- | --- | +| a | `spec.md` | **0** | 0 | +| b | `remediation-plan.2026-08-23T20-57.md` | **0** | 0 | +| c | `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` | **0** | 0 | +| d | `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | **0** | 0 | +| e | `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` | **0** | 0 | + +The git-log leg of the scan is deliberately not run here: this task runs before the P4-T9 and P4-T10 +commits, so `git log --format=%B $MergeBase..HEAD` could not yet see the messages this plan produces +and the leg could not fail. It runs post-commit in P4-T9 and is repeated in P4-T10. + +### Requirements-input carve-out record + +`remediation-inputs.2026-08-23T20-57.md` carries **three** matches of the scan regex, at its lines +227, 248, and 264, all inside negations that deny the repair claim. That file is **exempt by design** +from the file scan per the plan preamble: it is the input this plan consumes, not an artifact this +plan produces, and it was already committed to the branch before this cycle opened. GitHub parses +closing keywords only in commit messages and pull-request bodies, never in file contents, so its +committed text cannot auto-close either issue. A literal re-audit of "no closing keyword anywhere in +the branch" must apply this carve-out rather than raise the requirements input as a finding. + +### One additional observation, recorded rather than repaired + +The same class of pre-existing, already-committed file-content match exists at +`plan.2026-08-21T18-10.md` line 26, in the original plan's summary prose. That file is not among the +five the plan directs this task to scan, the match predates this cycle (it is byte-identical in +`HEAD`), and it is file content rather than a commit message or pull-request body, so it cannot +auto-close either issue. It is recorded here for the re-audit's benefit and was deliberately not +edited, because editing it is work this plan does not describe. + +--- + +## Residual conditions recorded rather than repaired + +1. **The genuine defect behind the #511 report** — the load-induced 60,000 ms `PumpTimeoutMs` expiry + cascade under machine load — is tracked as issue **#592** and is out of scope for this branch. + Findings A, B, and C are accepted: the fixture-hardening statement forces a handle that + construction already created, and this branch's value is the hardening, the regression tests + pinning the inherited state, and the mechanism finding. +2. **The three pre-existing `UtilitiesCS.Test` flakes** blocking any suite-wide zero gate are tracked + as issue **#594**. Every suite gate in this plan is scoped to the `QuickFiler.Test` assembly + accordingly. In this cycle's P3-T6 run and P3-T7 coverage run the flakes did not fire — both + recorded 6,459 passed and 0 failed on an otherwise idle machine — so they remain a real risk under + load that this cycle does not claim repaired. +3. **The repository-wide analyzer version skew** is tracked as issue **#597**; this plan back-fills + nothing new and edits no project file. +4. **Residual CPU-contention sensitivity** of the pump-hosted suite is a stated trade, unchanged by + this cycle. +5. **The `InvokeBeginInvoke` production asymmetry** remains a follow-up recorded in the spec's + `## Rollout & Follow-up`, not addressed here. + +--- + +## Diff scope at handoff + +`git diff --name-only $MergeBase`, filtered to `.cs`, `.csproj`, `.props`, `.targets`, and `.config`, +is exactly three paths, all under `QuickFiler.Test/`: + +1. `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` +2. `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` +3. `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` + +Prohibited counts, each exactly 0: paths beginning `QuickFiler/`, paths ending `.csproj`, and paths +beginning `.claude/` other than `.claude/agent-memory/`. Recorded in +`evidence/regression-testing/scope-lock-after-comment-fix.2026-08-23T20-57.md` and re-verified by +P4-T9 after the commit. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-analyzer-gate.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-analyzer-gate.2026-08-23T20-57.md new file mode 100644 index 000000000..a64b77d4e --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-analyzer-gate.2026-08-23T20-57.md @@ -0,0 +1,77 @@ +# Remediation QA Gate — Analyzer Gate + +Timestamp: 2026-08-23T19-16 + +Command: +``` +& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true +``` + +Run from the worktree root. Launched per the Phase 3 long-running command mechanic: a detached +`pwsh -NoProfile` runner invoked `Start-Process -PassThru` with `-RedirectStandardOutput +coverage\analyzer-remediation.log` and `-RedirectStandardError coverage\analyzer-remediation.err.log`, +recorded the child PID, then polled to completion. The recorded exit code is taken from the returned +process object's `ExitCode` property, not from `$LASTEXITCODE` of the polling shell. + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | Required | +| --- | --- | --- | +| Resolved msbuild path | `C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe` | recorded | +| Launched PID (`MSBuild.exe` child) | **380896** | recorded | +| Exit code (from the process object's `ExitCode`) | **0** | 0 | +| Warning count | **5** | not gated | +| Error count | **0** | 0 | +| Log lines matching `Skipping target "CoreCompile"` | **0** | exactly 0 | +| Log lines matching `CoreCompile:` (target actually executed) | 66 | corroboration only | +| `Done Building Project` lines | 20 | corroboration only | +| Lines matching `error CS` | 0 | corroboration only | +| Stderr log size | 0 bytes | corroboration only | +| Log file | `coverage\analyzer-remediation.log` (12,208 lines) | — | +| Wall time | 00:00:20.38 | — | + +MSBuild summary block, verbatim: + +``` + 5 Warning(s) + 0 Error(s) + +Time Elapsed 00:00:20.38 +``` + +## Acceptance conditions + +1. **`EXIT_CODE: 0`, taken from the process object's `ExitCode`** — met. +2. **The artifact records the resolved msbuild path** — met; bare `msbuild` does not resolve in this + environment and `pwsh -NoProfile` carries no Visual Studio developer environment, so the verified + absolute path is invoked through the call operator. +3. **Error count is 0** — met. +4. **`Skipping target "CoreCompile"` count is exactly 0** — met. This is the load-bearing proof that + the analyzers actually ran rather than being skipped by MSBuild incrementality, which is why + `/t:Rebuild` is used and `/t:Build` is not. It is corroborated positively by 66 `CoreCompile:` + target executions and 20 `Done Building Project` lines in the same log. No `csc.exe` count is + asserted, because that count is zero even on a real compile and would gate nothing. + +## Warning inventory + +All 5 warnings are the same pre-existing diagnostic, emitted once per affected project by +`packages\System.Reactive.7.0.0\build\System.Reactive.PackagesConfigCheck.targets(31,5)`: + +> warning : The project contains a packages.config file, which is not supported by System.Reactive +> v7.0 or later. Please migrate to PackageReference. + +This matches the baseline recorded in +`docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-gate.2026-08-21T18-10.md` +exactly: 5 warnings, 0 errors, 0 `Skipping target "CoreCompile"` lines, 20 `Done Building Project` +lines, 21.11 s baseline versus 20.38 s here. This cycle introduced no analyzer diagnostic. + +## Invocation note + +The first launch attempt failed with `MSBUILD : error MSB1008: Only one project can be specified.` +because `Start-Process -ArgumentList` was given an array whose `/p:Platform=Any CPU` element lost its +quoting when the arguments were joined. The runner was corrected to pass a single pre-quoted argument +string so the command line reaching `MSBuild.exe` is character-for-character the command above. The +failed attempt compiled nothing and is recorded here for completeness; it is an invocation-mechanics +correction, not a toolchain failure, and does not constitute a loop restart. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-clean-pass.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-clean-pass.2026-08-23T20-57.md new file mode 100644 index 000000000..62a3db2d0 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-clean-pass.2026-08-23T20-57.md @@ -0,0 +1,69 @@ +# Remediation QA Gate — Clean-Pass Attestation + +Timestamp: 2026-08-23T19-30 + +The Phase 3 final QC loop completed in a **single consecutive pass**. Every task P3-T1 through +P3-T10 executed its stated command, recorded a result, and neither failed nor changed a file. +`SKIPPED` was not used as a completion state for any task in this phase. + +## Per-task record + +| Task | Command | Exit code | Files changed by the step | +| --- | --- | --- | --- | +| P3-T1 | `dotnet tool restore` | 0 | none (CSharpier 1.2.6 already restored; restore is idempotent) | +| P3-T2 | `dotnet tool run csharpier format ` | 0 | **0** — hash-derived rewritten-file count, all three SHA-256 hashes identical before and after | +| P3-T3 | `dotnet tool run csharpier check .` | 0 | none (read-only); 1,519 files checked, 0 unformatted | +| P3-T4 | `& '' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true` | 0 | none in the source tree (build outputs only) | +| P3-T5 | `& '' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true` | 0 | none in the source tree (build outputs only) | +| P3-T6 | `& '' /EnableCodeCoverage /InIsolation /Logger:trx /ResultsDirectory:.../r1-p3-t6 /TestCaseFilter:"TestCategory!=LiveOutlook"` | 0 | none in the source tree (one TRX plus a `.coverage` file in the gitignored `r1-p3-t6/` scratch directory) | +| P3-T7 | `pwsh -NoProfile -File .\scripts\vscode\Invoke-MSTestWithCoverage.ps1 -SearchRoot . -CoverageOutput coverage\remediation.cobertura.xml` | 0 | none in the source tree (Cobertura XML in the gitignored `coverage\` directory) | +| P3-T8 | analysis of the P3-T7 and baseline artifacts (no external command) | 0 | none | +| P3-T9 | `Copy-Item coverage\remediation.cobertura.xml artifacts\csharp\coverage.xml` plus hash and attribute reads | 0 | none in the source tree (`artifacts/` is gitignored) | +| P3-T10 | `Get-Content -LiteralPath` line counts on the three touched files | 0 | none (read-only) | + +`` is `C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe`; +`` is +`C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe`. +Both are the verified absolute paths; bare `msbuild` does not resolve in this environment. + +## Loop restarts + +**Number of loop restarts performed: 0.** + +No step failed and no step changed a file, so the restart rule never fired. The pass recorded above +is the first and only pass. + +## Authorized P3-T7 re-run attempts + +**Number of authorized P3-T7 re-run attempts: 0.** The coverage capture succeeded on its first +attempt (1 of a permitted maximum of 3), so the bounded load-induced-timeout re-run authorization was +not exercised. + +## Non-restart events recorded for completeness + +Two events occurred that are **not** loop restarts and are recorded here so the attestation is +complete rather than tidy: + +1. **P3-T4 invocation-mechanics correction.** The first launch of the analyzer gate failed with + `MSBUILD : error MSB1008: Only one project can be specified.` because `Start-Process + -ArgumentList` was given an array whose `/p:Platform=Any CPU` element lost its quoting when the + arguments were joined into a command line. That attempt compiled nothing — the log shows the + MSB1008 error before any project began building — and changed no file. The runner was corrected to + pass a single pre-quoted argument string, and the gate then ran to completion with exit 0 and zero + `Skipping target "CoreCompile"` lines. This is a defect in how the executor spelled the + invocation, not a toolchain failure, and it triggers no restart of the loop. +2. **Idle MSBuild node stop before P3-T7.** Seventeen idle `MSBuild.exe` node-reuse processes left + resident by this cycle's own P3-T4 and P3-T5 `/m` builds (all with StartTime 19:16:12, i.e. + started by this run) were stopped before the coverage capture, following the load lesson recorded + in `evidence/baseline/coverage.2026-08-21T18-10.md`, where the same idle nodes were the only + environmental difference between a failed and a successful coverage invocation. No process + belonging to any other agent or worktree was touched: zero `testhost`, `vstest.console`, and + `dotnet-coverage` processes were resident at the time. This changed no file. + +## Attestation + +P3-T1 through P3-T10 all completed without failure and without changing files, in a single +consecutive pass. The five-step toolchain — format, format-verify, analyze, type-check, test with +coverage — is green end to end, with numeric coverage recorded (85.59% repository line rate, 79.06% +repository branch rate, 81.08% `QuickFiler` package line rate, 86.34% changed-module rate) and a +non-negative `QuickFiler` coverage delta of +0.15 percentage points against the baseline. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage-artifact.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage-artifact.2026-08-23T20-57.md new file mode 100644 index 000000000..c1b4fc604 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage-artifact.2026-08-23T20-57.md @@ -0,0 +1,42 @@ +# Remediation QA Gate — Downstream Review-Gate Coverage Artifact + +Timestamp: 2026-08-23T19-28 + +Command: +```powershell +New-Item -ItemType Directory -Force -Path "artifacts\csharp" +Copy-Item -LiteralPath "coverage\remediation.cobertura.xml" -Destination "artifacts\csharp\coverage.xml" -Force +Get-FileHash -Algorithm SHA256 -LiteralPath "coverage\remediation.cobertura.xml" +Get-FileHash -Algorithm SHA256 -LiteralPath "artifacts\csharp\coverage.xml" +([xml](Get-Content -Raw -LiteralPath "artifacts\csharp\coverage.xml")).coverage.'line-rate' +([xml](Get-Content -Raw -LiteralPath "artifacts\csharp\coverage.xml")).coverage.'branch-rate' +git check-ignore -q artifacts/csharp/coverage.xml +``` +(run from the worktree root) + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | Required | +| --- | --- | --- | +| `artifacts/csharp/coverage.xml` exists | yes | yes | +| SHA-256 of `coverage\remediation.cobertura.xml` | `94180AA0875F0C64AC2D8689F865EDF4A1ED7EB1B03292A9CD82FA82180050B1` | — | +| SHA-256 of `artifacts/csharp/coverage.xml` | `94180AA0875F0C64AC2D8689F865EDF4A1ED7EB1B03292A9CD82FA82180050B1` | must match | +| Byte-identical | **yes** | yes | +| Root `line-rate` | `0.855916` = **85.59%** | >= 85 | +| Root `branch-rate` | `0.790598` = **79.06%** | >= 75 | +| `git check-ignore -q artifacts/csharp/coverage.xml` | exit 0 (ignored) | — | + +Both thresholds are met against the baseline of 85.55% line and 79.03% branch: the copied artifact +records 85.59% line (>= 85, and above the baseline) and 79.06% branch (>= 75, and above the +baseline). + +## Location note + +`artifacts/csharp/` is a **tool-output producer path** read by the downstream feature-review coverage +hook, not an evidence location. The evidence-location invariant is therefore unaffected: the numeric +record lives here, under +`docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/`. The copied XML +itself is excluded by the repository-root `.gitignore` — `git check-ignore` exits 0 on it — so it does +not disturb the P4-T9 clean-tree gate. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage-delta.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage-delta.2026-08-23T20-57.md new file mode 100644 index 000000000..e85f83b6e --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage-delta.2026-08-23T20-57.md @@ -0,0 +1,76 @@ +# Remediation QA Gate — Coverage Delta Against the Baseline + +Timestamp: 2026-08-23T19-27 + +Baseline source: +`docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md` +Post-change source: +`docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage.2026-08-23T20-57.md` + +Both measurements were produced by the same script +(`scripts\vscode\Invoke-MSTestWithCoverage.ps1`) against a post-processed Cobertura XML, and the +changed-module figure was computed with the identical per-class-deduplicated `` counting method +the baseline artifact mandates. + +## The four measured figures + +| Figure | Baseline | Post-change | Signed delta (percentage points) | +| --- | --- | --- | --- | +| Repository headline line rate (root `line-rate`) | 85.55% (`0.855531`) | 85.59% (`0.855916`) | **+0.04** | +| Repository headline branch rate (root `branch-rate`) | 79.03% (`0.790312`) | 79.06% (`0.790598`) | **+0.03** | +| `QuickFiler` package line rate | 80.93% (`0.8092566619915849`) | 81.08% (`0.81084081028582`) | **+0.15** | +| Changed-module aggregate (`QuickFiler\Controllers\QfcItemController*`, 10 classes) | 86.34% (1410 / 1633) | 86.34% (1410 / 1633) | **+0.00** | + +The `QuickFiler` package `line-rate` delta is **+0.15 percentage points**, which is greater than or +equal to 0. The strict, no-tolerance condition on that figure is satisfied. + +## Per-class deltas for the changed module + +| Filename | Baseline line-rate | Post-change line-rate | Signed delta (pp) | +| --- | --- | --- | --- | +| `QuickFiler\Controllers\QfcItemController.cs` | 1 (100.00%) | 1 (100.00%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.Initialization.cs` | 0.949612 (94.96%) | 0.949612 (94.96%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.ViewerSetup.cs` | 0.850829 (85.08%) | 0.850829 (85.08%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.Conversation.cs` | 0.882353 (88.24%) | 0.882353 (88.24%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.FolderHandling.cs` | 0.952381 (95.24%) | 0.952381 (95.24%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.EventWiring.cs` | 0.815182 (81.52%) | 0.815182 (81.52%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.EventHandlers.cs` | 0.7865168539325843 (78.65%) | 0.7865168539325843 (78.65%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.Navigation.cs` | 0.90678 (90.68%) | 0.90678 (90.68%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.FocusAndTheme.cs` | 0.793249 (79.32%) | 0.793249 (79.32%) | +0.00 | +| `QuickFiler\Controllers\QfcItemController.MailActions.cs` | 0.768 (76.80%) | 0.768 (76.80%) | +0.00 | + +Every per-class `line-rate` delta is exactly +0.00 percentage points, comfortably above the +-0.50 percentage-point floor. The floor exists because `dotnet-coverage` denominators are not +bit-stable between runs; in this instance no per-class rate moved at all, so no measurement-noise +allowance had to be drawn on. The matched-class count is 10 in both measurements. + +## Changed-line coverage + +| Row | Value | +| --- | --- | +| Executable lines changed by this cycle's diff against the evidence-producing source (`02983a70`) | **0** | +| Comment lines changed | 13 added, 7 removed, across two files | +| Files with any change | `QfcItemController.InitializationTests.Part2.cs`, `QfcItemController.ViewerSetupTests.cs` | +| Changed-line coverage | vacuously non-regressed | + +This cycle's diff against the source that produced the Phase 4 determinism evidence consists of +comment lines only. `git diff --numstat 02983a70` on the three touched files reports `7 5` and `6 2` +with `QfcItemController.InitializationTests.Part3.cs` absent entirely, and filtering that diff to +changed lines that are not `//` comment lines returns the empty set — the verification is recorded in +`docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2-narrowing-rationale.2026-08-23T20-57.md`. +Zero executable lines changed, so there is no changed-line coverage denominator to regress and the +no-regression-on-changed-lines requirement is satisfied vacuously rather than by measurement. + +## Cell-value audit + +Every cell in every table above holds a numeric value or an explicit textual value derived from a +measurement. No cell holds a placeholder, and the token `UNVERIFIED` appears nowhere in this +artifact. + +## Acceptance conditions + +1. `QuickFiler` package `line-rate` delta greater than or equal to 0 (strict, no tolerance) — met at + **+0.15 pp**. +2. Every `QfcItemController` class `line-rate` delta greater than or equal to -0.50 pp — met; all ten + are exactly +0.00 pp. +3. Every cell holds a numeric value rather than a placeholder — met. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage.2026-08-23T20-57.md new file mode 100644 index 000000000..15c6044bf --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage.2026-08-23T20-57.md @@ -0,0 +1,129 @@ +# Remediation QA Gate — Post-Change Numeric Coverage + +Timestamp: 2026-08-23T19-25 + +Command: +``` +pwsh -NoProfile -File .\scripts\vscode\Invoke-MSTestWithCoverage.ps1 -SearchRoot . -CoverageOutput coverage\remediation.cobertura.xml +``` + +Run from the worktree root and launched per the Phase 3 long-running command mechanic: a detached +`pwsh -NoProfile` runner invoked `Start-Process -PassThru` with stdout redirected to +`coverage\coverage-remediation.log` and stderr to `coverage\coverage-remediation.err.log`, recorded +the child PID, then polled to completion. The recorded exit code is taken from the returned process +object's `ExitCode` property. The script wraps the same nine assemblies with `dotnet-coverage` and +emits Cobertura XML; `vstest.console.exe /EnableCodeCoverage` alone emits a binary `.coverage` file, +not a percentage, which is why this script is the source of numeric coverage. + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | +| --- | --- | +| Launched PID | **12564** | +| Exit code (from the process object's `ExitCode`) | **0** | +| Discovered test assemblies | **9** | +| vstest result | `Test Run Successful.` — total 6459, passed 6459, failed 0 | +| vstest exit code, recorded verbatim | **0** (the script exits non-zero and throws at line 236 when `dotnet-coverage` returns non-zero; it returned 0) | +| Stderr log size | 0 bytes | +| Post-processed Cobertura XML | `coverage\remediation.cobertura.xml` (10,465,460 bytes) | +| Wall time | 47.0414 s test time; run ended 2026-08-23T19-24-41 | + +Script output tail, verbatim: + +``` +Discovered 9 test assemblies. +Test Run Successful. +Total tests: 6459 + Passed: 6459 + Total time: 47.0414 Seconds +Code coverage results: ...\coverage\remediation.cobertura.xml. +Post-processing coverage XML for Koverage compatibility... +Done. Coverage artifact: ...\coverage\remediation.cobertura.xml +``` + +### The four required figures, as numeric percentages to two decimal places + +| Figure | Cobertura attribute | Raw | Percent | +| --- | --- | --- | --- | +| Repository headline line rate | root `line-rate` | `0.855916` | **85.59%** | +| Repository headline branch rate | root `branch-rate` | `0.790598` | **79.06%** | +| `QuickFiler` package line rate | `QuickFiler` package `line-rate` | `0.81084081028582` | **81.08%** | +| Changed-module rate (`QuickFiler\Controllers\QfcItemController*` classes, aggregated) | per-`` count across the 10 matched classes | 1410 / 1633 | **86.34%** | + +Supporting root counters: `lines-covered="53505"`, `lines-valid="62512"`, +`branches-covered="12580"`, `branches-valid="15912"`. The `QuickFiler` package branch rate is +`0.7502908103916247` (**75.03%**). + +No coverage field above is empty and none carries the token `UNVERIFIED`. + +### All nine packages + +| Package | line-rate | Percent | +| --- | --- | --- | +| QuickFiler | 0.81084081028582 | 81.08% | +| UtilitiesCS | 0.8958155619596542 | 89.58% | +| TaskVisualization | 0.8984326018808777 | 89.84% | +| SVGControl | 0.47303128371089537 | 47.30% | +| ToDoModel | 0.5731056563500534 | 57.31% | +| Tags | 0.9268929503916449 | 92.69% | +| TaskMaster | 0.7335945151811949 | 73.36% | +| TaskTree | 0.9548387096774194 | 95.48% | +| VBFunctions | 1 | 100.00% | + +### Per-class figures for the changed module + +Ten Cobertura classes have a `filename` beginning `QuickFiler\Controllers\QfcItemController` +(`MATCH_COUNT=10`), matching the baseline's match count exactly. Filenames use backslashes because +the script's Koverage post-processing rewrites them; a forward-slash query matches nothing. + +| Filename | line-rate | Percent | branch-rate | +| --- | --- | --- | --- | +| `QuickFiler\Controllers\QfcItemController.cs` | 1 | 100.00% | 0.7857142857142857 | +| `QuickFiler\Controllers\QfcItemController.Initialization.cs` | 0.949612 | 94.96% | 0.90625 | +| `QuickFiler\Controllers\QfcItemController.ViewerSetup.cs` | 0.850829 | 85.08% | 0.677419 | +| `QuickFiler\Controllers\QfcItemController.Conversation.cs` | 0.882353 | 88.24% | 0.944444 | +| `QuickFiler\Controllers\QfcItemController.FolderHandling.cs` | 0.952381 | 95.24% | 0.7 | +| `QuickFiler\Controllers\QfcItemController.EventWiring.cs` | 0.815182 | 81.52% | 0.65 | +| `QuickFiler\Controllers\QfcItemController.EventHandlers.cs` | 0.7865168539325843 | 78.65% | 0.6111111111111112 | +| `QuickFiler\Controllers\QfcItemController.Navigation.cs` | 0.90678 | 90.68% | 0.818182 | +| `QuickFiler\Controllers\QfcItemController.FocusAndTheme.cs` | 0.793249 | 79.32% | 0.691176 | +| `QuickFiler\Controllers\QfcItemController.MailActions.cs` | 0.768 | 76.80% | 0.727273 | + +### Counting method (reproduced from the baseline exactly) + +The aggregate changed-module figure was computed by counting `` elements inside each matched +``, deduplicated by line `number` **within** each class, and summing across the ten classes: +1,633 total lines, 1,410 covered, **86.34%**. This is byte-for-byte the method the baseline artifact +mandates. Cobertura repeats line entries under `` as well as under the class-level `` +element, so an all-descendant count without deduplication roughly doubles the denominator and would +fabricate a coverage delta. The measurement was taken against the **post-processed** XML produced by +the same script that produced the baseline. + +### Attempts + +| Attempt | Timestamp | Outcome | Machine-load state at launch | +| --- | --- | --- | --- | +| 1 (only) | 2026-08-23T19-23 launch, 19-24-41 end | Success. `Test Run Successful`, 6459/6459, `dotnet-coverage` exit 0, post-processing completed. | Idle. Average processor load sampled at 15% immediately before launch; zero `testhost`, `vstest.console`, and `dotnet-coverage` processes resident; the 17 idle MSBuild node-reuse processes left by this cycle's own P3-T4 analyzer build (all with StartTime 19:16:12, i.e. started by this run) were stopped first, per the load lesson recorded in the baseline coverage artifact. | + +The bounded re-run authorization in P3-T7 (up to two additional attempts for a load-induced +60,000 ms `PumpTimeoutMs` expiry in `QuickFiler.Test`, the out-of-scope #592 defect) was **not +exercised**: the first attempt succeeded. Total attempts: 1 of a permitted maximum of 3. + +### Sibling-assembly failures during the coverage run + +**None.** The run reported 6459 total and 6459 passed with zero failures, so no sibling-assembly +failure needed to be listed or attributed to issue #594. + +### Acceptance conditions + +1. The script reported exactly 9 discovered test assemblies — met (`Discovered 9 test assemblies.`). +2. No coverage field is empty or contains the token `UNVERIFIED` — met; all four figures are numeric. +3. The vstest exit code is recorded verbatim — met (0). +4. Every attempt is recorded — met; a single attempt, recorded above. +5. Sibling-assembly failures listed and attributed — vacuously met, there were none. + +The raw Cobertura XML stays in the gitignored `coverage\` directory and is not copied into the +evidence tree. P3-T9 copies it to the gitignored `artifacts/csharp/` producer path for the +downstream review-gate hook. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-csharpier-check.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-csharpier-check.2026-08-23T20-57.md new file mode 100644 index 000000000..aed746aad --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-csharpier-check.2026-08-23T20-57.md @@ -0,0 +1,28 @@ +# Remediation QA Gate — Repo-Wide CSharpier Check (read-only) + +Timestamp: 2026-08-23T19-13 + +Command: +``` +dotnet tool run csharpier check . +``` +(run from the worktree root) + +EXIT_CODE: 0 + +Output Summary: + +``` +Checked 1519 files in 5595ms. +``` + +Unformatted-file count: **0**. CSharpier reported no file as needing formatting across all 1,519 +checked files, so the count is zero both repo-wide and, a fortiori, among the three touched files: + +- `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` — not reported +- `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` — not reported +- `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` — not reported + +Because the unformatted-file count is zero, the question of whether any reported file is a +pre-existing condition outside the three touched files does not arise. The gate's acceptance +condition — no file among the three touched files is reported as unformatted — holds. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-csharpier-format.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-csharpier-format.2026-08-23T20-57.md new file mode 100644 index 000000000..84a9ffb51 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-csharpier-format.2026-08-23T20-57.md @@ -0,0 +1,33 @@ +# Remediation QA Gate — Scoped CSharpier Format + +Timestamp: 2026-08-23T19-12 + +Command: +``` +dotnet tool run csharpier format QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs +``` +(run from the worktree root; the mutating pass is deliberately scoped to the three touched files — +a repo-wide `format .` would rewrite unrelated files and break the three-file scope lock) + +EXIT_CODE: 0 + +Output Summary: + +Console output: `Formatted 3 files in 1774ms.` + +That console line is CSharpier 1.x's **processed**-file count, not a rewrite count: it reads 3 +whatever the formatter did, so a restart rule keyed on it would never terminate. The rewritten-file +count below is therefore derived from SHA-256 hashes captured immediately before and immediately +after the `format` invocation. + +| File | SHA-256 before | SHA-256 after | Rewritten | +| --- | --- | --- | --- | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` | `5002CA0E5BEDF06708F020F16E654AB4490576BE025F1DEB83048BA9CC14A31A` | `5002CA0E5BEDF06708F020F16E654AB4490576BE025F1DEB83048BA9CC14A31A` | no | +| `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | `2A65D8472AF261AE63F3A7A87D08AB3BDEB3B7434D9201132C64FB5F1B6863FA` | `2A65D8472AF261AE63F3A7A87D08AB3BDEB3B7434D9201132C64FB5F1B6863FA` | no | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` | `9BCABD8824031B25DEE81880CD9E226F29AEF82CFDB05D0CE9F38B987E2EC7AC` | `9BCABD8824031B25DEE81880CD9E226F29AEF82CFDB05D0CE9F38B987E2EC7AC` | no | + +**Hash-derived rewritten-file count: 0.** + +The Phase 1 comment corrections were authored at the same wrap width and indentation CSharpier +produces, so the formatter changed nothing. Because the rewritten-file count is 0, no loop restart +from P3-T1 is triggered by this task. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-file-size-audit.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-file-size-audit.2026-08-23T20-57.md new file mode 100644 index 000000000..f3a857e91 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-file-size-audit.2026-08-23T20-57.md @@ -0,0 +1,30 @@ +# Remediation QA Gate — 500-Line Cap Re-Audit After the Final Formatting Pass + +Timestamp: 2026-08-23T19-29 + +Command: +```powershell +foreach ($f in @( + "QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs", + "QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs", + "QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs")) { + Write-Output ("{0} {1}" -f $f, (Get-Content -LiteralPath $f).Count) +} +``` +(run from the worktree root, after the P3-T2 scoped `csharpier format` and the P3-T3 repo-wide +`csharpier check`) + +EXIT_CODE: 0 + +Output Summary: + +| File | Line count | Headroom against the 500-line cap | Under the cap | +| --- | --- | --- | --- | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` | **418** | 82 | yes | +| `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | **474** | 26 | yes | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` | **398** | 102 | yes | + +This re-audit exists because CSharpier can add lines. It did not: the P3-T2 hash comparison recorded +a rewritten-file count of 0, so all three counts are unchanged from the P1-T3 post-edit measurement +(418, 474, 398). Each of the three recorded counts is less than 500, satisfying the general +code-change file-size limit. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-nullable-gate.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-nullable-gate.2026-08-23T20-57.md new file mode 100644 index 000000000..7cc2c6842 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-nullable-gate.2026-08-23T20-57.md @@ -0,0 +1,62 @@ +# Remediation QA Gate — Nullable / Warnings-As-Errors Gate + +Timestamp: 2026-08-23T19-18 + +Command: +``` +& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true +``` + +Run from the worktree root. Launched per the Phase 3 long-running command mechanic: a detached +`pwsh -NoProfile` runner invoked `Start-Process -PassThru` with `-RedirectStandardOutput +coverage\nullable-remediation.log` and `-RedirectStandardError coverage\nullable-remediation.err.log`, +recorded the child PID, then polled to completion. The recorded exit code is taken from the returned +process object's `ExitCode` property, not from `$LASTEXITCODE` of the polling shell. + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | Required | +| --- | --- | --- | +| Resolved msbuild path | `C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe` | recorded | +| Launched PID (`MSBuild.exe` child) | **90916** | recorded | +| Exit code (from the process object's `ExitCode`) | **0** | 0 | +| Error count | **0** | 0 | +| Warning count | 5 | not gated | +| Log lines matching `Skipping target "CoreCompile"` | **0** | exactly 0 | +| Log lines matching `CoreCompile:` (target actually executed) | 78 | corroboration only | +| Occurrences of `p:Nullable=enable` anywhere in the log | **0** | must be 0 | +| Log file | `coverage\nullable-remediation.log` (11,939 lines) | — | +| Wall time | 00:00:17.32 | — | + +MSBuild summary block, verbatim: + +``` + 5 Warning(s) + 0 Error(s) + +Time Elapsed 00:00:17.32 +``` + +## Acceptance conditions + +1. **`EXIT_CODE: 0`, taken from the process object's `ExitCode`** — met. +2. **The artifact records the resolved msbuild path** — met. +3. **Error count is 0** — met. No `CS86xx` nullable-flow diagnostic was promoted to an error in any + file that carries a `#nullable enable` directive. +4. **`Skipping target "CoreCompile"` count is exactly 0** — met, corroborated by 78 `CoreCompile:` + target executions. `/t:Rebuild` is used, never `/t:Build`, because MSBuild's up-to-date check + does not invalidate on a command-line `/p:` change and a warm `/t:Build` would return exit 0 + having compiled nothing. +5. **The command carried no `/p:Nullable=enable`** — confirmed. The property appears nowhere in the + command line above and matches zero lines of the build log. This is deliberate: no project in + this repository carries a `` element and there is no `Directory.Build.props`, so the + property is a solution-wide opt-in that conscripts every file which never adopted the pragma, and + `.github/workflows/ci.yml` omits it. The command above is character-for-character the CI step + "Build with nullable warnings treated as errors". + +The 5 warnings are the same pre-existing `System.Reactive.PackagesConfigCheck.targets` diagnostic +recorded in the analyzer gate. `/p:TreatWarningsAsErrors=true` did not promote them to errors, which +matches the baseline recorded in +`docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nullable-gate.2026-08-21T18-10.md`. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md new file mode 100644 index 000000000..e2daf8c71 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md @@ -0,0 +1,119 @@ +# Remediation QA Gate — Full Nine-Assembly Suite Run + +Timestamp: 2026-08-23T19-21 + +Command: +``` +& 'C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe' ` + QuickFiler.Test\bin\Debug\QuickFiler.Test.dll ` + SVGControl.Test\bin\Debug\SVGControl.Test.dll ` + Tags.Test\bin\Debug\Tags.Test.dll ` + TaskMaster.Test\bin\Debug\TaskMaster.Test.dll ` + TaskTree.Test\bin\Debug\TaskTree.Test.dll ` + TaskVisualization.Test\bin\Debug\TaskVisualization.Test.dll ` + ToDoModel.Test\bin\Debug\ToDoModel.Test.dll ` + UtilitiesCS.Test\bin\Debug\UtilitiesCS.Test.dll ` + VBFunctions.Test\bin\Debug\VBFunctions.Test.dll ` + /EnableCodeCoverage /InIsolation /Logger:trx ` + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/r1-p3-t6 ` + /TestCaseFilter:"TestCategory!=LiveOutlook" +``` + +Run from the worktree root, invoked through `pwsh -NoProfile` and launched per the Phase 3 +long-running command mechanic: a detached `pwsh -NoProfile` runner invoked `Start-Process -PassThru` +with `-RedirectStandardOutput coverage\suite-remediation.log` and `-RedirectStandardError +coverage\suite-remediation.err.log`, recorded the child PID, then polled to completion. The recorded +exit code is taken from the returned process object's `ExitCode` property. + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | Required | +| --- | --- | --- | +| Launched PID (`vstest.console.exe` child) | **61900** | recorded | +| Exit code (from the process object's `ExitCode`) | **0** | recorded | +| Total tests | **6459** | at least 6,000 | +| Passed | **6459** | — | +| Failed | **0** | — | +| Skipped / not executed | **0** | — | +| TRX files in the results subdirectory | **1** | exactly 1 | +| `QuickFiler.Test` failed count | **0** | exactly 0 | +| Wall time | 51.7069 s | — | +| Log file | `coverage\suite-remediation.log` (6,473 lines) | — | + +vstest summary block, verbatim: + +``` +Test Run Successful. +Total tests: 6459 + Passed: 6459 + Total time: 51.7069 Seconds +``` + +TRX `ResultSummary/Counters`, verbatim: + +``` + +``` + +## TRX path + +`docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/r1-p3-t6/__2026-08-23_19_20_16_net481.trx` + +The leading two segments of the filename are the default `vstest.console.exe` TRX naming, which +embeds the account and machine name. They are redacted here as `` and `` per the +repository's host-identifier hygiene rule. The whole `r1-p3-t6/` subdirectory is excluded by the +evidence `.gitignore` line `r1-p*-t*/` appended by P0-T9, and its contents are deleted by P4-T10. + +## All nine assemblies loaded + +The TRX `TestDefinitions` reference all nine expected assemblies, confirming none was silently +dropped: + +| Assembly | Passed | Failed | +| --- | --- | --- | +| `QuickFiler.Test.dll` | 925 | 0 | +| `SVGControl.Test.dll` | 75 | 0 | +| `Tags.Test.dll` | 65 | 0 | +| `TaskMaster.Test.dll` | 367 | 0 | +| `TaskTree.Test.dll` | 51 | 0 | +| `TaskVisualization.Test.dll` | 163 | 0 | +| `ToDoModel.Test.dll` | 122 | 0 | +| `UtilitiesCS.Test.dll` | 4690 | 0 | +| `VBFunctions.Test.dll` | 1 | 0 | +| **Total** | **6459** | **0** | + +The mass-failure signature that indicates a missing `/InIsolation` — roughly 1,695 failures with +empty messages and sub-millisecond durations — did not occur. `/InIsolation` was present and the +run needed no correction or re-run. + +## The four owned named tests + +| Test | Outcome | +| --- | --- | +| `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` | Passed | +| `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` | Passed | +| `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` | Passed | +| `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` | Passed | + +## Sibling-assembly failures + +**None.** The `UtilitiesCS.Test` assembly reported 4,690 passed and 0 failed in this run, so the +three pre-existing flakes tracked as issue #594 did not fire. No failure outside `QuickFiler.Test` +needed to be listed or attributed. The suite was run on an otherwise idle machine, which is the +condition under which those flakes do not reproduce; they remain a real, separately tracked risk +under load and are not claimed repaired by this cycle. + +## Acceptance conditions + +1. `EXIT_CODE:` taken from the process object's `ExitCode` — met, value 0. +2. The subdirectory holds exactly one TRX file — met. +3. Total is at least 6,000, confirming all nine assemblies loaded — met, 6,459 across nine + assemblies. +4. `QuickFiler.Test` failed count is exactly 0 — met. +5. All four owned named tests recorded as passed — met. +6. Every failure outside `QuickFiler.Test` listed and attributed to issue #594 — vacuously met, + there were none. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-tool-restore.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-tool-restore.2026-08-23T20-57.md new file mode 100644 index 000000000..84f22261d --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-tool-restore.2026-08-23T20-57.md @@ -0,0 +1,25 @@ +# Remediation QA Gate — `dotnet tool restore` + +Timestamp: 2026-08-23T19-11 + +Command: +``` +dotnet tool restore +``` +(run from the worktree root `.claude/worktrees/agent-ad37a256a0fb60243`) + +EXIT_CODE: 0 + +Output Summary: + +``` +Tool 'csharpier' (version '1.2.6') was restored. Available commands: csharpier + +Restore was successful. +``` + +Restored CSharpier version: **1.2.6**, matching the pin in the worktree-root manifest +`dotnet-tools.json` (`"csharpier": { "version": "1.2.6", "rollForward": false }`). The manifest sits +at the worktree root, not under `.config/`. All later formatting steps in this phase invoke +CSharpier through `dotnet tool run` so this manifest-pinned version is the one used, matching +`.github/workflows/ci.yml`. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/consumer-tests.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/consumer-tests.2026-08-21T18-10.md new file mode 100644 index 000000000..fc0dee62b --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/consumer-tests.2026-08-21T18-10.md @@ -0,0 +1,52 @@ +# P3-T5 — Pump-Hosted Consumer Tests + +Timestamp: 2026-08-22T10-36 + +Command: +``` +vstest.console.exe QuickFiler.Test\bin\Debug\QuickFiler.Test.dll /InIsolation /Logger:trx ` + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t5 ` + /TestCaseFilter:"FullyQualifiedName~ThroughThePumpHost|FullyQualifiedName~WithFaultingWebViewSeam|FullyQualifiedName~WithInjectedSeams" +``` + +EXIT_CODE: 0 + +Output Summary: + +TRX: `evidence/regression-testing/p3-t5/2026-08-22_10_36_21_net481.trx` + +TRX `` verbatim: + +``` +total="8" executed="8" passed="8" failed="0" error="0" timeout="0" aborted="0" +inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" +``` + +| # | Test | Outcome | Duration | +| --- | --- | --- | --- | +| 1 | `InitializeSequentialAsync_ThroughThePumpHost_CompletesAndInitializesState` | Passed | 1 s | +| 2 | `InitializeGraphicsAsync_ThroughThePumpHost_CompletesAndAppliesDarkTheme` | Passed | 132 ms | +| 3 | `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` | Passed | 146 ms | +| 4 | `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` | Passed | 164 ms | +| 5 | `InitializeAsync_ThroughThePumpHost_RunsToTheMockedWebViewSeamAndFaults` | Passed | 515 ms | +| 6 | `ResolveControlGroupsAsync_ThroughThePumpHost_PopulatesTipsAndControlGroups` | Passed | 108 ms | +| 7 | `CreateSequentialAsync_WithInjectedSeams_ReturnsAnInitializedController` | Passed | 111 ms | +| 8 | `CreateAsync_WithFaultingWebViewSeam_FaultsWithThatExceptionAfterInitializing` | Passed | 128 ms | + +Acceptance: recorded failed count is **0**; recorded executed count is **8**, which is at least 8. + +## Note on the anticipated side effect + +The task anticipates that forcing the handle flips `Theme.cs:433` `_lblItemNumber.InvokeRequired` +and `ViewerSetup.cs:361` `_itemViewer.InvokeRequired` from `false` to `true` on off-pump evaluation, +so those paths marshal instead of running inline. + +That flip is not observable as a behavioural change here, and the measurement in +`webview-child-handle-measurement.2026-08-21T18-10.md` explains why: the viewer's window handle was +already being created before the Phase 2 change, as a side effect of the two WebView2 children's +`ISupportInitialize.EndInit()` calls during `ItemViewer` construction. `InvokeRequired` on an +off-pump thread was therefore already `true` for a harness viewer, and those paths were already +marshalling. What the Phase 2 change removes is the dependency on that third-party side effect +occurring, not the marshalling behaviour itself. + +All eight tests pass either way, so no consumer regression is recorded. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md new file mode 100644 index 000000000..39469d4f3 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md @@ -0,0 +1,119 @@ +# P4-T6 — Consolidated Determinism Record (Ten Runs Under Load) + +Timestamp: 2026-08-22T14-40 + +## The ten TRX paths + +All ten sit in the task-private subdirectory +`docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`, +which holds exactly ten `.trx` files and no other file. (`vstest.console.exe /EnableCodeCoverage` +additionally creates one attachment directory per run alongside them; the same structure is present +in the Phase 1 `p1-t3` and `p1-t4` subdirectories.) + +1. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_11_53_56_net481.trx` +2. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_12_12_50_net481.trx` +3. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_12_30_40_net481.trx` +4. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_12_37_28_net481.trx` +5. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_12_53_39_net481.trx` +6. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_13_10_45_net481.trx` +7. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_13_17_44_net481.trx` +8. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_13_32_03_net481.trx` +9. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_13_39_20_net481.trx` +10. `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/2026-08-22_14_03_59_net481.trx` + +## Per-run record + +Durations are the TRX `Times` finish-minus-start span. MSBuild node counts were sampled immediately +before and immediately after each `vstest.console.exe` invocation. + +| # | Total | Passed | Failed | Not executed | Duration (s) | MSBuild nodes before / after | +| --- | --- | --- | --- | --- | --- | --- | +| 1 | 6439 | 6439 | 0 | 0 | 1153.8 | 0 / 0 | +| 2 | 6439 | 6439 | 0 | 0 | 1063.8 | 0 / 0 | +| 3 | 6439 | 6439 | 0 | 0 | 399.7 | 0 / 0 | +| 4 | 6439 | 6439 | 0 | 0 | 960.0 | 0 / 0 | +| 5 | 6439 | 6438 | **1** | 0 | 1021.7 | 0 / 0 | +| 6 | 6439 | 6439 | 0 | 0 | 414.4 | 0 / 0 | +| 7 | 6439 | 6439 | 0 | 0 | 849.5 | 0 / 0 | +| 8 | 6439 | 6439 | 0 | 0 | 430.2 | 0 / 0 | +| 9 | 6439 | 6439 | 0 | 0 | 1471.9 | 0 / 0 | +| 10 | 6439 | 6439 | 0 | 0 | 1273.2 | 0 / 0 | + +Total is 6439 in every run: the 6437 of the P0-T15 baseline plus the two regression tests added by +P1-T1 and P3-T1. + +## Sustained CPU utilization + +| Point | Timestamp | Samples | Mean | +| --- | --- | --- | --- | +| P4-T1, before run 1 | 2026-08-22T11-53 | `100`, `100`, `100`, `100`, `100` | **100.00** | +| P4-T3, after run 10 | 2026-08-22T14-24 | `99.94`, `100`, `100`, `100`, `100` | **99.99** | + +23 load jobs (`ProcessorCount - 1`, `ProcessorCount = 24`) ran for the whole window. Every run took +between 399.7 s and 1471.9 s against a measured unloaded baseline of 55.4 s to 70.0 s for the same +command in P1-T4, that is between 6x and 26x slower, which corroborates sustained contention across +the window rather than only at its ends. + +## Pre-fix and post-fix, side by side, measured values only + +| Test | Pre-fix (P1-T5, 20 runs, unloaded) | Post-fix (P4-T2, 10 runs, 100% CPU load) | +| --- | --- | --- | +| `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` | Passed 20 / 20 | Passed **10 / 10** | +| `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` | Passed 20 / 20 | Passed **10 / 10** | +| `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` | Passed 20 / 20 | Passed **10 / 10** | +| `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` | not authored until P3-T1 | Passed **10 / 10** | +| Suite-wide failed count | 0 in each of the 20 runs | 0 in 9 of 10 runs; **1** in run 5 | + +The pre-fix column is drawn from `prefix-baseline.2026-08-21T18-10.md`; the post-fix column from +`named-tests-ten-runs.2026-08-21T18-10.md` and `regression-tests-ten-runs.2026-08-21T18-10.md`. + +### What the comparison does and does not establish + +It does **not** establish a fail-before / pass-after transition for the two named tests, because the +pre-fix measurement recorded no failure in either of them across its twenty runs. That was recorded +at the time and is not restated here as anything stronger. + +What it does establish is that both named tests, and both regression tests, held under sustained +100% CPU saturation for ten consecutive full-suite runs totalling roughly two and a half hours, at +6x to 26x the unloaded run duration, with `PumpTimeoutMs = 60000` unchanged and no sleep, retry, or +timing tolerance anywhere in the change. + +One genuine pre-fix failure of both named tests was observed in this execution, outside the +twenty-run pre-fix table: the second P0-T16 coverage invocation reported 6430 / 6437 with seven +60,000 ms `PumpTimeoutMs` expiries including both named tests. Its distinguishing condition was +17 idle MSBuild node-reuse processes, which the ten runs above did not carry. That gap is closed +separately in `supplementary-msbuild-node-contention-ten-runs.2026-08-21T18-10.md`. + +## Recorded failure — P4-T2's acceptance condition is not met + +P4-T2 requires that each of the ten TRX files record a failed count of exactly 0. **Run 5 records +`failed="1"`, so P4-T2's acceptance condition is not met and the task is not checked off.** + +The failing test is: + +``` +UtilitiesCS.Test.Extensions.DfDeedle_COM_Tests.GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform +System.NullReferenceException: Object reference not set to an instance of an object. +duration 00:00:26.1779280 +``` + +Four facts about it are recorded rather than argued: + +1. It is in `UtilitiesCS.Test`, a different assembly from the one this change touches. Nothing in + this change's diff reaches it: the diff is confined to three files under + `QuickFiler.Test/Controllers/`. +2. It is not a `[Timeout]` expiry and is not a pump-harness test. It is a `NullReferenceException` + in a Deedle data-frame test, unrelated to window handles, the WinForms pump, or the dispatcher + gate. +3. It passed in the other nine runs of this window, in all twenty pre-fix runs of P1-T3 and P1-T4, + and in the P0-T15 baseline. +4. All four tests this plan tracks passed in run 5. + +The run was **not** repeated to obtain a tenth green result. The plan forbids doing so without +recording every attempt, and the honest record is that ten runs were executed and one of them +recorded one failure in an out-of-scope assembly. + +The disposition of that failure — whether it is a pre-existing latent defect in +`DfDeedle_COM_Tests` that saturation exposes, and whether P4-T2's absolute-zero condition over the +whole nine-assembly suite is the right gate for a change scoped to three `QuickFiler.Test` files — +is escalated to the caller rather than decided here. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-comment-fix.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-comment-fix.2026-08-23T20-57.md new file mode 100644 index 000000000..87d657192 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-comment-fix.2026-08-23T20-57.md @@ -0,0 +1,33 @@ +# File-Size Cap Re-Audit After the Phase 1 Comment Corrections + +Timestamp: 2026-08-23T19-02 + +Command: +```powershell +foreach ($f in @( + "QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs", + "QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs", + "QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs")) { + Write-Output ("{0} {1}" -f $f, (Get-Content -LiteralPath $f).Count) +} +``` + +EXIT_CODE: 0 + +Output Summary: + +| File | P0-T7 count | Post-edit count | Delta | Under the 500-line cap | +| --- | --- | --- | --- | --- | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` | 416 | 418 | +2 | yes | +| `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | 470 | 474 | +4 | yes | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` | 398 | 398 | 0 | yes | + +The two deltas are exactly the comment-block growth the plan specifies: P1-T1 replaced 5 comment +lines with 7 (+2) and P1-T2 replaced 2 comment lines with 6 (+4). No executable line was added, +moved, or removed in either file; both `viewer.Handle` read statements are retained per orchestrator +Decision 2. + +`QfcItemController.InitializationTests.Part3.cs` is unchanged from its P0-T7 count of 398, confirming +Phase 1 touched only the two comment sites. + +All three post-edit counts are less than 500, so the general-code-change file-size limit holds. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-fixture-change.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-fixture-change.2026-08-21T18-10.md new file mode 100644 index 000000000..9bce54af7 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-fixture-change.2026-08-21T18-10.md @@ -0,0 +1,31 @@ +# P2-T4 — File-Size Budget After the Phase 2 Fixture Change + +Timestamp: 2026-08-22T10-19 + +Command: +``` +(Get-Content -LiteralPath QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs).Count +(Get-Content -LiteralPath QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs).Count +(Get-Content -LiteralPath QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs).Count +``` + +EXIT_CODE: 0 + +Output Summary: + +| File | Pre-change (P0-T7 baseline) | Post-change | Delta | Under 500 | +| --- | --- | --- | --- | --- | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` | 409 | **416** | +7 (P2-T1 comment + statement) | yes | +| `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | 467 | **470** | +3 (P2-T3 comment + statement) | yes | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` | 290 | **339** | +49 (P1-T1 probe test, added in Phase 1) | yes | + +Acceptance: + +- All three post-change counts are less than 500. +- `QfcItemController.ViewerSetupTests.cs` is recorded at 470 lines, which is at or below the + 475-line ceiling this task states. + +Note on `Part3.cs`: the plan's pre-change budget table records 290 lines. Phase 1 (P1-T1) already +added the `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` probe, so the count +observed at the start of Phase 2 was 339. Phase 2 made no edit to this file; P3-T1 adds the second +regression test and P3-T2 re-measures it. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-part3.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-part3.2026-08-21T18-10.md new file mode 100644 index 000000000..ca9965138 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-part3.2026-08-21T18-10.md @@ -0,0 +1,40 @@ +# P3-T2 — `Part3.cs` Line Count After Both Regression Tests + +Timestamp: 2026-08-22T10-35 + +Command: +``` +(Get-Content -LiteralPath QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs).Count +``` + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | +| --- | --- | +| Pre-change count (P0-T7 baseline, before Phase 1) | **290** | +| After P1-T1 (`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`) | 339 (+49) | +| Post-change count, after P3-T1 (`BuildPumpHarness_DoesNotCreateTheWebViewChildHandles`) | **398** (+59) | +| 500-line cap | 398 < 500 — **holds**, 102 lines of headroom remain | + +Acceptance: the recorded post-change count of 398 is less than 500. + +Line-number stability re-verified in the same measurement (spec AC 1 and AC 2 cite these): + +| Method | Declaration line | +| --- | --- | +| `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` | **131** | +| `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` | **175** | +| `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` (P1-T1) | 301 | +| `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` (P3-T1) | 356 | + +Both new tests were appended after the last existing method, so neither pre-existing declaration +line moved. + +`dotnet tool run csharpier check .` reports `Checked 1517 files` with exit code 0, so the recorded +count is the formatter-stable count and no later format step will change it. + +Note: the +59 delta for P3-T1 includes the corrected `` block recording the measurement +described in `webview-child-handle-measurement.2026-08-21T18-10.md`. The first draft of the method +was 53 lines; the corrected form is 59. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-serialization.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-serialization.2026-08-21T18-10.md new file mode 100644 index 000000000..a75bd8ec9 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-serialization.2026-08-21T18-10.md @@ -0,0 +1,55 @@ +# P3-T7 — Cross-Class `UiThreadDispatcherGate` Serialization + +Timestamp: 2026-08-22T10-37 + +Command: +``` +vstest.console.exe QuickFiler.Test\bin\Debug\QuickFiler.Test.dll /InIsolation /Logger:trx ` + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t7 ` + /TestCaseFilter:"FullyQualifiedName~QfcItemController_SeamFactoryTests|FullyQualifiedName~QfcItemController_InitializationTests" +``` + +Both classes run in the **same** invocation, so class-level parallelization exercises the shared +process-wide `UiThreadDispatcherGate`. + +EXIT_CODE: 0 + +Output Summary: + +TRX: `evidence/regression-testing/p3-t7/2026-08-22_10_37_42_net481.trx` + +TRX `` verbatim: + +``` +total="20" executed="20" passed="20" failed="0" error="0" timeout="0" aborted="0" +inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" +``` + +| Class | Tests in run | Passed | Failed | +| --- | --- | --- | --- | +| `QfcItemController_InitializationTests` | 11 | **11** | 0 | +| `QfcItemController_SeamFactoryTests` | 9 | **9** | 0 | +| Total | 20 | **20** | 0 | + +Total wall-clock duration: **4.7090 seconds**. + +Acceptance: + +- Recorded failed count is **0**. +- Both class names appear in the TRX with at least one passed test each (11 and 9 respectively). +- No test is recorded as failing on its `[Timeout]`: the TRX carries `timeout="0"` and zero + `outcome="Timeout"` results. The four longest tests in the run are + `InitializeSequentialAsync_ThroughThePumpHost_CompletesAndInitializesState` (1 s), + `InitializeAsync_ThroughThePumpHost_RunsToTheMockedWebViewSeamAndFaults` (411 ms), + `PrimaryConstructor_AssignsFieldsAndSetsControllerBackReference` (306 ms) and + `InitializeGraphicsAsync_ThroughThePumpHost_CompletesAndAppliesDarkTheme` (202 ms), all far below + the 60,000 ms `PumpTimeoutMs`. + +The gate cascade the task warns about did not occur. The acquire-and-release structure verified +statically in P2-T2 is confirmed here at runtime: `QfcItemController_SeamFactoryTests` acquires the +same gate through the `internal static BuildPumpHarnessAsync` wrapper, and every fixture released it +via `PumpHarness.Restore`, so no class starved the other. + +Both new regression tests ran inside this two-class invocation and passed: +`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` (101 ms) and +`BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` (90 ms). diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-structure-part2.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-structure-part2.2026-08-21T18-10.md new file mode 100644 index 000000000..acfa17b0f --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-structure-part2.2026-08-21T18-10.md @@ -0,0 +1,36 @@ +# P2-T2 — `Part2.cs` Gate-Structure Invariants After the Fixture Change + +Timestamp: 2026-08-22T10-19 + +Command: +``` +grep -n "UiThreadDispatcherGate\|SwapUiThreadDispatcher\|_restored" QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs +git diff --numstat -- QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs +wc -l QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs +``` + +EXIT_CODE: 0 + +Output Summary: + +All four invariants hold after the P2-T1 edit. The edit is a pure 7-line insertion +(`git diff --numstat` reports `7 0`), so no existing line of the file changed. + +| # | Invariant | Observed | Verdict | +| --- | --- | --- | --- | +| 1 | `UiThreadDispatcherGate` declared as `SemaphoreSlim(1, 1)` | line 51: `private static readonly SemaphoreSlim UiThreadDispatcherGate = new SemaphoreSlim(1, 1);` | HOLDS | +| 2 | `BuildPumpHarnessAsync` calls `UiThreadDispatcherGate.WaitAsync` before delegating, and `UiThreadDispatcherGate.Release` in its `catch` | line 67 `await UiThreadDispatcherGate.WaitAsync().ConfigureAwait(false);` precedes the line 70 delegation to `BuildPumpHarnessCoreAsync`; line 74 `UiThreadDispatcherGate.Release();` sits inside the `catch` block | HOLDS | +| 3 | `PumpHarness.Restore` calls `UiThreadDispatcherGate.Release` exactly once behind the `_restored` guard | field `_restored` at line 307; guard `if (_restored) { return; }` at lines 340-343; `_restored = true;` at line 345; a single `UiThreadDispatcherGate.Release();` at line 348 | HOLDS | +| 4 | File line count < 500 | 416 | HOLDS | + +Post-edit line count: **416** (pre-change 409, +7). + +Cross-class serialization is therefore intact: `QfcItemController_SeamFactoryTests` reaching +`BuildPumpHarnessAsync` still acquires the same process-wide gate, and the acquire-and-release +structure is unchanged. P3-T7 exercises both classes in one invocation as the runtime proof. + +Line indices relevant to the inserted statement (P2-T1): + +- viewer construction: line 84 +- inserted `_ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false);`: line 92 +- `SwapUiThreadDispatcher(viewer.UiDispatcher)` call: line 136 diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/intermittency-question.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/intermittency-question.2026-08-21T18-10.md new file mode 100644 index 000000000..5f6a57ade --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/intermittency-question.2026-08-21T18-10.md @@ -0,0 +1,139 @@ +# Phase 1 — Disposition of the Open Intermittency Question (P1-T6) + +Timestamp: 2026-08-22T10-28 + +The plan carried one open question into Phase 1 and required it to be settled by execution rather than +by static reading. This artifact records what the measured data supports, what it rules out, and what +remains open. It does not close the question by assertion; every sentence below that claims a mechanism +cites an observation. + +## The question as posed + +Static reading predicted that both named tests should fail on **every** run: `Control.Invoke` throws +unconditionally without a created handle, and the research found no handle-creating call anywhere in +the `ResolveControlGroups` then `SetupThemes` then `PopulateControls` path. Issue #571 nevertheless +recorded the tests passing on some runs. Two candidate explanations were carried forward: + +- **Candidate A** — the traced initialization sequence really does lack a handle-creating call, and + some path *outside* that traced sequence creates the handle. The plan named third-party + `Microsoft.Web.WebView2.WinForms.WebView2` `ISupportInitialize` or implicit-initialization behaviour + as the prime suspect, noting its source is not present in this repository. +- **Candidate B** — the handle is genuinely absent, and the tests fail whenever the initialization path + is reached, so any passing run would have to be explained some other way. + +## What the measured data supports + +**Candidate A is supported. Candidate B is ruled out.** + +The P1-T5 table records twenty runs — rows 1 through 10 class-filtered, rows 11 through 20 full +nine-assembly suite. **Every one of those twenty rows records +`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` as `Passed` and therefore +`IsHandleCreated: true`.** Naming the runs as the task requires: the probe reported +`IsHandleCreated: true` on P1-T5 rows 1, 2, 3, 4, 5, 6, 7, 8, 9, and 10 (class-filtered runs 1 through +10) and on rows 11, 12, 13, 14, 15, 16, 17, 18, 19, and 20 (full-suite runs 1 through 10) — that is, +on all twenty pre-fix runs. + +Because the probe asserts `harness.Viewer.IsHandleCreated` is `true` **and** that +`harness.Viewer.InvokeRequired` evaluated on the pump thread is `false`, those twenty observations +establish two things about the pre-fix code: + +1. The viewer's window handle **did exist** by the time `BuildPumpHarnessAsync` returned, on every one + of the twenty runs. Candidate B, which requires the handle to be absent, is therefore ruled out for + these runs. +2. The handle was owned by the **pump thread**, not by some other thread, on every one of the twenty + runs. `InvokeRequired` returning `false` when evaluated on the pump thread is what establishes + this. + +Since the research's traced `ResolveControlGroups` then `SetupThemes` then `PopulateControls` sequence +contains no handle-creating call, and the handle nevertheless existed on all twenty runs, **some path +outside that traced initialization sequence created the handle.** That inference rests directly on the +twenty `IsHandleCreated: true` observations in the P1-T5 table. + +## The prime suspect, and why it remains unverified + +The plan named third-party WebView2 `ISupportInitialize` or implicit-initialization behaviour as the +unverified prime suspect. This execution found structural evidence consistent with that route, which +raises its plausibility without confirming it. + +The harness constructs its viewer with `new QuickFiler.ItemViewer()` on the pump thread +(`QfcItemController.InitializationTests.Part2.cs`, inside `BuildPumpHarnessCoreAsync`, at the line +reading `QuickFiler.ItemViewer viewer = await host.InvokeAsync(() => new QuickFiler.ItemViewer())`). +That constructor runs `InitializeComponent()`, and `QuickFiler/Viewers/ItemViewer.Designer.cs` routes +both WebView2 children plus one further control through the `ISupportInitialize` protocol: + +``` +89: ((System.ComponentModel.ISupportInitialize)(this._l0v2h2_WebView2)).BeginInit(); +90: ((System.ComponentModel.ISupportInitialize)(this._l0vhBreadcrumb_WebView2)).BeginInit(); +92: ((System.ComponentModel.ISupportInitialize)(this._topicThread)).BeginInit(); +... +6166: ((System.ComponentModel.ISupportInitialize)(this._l0v2h2_WebView2)).EndInit(); +6167: ((System.ComponentModel.ISupportInitialize)(this._l0vhBreadcrumb_WebView2)).EndInit(); +6170: ((System.ComponentModel.ISupportInitialize)(this._topicThread)).EndInit(); +``` + +(Line numbers re-derived in this worktree rather than taken from any prior citation.) + +This places an `ISupportInitialize` `BeginInit`/`EndInit` pair on the WebView2 children **inside the +constructor** — that is, genuinely outside the traced `ResolveControlGroups` / `SetupThemes` / +`PopulateControls` sequence, which is where the inference above says the handle creation must live. + +**This does not verify the mechanism, and the question is not closed.** What remains open: + +- The `Microsoft.Web.WebView2.WinForms.WebView2` implementation of `EndInit` is third-party and its + source is **not present in this repository**, so whether it creates a parent window handle cannot be + read here. The correlation is structural and positional only. +- `_topicThread` also goes through the same protocol, so the designer evidence does not isolate the + WebView2 controls as the responsible participant even if the `ISupportInitialize` route is the right + one. +- No experiment in this execution attributed handle creation to any specific call. Doing so would + require instrumenting or bisecting the constructor, which is outside this plan's scope and is not + required by any task in it. + +## The one pre-fix failure observed in this execution, and what it does and does not show + +A run in which **both named tests failed** was observed during P0-T16 and is recorded in +`evidence/baseline/coverage.2026-08-21T18-10.md`: the second invocation of +`scripts/vscode/Invoke-MSTestWithCoverage.ps1` reported `Total tests: 6437, Passed: 6430, Failed: 7, +Test Run Failed.`, with all seven failures being 60,000 ms `PumpTimeoutMs` expiries and both +`InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` and +`InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` among them. + +That run is deliberately **not** among the twenty P1-T5 rows, because it is neither a P1-T3 +class-filtered run nor a P1-T4 full-suite run and used a different harness (`dotnet-coverage` +instrumentation rather than plain `vstest.console.exe /EnableCodeCoverage`). + +What it shows: the failure mode is **reachable** on this machine against the pre-fix code, so the zero +failure rate in the twenty-row table is not evidence that the defect cannot occur. + +What it does **not** show: the mechanism. The probe did not run in that invocation's failing set in a +readable way, so no `IsHandleCreated` value is available for it, and the failures were timeouts rather +than the `Control.Invoke` handle exception the static reading predicts. A 60-second timeout is +consistent with more than one cause — a handle-less control is one, and pump starvation under load is +another — and this execution did not distinguish them. That ambiguity is recorded, not resolved. + +The only environmental difference between that failing invocation and the passing invocations +immediately before and after it was machine load: 17 idle MSBuild node-reuse processes from the P0-T13 +and P0-T14 builds were resident during it and were stopped before the next invocation, which passed. No +stray `testhost`, `vstest.console`, or `dotnet-coverage` process belonging to another agent was present +at any point, so a competing test runner is ruled out as the cause. + +## Summary of disposition + +| Item | Status | +| --- | --- | +| Candidate A (handle created outside the traced sequence) | **Supported** by twenty `IsHandleCreated: true` observations (P1-T5 rows 1 through 20) | +| Candidate B (handle genuinely absent) | **Ruled out** for all twenty measured runs | +| WebView2 `ISupportInitialize` as the responsible route | **Remains open** — named as the prime suspect, plausibility raised by the designer evidence, source not in this repository, not verified | +| Which specific call creates the handle | **Remains open** — not investigated; outside plan scope | +| Whether the observed 60-second timeouts share the same root cause as the handle question | **Remains open** — timeout is consistent with both a handle-less control and load-induced pump starvation | +| Measured pre-fix failure rate across the twenty planned runs | **0 / 20**, recorded as measured | +| Reachability of the failure mode against pre-fix code | **Demonstrated once**, outside the twenty-row table, under added machine load | + +## Effect on the remedy — none + +Per the plan's binding instruction, this result does **not** narrow, widen, or abandon the chosen +remedy. Forcing the handle with `_ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false)` +is correct under either explanation: if some incidental path currently creates the handle, the fix +removes the dependency on that incidental behaviour; if the handle is sometimes absent, the fix supplies +it. The twenty green pre-fix runs are recorded as data about the race window, not as evidence the defect +is absent. Phase 2 proceeds as written. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-start.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-start.2026-08-21T18-10.md new file mode 100644 index 000000000..e01cb51f7 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-start.2026-08-21T18-10.md @@ -0,0 +1,75 @@ +# P4-T1 — CPU Load Generator Started + +Timestamp: 2026-08-22T11-53 + +Command: +```powershell +$jobCount = [Environment]::ProcessorCount - 1 +$loop = { $x = 1; while ($true) { $x = ($x * 1103515245 + 12345) % 2147483647 } } +$jobs = @() +for ($i = 0; $i -lt $jobCount; $i++) { $jobs += Start-Job -ScriptBlock $loop } + +Get-Counter '\Processor(_Total)\% Processor Time' -SampleInterval 1 -MaxSamples 5 +``` + +P4-T1, P4-T2 and P4-T3 run inside a **single** `pwsh -NoProfile` session. PowerShell background jobs +are session-scoped, so a job started in one process dies when that process exits; running the three +tasks in one session is what keeps the generator loading the machine across the whole ten-run window +and is what makes P4-T3's `Stop-Job` / `Remove-Job` operate on the jobs P4-T1 started. + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | +| --- | --- | +| `[Environment]::ProcessorCount` | 24 | +| Required job count (`ProcessorCount - 1`) | 23 | +| **Jobs actually started** | **23** | +| Sampled `\Processor(_Total)\% Processor Time` | `100`, `100`, `100`, `100`, `100` | +| **Mean of the five samples** | **100.00** | +| Required mean | at least 80 | +| MSBuild node-reuse process count at start | 0 | + +Acceptance: the recorded job count (23) equals `[Environment]::ProcessorCount - 1` (24 - 1 = 23), +and the mean of the five sampled utilization values (100.00) is at least 80. + +Each job runs a pure integer busy loop with no `Start-Sleep`, no wait, and no file I/O. The +generator is test-harness scaffolding executed in the runner session; it introduces no sleep, retry, +or timing tolerance into any test, and it creates no temporary file. + +## Recorded interruption and restart + +An earlier attempt at this window began at 2026-08-22T10-42 with 23 jobs, a sampled mean of 99.99, +and **17** MSBuild node-reuse processes resident. It completed three runs +(6439 / 6439 passed on each, durations 447.8 s, 861.3 s and 1282.9 s) and was then terminated +mid-run-4 when its host process was stopped by the session's background-task lifecycle. Its 23 load +jobs were children of that process and died with it; a process inventory taken immediately +afterwards confirmed zero surviving load jobs, zero `testhost`, zero `vstest.console` and zero +`MSBuild` processes, so no orphan carried into the restart. + +The window was restarted from scratch rather than resumed, because P4-T2's ten runs must all sit +inside one continuous load window for the load figures at the two ends to bracket them. The +`p4-t2` results directory was cleared before the restart, so the three TRX files from the abandoned +attempt are not present and cannot be mistaken for part of the ten. The restarted runner was +launched detached, outside the background-task lifecycle, and survived to completion. + +The abandoned attempt is recorded here rather than discarded because the plan forbids obtaining a +result without recording every attempt. Its three runs were green; it produced no failure that this +restart conceals. + +## Additional condition recorded: MSBuild node-reuse process count + +The plan mandates a CPU load generator. The condition empirically observed to reproduce the #511 +failure during Phase 0 was different: the one genuine pre-fix failing run +(6430 / 6437, seven 60,000 ms `PumpTimeoutMs` expiries including both named tests) differed from the +passing runs either side of it only in the presence of **17 idle MSBuild node-reuse processes**. +Clearing them restored 6437 / 6437. + +**MSBuild node-reuse process count at load-generator start on the completed window: 0.** The 17 +nodes left by the P2-T6 and P3-T3 rebuilds reached their idle timeout and exited during the +abandoned attempt, so the ten completed runs all executed with a node count of 0. The per-run count +is recorded in the P4-T6 consolidated artifact, and the gap between the plan's mandated CPU-load +condition and the empirically observed reproduction condition is closed by the separate +supplementary ten-run record +`supplementary-msbuild-node-contention-ten-runs.2026-08-21T18-10.md`. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-stop.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-stop.2026-08-21T18-10.md new file mode 100644 index 000000000..01925bb10 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-stop.2026-08-21T18-10.md @@ -0,0 +1,45 @@ +# P4-T3 — CPU Load Generator Stopped + +Timestamp: 2026-08-22T14-24 + +Command: +```powershell +Get-Counter '\Processor(_Total)\% Processor Time' -SampleInterval 1 -MaxSamples 5 +$jobs | Stop-Job +$jobs | Remove-Job -Force +@(Get-Job).Count +``` + +The five samples were taken **immediately before** `Stop-Job`, in the same session that started the +jobs in P4-T1, inside the `finally` block that follows the tenth run. + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | +| --- | --- | +| Pre-stop `\Processor(_Total)\% Processor Time` samples | `99.94`, `100`, `100`, `100`, `100` | +| **Mean pre-stop utilization** | **99.99** | +| Required mean | at least 80 | +| **Post-stop job count** | **0** | +| MSBuild node-reuse process count at stop | 0 | + +Acceptance: the recorded mean pre-stop utilization (99.99) is at least 80 and was sampled +immediately before the load generator was stopped; the recorded post-stop job count is exactly 0. + +## Bracketing, not continuous measurement + +The P4-T1 and P4-T3 samples bracket the ten-run window; they are not a continuous measurement across +it. What they establish is that the generator was still loading the machine at both ends: + +| Point | Timestamp | Mean utilization | +| --- | --- | --- | +| P4-T1, before run 1 | 2026-08-22T11-53 | 100.00 | +| P4-T3, after run 10 | 2026-08-22T14-24 | 99.99 | + +Corroborating evidence from inside the window: the ten runs took between 399.7 s and 1471.9 s of +wall-clock time each, against a measured unloaded baseline of 55.4 s to 70.0 s for the same +nine-assembly command in P1-T4. Every run inside the window was therefore between 6x and 26x slower +than unloaded, which is consistent with sustained contention across the whole window rather than +only at its ends. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-regression-tests.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-regression-tests.2026-08-21T18-10.md new file mode 100644 index 000000000..6b7aefb24 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-regression-tests.2026-08-21T18-10.md @@ -0,0 +1,58 @@ +# P3-T4 — Both Named Regression Tests + +Timestamp: 2026-08-22T10-34 + +Command: +``` +vstest.console.exe QuickFiler.Test\bin\Debug\QuickFiler.Test.dll /InIsolation /Logger:trx ` + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t4 ` + /TestCaseFilter:"FullyQualifiedName~BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread|FullyQualifiedName~BuildPumpHarness_DoesNotCreateTheWebViewChildHandles" +``` + +Resolved through +`C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe`, +invoked from `pwsh -NoProfile` at the worktree root. `/InIsolation` is present, as mandated. + +EXIT_CODE: 0 + +Output Summary: + +TRX: `evidence/regression-testing/p3-t4/2026-08-22_10_34_47_net481.trx` +(the only file in that subdirectory). + +TRX `` verbatim: + +``` +total="2" executed="2" passed="2" failed="0" error="0" timeout="0" aborted="0" +inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" +``` + +| Test | Outcome | Duration | +| --- | --- | --- | +| `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` | **Passed** | 1 s | +| `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` | **Passed** | 98 ms | + +Acceptance: exactly 2 executed, 2 passed, 0 failed, 0 skipped (`notExecuted="0"`). Neither test was +skipped or not-run. + +## Recorded deviation + +`BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` did not pass in its first authored form. The +first run of this task recorded `total=2 passed=1 failed=1`, the failure being +`Expected bodyWebViewHandleCreated to be False ... but found True`. That run's TRX was discarded +along with its subdirectory and is not counted here; the result recorded above is from the re-run +after the correction. + +The cause was established by a four-configuration measurement, not by assumption, and is recorded in +full in `webview-child-handle-measurement.2026-08-21T18-10.md`. In summary: both +`Microsoft.Web.WebView2.WinForms.WebView2` children already have their window handles created by +`ItemViewer` construction (the Designer's `ISupportInitialize.EndInit()` calls), before the harness +runs and independently of the Phase 2 fixture change. A bare `new QuickFiler.ItemViewer()` +constructed on the pump with no harness at all reports both children as handle-created. P3-T1's +instruction to assert `false` was therefore an unmeasured prediction that does not hold, and the +assertions were corrected to the measured value with `because` clauses recording the provenance. +The method name, attributes, structure, and the two named property reads are unchanged, so P3-T1's +own acceptance condition is satisfied verbatim. + +This deviation is escalated in the final execution report. No timing construct was introduced and no +production file was touched to obtain this result. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md new file mode 100644 index 000000000..fa29f6c32 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md @@ -0,0 +1,46 @@ +# P4-T4 — The Two Named Tests Across the Ten Runs + +Timestamp: 2026-08-22T14-35 + +Command: +```powershell +Get-ChildItem docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/*.trx | + Sort-Object Name | + ForEach-Object { + [xml]$x = Get-Content -Raw $_.FullName + # map TestDefinitions/UnitTest id -> TestMethod name, then read Results/UnitTestResult outcome + } +``` + +Each cell was read from that run's own TRX by resolving the result's `testId` against the run's +`TestDefinitions`, so a cell reports the outcome recorded for that exact test in that exact file. + +EXIT_CODE: 0 + +Output Summary: + +Column abbreviations: **Bool** = `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState`; +**NineArg** = `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates`. + +| # | TRX | Bool | NineArg | +| --- | --- | --- | --- | +| 1 | `2026-08-22_11_53_56_net481.trx` | passed | passed | +| 2 | `2026-08-22_12_12_50_net481.trx` | passed | passed | +| 3 | `2026-08-22_12_30_40_net481.trx` | passed | passed | +| 4 | `2026-08-22_12_37_28_net481.trx` | passed | passed | +| 5 | `2026-08-22_12_53_39_net481.trx` | passed | passed | +| 6 | `2026-08-22_13_10_45_net481.trx` | passed | passed | +| 7 | `2026-08-22_13_17_44_net481.trx` | passed | passed | +| 8 | `2026-08-22_13_32_03_net481.trx` | passed | passed | +| 9 | `2026-08-22_13_39_20_net481.trx` | passed | passed | +| 10 | `2026-08-22_14_03_59_net481.trx` | passed | passed | + +Acceptance: the table has exactly ten rows and every cell reads passed. + +Neither test was recorded as `NotExecuted` in any of the ten files; each run's TRX carries +`notExecuted="0"`, so no cell above is a skipped test reported as absent. + +Run 5 is the run that recorded one suite-wide failure. That failure is +`UtilitiesCS.Test.Extensions.DfDeedle_COM_Tests.GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform`, +in a different assembly; both tests tracked by this task passed in run 5. The failure is recorded +against P4-T2, whose acceptance condition it violates. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/no-timing-hacks.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/no-timing-hacks.2026-08-21T18-10.md new file mode 100644 index 000000000..1d5070cd2 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/no-timing-hacks.2026-08-21T18-10.md @@ -0,0 +1,56 @@ +# P3-T8 — No Prohibited Timing Construct in the Added Lines + +Timestamp: 2026-08-22T10-39 + +Command: +``` +git diff --unified=0 c551eabab0aa0a6b1a284252811a2e1de819634e -- ` + QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs ` + QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs ` + QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs > coverage/p3-t8.diff + +grep '^+[^+]' coverage/p3-t8.diff > coverage/p3-t8-added.txt +grep -cF 'Thread.Sleep' coverage/p3-t8-added.txt +grep -cF 'Task.Delay' coverage/p3-t8-added.txt +grep -cF 'SpinWait' coverage/p3-t8-added.txt +grep -cF 'PumpTimeoutMs =' coverage/p3-t8-added.txt +``` + +The merge-base form `git diff ` is used rather than `..HEAD`, because the +merge base currently equals `HEAD` (nothing is committed on this branch yet) and the two-dot form +would compare a commit with itself and see none of the edits. + +EXIT_CODE: 0 + +Output Summary: + +Diff scope: 109 added lines, **0** removed lines, across the three touched test files. The change is +purely additive. + +| Literal | Count in added lines | Required | +| --- | --- | --- | +| `Thread.Sleep` | **0** | exactly 0 | +| `Task.Delay` | **0** | exactly 0 | +| `SpinWait` | **0** | exactly 0 | +| `PumpTimeoutMs =` | **0** | exactly 0 | + +## Timeout constants retain their current values (file inspection) + +| Constant | File | Line | Value | +| --- | --- | --- | --- | +| `PumpTimeoutMs` | `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.cs` | 38 | `internal const int PumpTimeoutMs = 60000;` | +| `PumpTimeoutMs` | `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | 34 | `private const int PumpTimeoutMs = 60000;` | +| `PumpTimeoutMs` | `QuickFiler.Test/Controllers/QfcItemController.SeamFactoryTests.cs` | 293 | `private const int PumpTimeoutMs = 60000;` | +| `TimeoutMs` | `QuickFiler.Test/TestSupport/WinFormsPumpHostTests.cs` | 24 | `private const int TimeoutMs = 30000;` | + +None of these four declarations is in the diff. `QfcItemController.InitializationTests.cs`, +`QfcItemController.SeamFactoryTests.cs` and `WinFormsPumpHostTests.cs` are not touched by this +change at all; `QfcItemController.ViewerSetupTests.cs` is touched, but only at lines 436-438, and +its `PumpTimeoutMs` declaration at line 34 is unchanged. + +Path note: `WinFormsPumpHostTests.cs` resides at `QuickFiler.Test/TestSupport/`, not under +`QuickFiler.Test/Controllers/`. Its line count is 443, matching the plan's do-not-touch budget entry, +and it shows a zero diff. + +Acceptance: all four counts are exactly 0 and all four timeout constants retain their current values. +No sleep, retry, `SpinWait`, or raised timeout constant was introduced anywhere in this change. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2-narrowing-rationale.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2-narrowing-rationale.2026-08-23T20-57.md new file mode 100644 index 000000000..39542639d --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2-narrowing-rationale.2026-08-23T20-57.md @@ -0,0 +1,89 @@ +# P4-T2 Narrowing Rationale — Why No Ten-Run Determinism Pass Is Re-Executed + +Timestamp: 2026-08-23T19-06 + +## (a) The narrowed condition and the measured evidence of record + +Remediation Finding F established that the original P4-T2 acceptance clause — each of ten TRX +recording an absolute zero failed count across all nine assemblies — spans an assembly this child +does not own. Task P2-T3 of `remediation-plan.2026-08-23T20-57.md` narrowed that clause to: + +> each of those ten records zero failed tests within the `QuickFiler.Test` assembly, with both named +> end-to-end tests (`InitializeBool_ThroughThePumpHost_CompletesAndInitializesState`, +> `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates`) and both named +> regression tests (`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`, +> `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles`) recorded as passed in every TRX, and any +> failure in a sibling assembly recorded by fully qualified name and attributed to issue #594 rather +> than failing the task (narrowed 2026-08-23 per remediation Finding F) + +The narrowed condition is satisfied by evidence already committed to this branch. The three distilled +records of record are: + +| Record | What it establishes | +| --- | --- | +| `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md` | Nine of the ten runs report a suite-wide `failed=0`; run 5 reports `failed=1`. | +| `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md` | Both named end-to-end tests recorded `Passed` in 10 of 10 runs. | +| `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md` | Both named regression tests recorded `Passed` in 10 of 10 runs. | + +Run 5's single failure is +`UtilitiesCS.Test.Extensions.DfDeedle_COM_Tests.GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform`. +It sits in `UtilitiesCS.Test`, a sibling-owned assembly that this child's three-file +`QuickFiler.Test/` diff cannot reach, and it is one of the three pre-existing flakes tracked as +issue #594. Under the narrowed condition it is recorded and attributed, not treated as a gate +failure. The `QuickFiler.Test` failed count is zero in all ten runs. + +## (b) The post-remediation source differs from the evidence-producing source by comment lines only + +The ten-run determinism pass was executed against the source at commit `02983a70` +(`wip(511): preserve halted #511/#571 investigation`), which is the commit that introduced both the +fixture change and the distilled ten-run records. The only source edits since then are the two +comment-block corrections made by remediation tasks P1-T1 and P1-T2. + +Verification command and output: + +``` +$ git diff --numstat 02983a70 -- \ + QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs \ + QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs \ + QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs +7 5 QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs +6 2 QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs +``` + +`QfcItemController.InitializationTests.Part3.cs` does not appear in the numstat output at all: it is +byte-identical to the source that produced the Phase 4 evidence. + +Filtering the same diff to changed lines that are not `//` comment lines returns the empty set: + +``` +$ git diff 02983a70 -- \ + | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' | grep -vE '^[+-]\s*//' +(no output) +``` + +The post-remediation source therefore differs from the source that produced the Phase 4 determinism +evidence by comment lines only. Every one of the 13 added and 7 removed lines is a `//` comment +line. No executable statement, no assertion, no timeout constant, and no test method signature +changed; in particular both `viewer.Handle` read statements are retained per orchestrator Decision 2. +A recompiled binary is behaviourally identical, so re-running the ten-run determinism pass could +produce no information the committed records do not already carry. No re-run of the ten-run +determinism pass is required, and none is performed by this cycle. + +## (c) Faithfulness of the distilled record, and the raw-artifact deletion it licensed + +Remediation-inputs Part 1 row 8 records that the committed distilled record +`determinism-ten-runs.2026-08-21T18-10.md` was compared against values re-derived directly from the +raw TRX (`ResultSummary/Counters` for the per-run pass and fail counts, +`UnitTestResult[@outcome='Failed']` for the failing test identity, and a per-test outcome scan for +the four owned named tests) and was confirmed identical. The distilled markdown is therefore a +faithful distillation and is the evidence of record. + +That finding licensed the raw-artifact deletion already carried out. The raw ten-TRX directory +`docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/` +**no longer exists**: its contents were deleted at maintainer instruction on 2026-08-23, together +with the other 56 raw `.trx` and 42 `.coverage` files (roughly 1,180.6 MB) and 188 empty scratch +directories. The recorded disposition is +`docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`. + +Because that directory has been deleted, no task in this cycle asserts its existence, and it is +named in the past tense wherever it is referenced. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-baseline.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-baseline.2026-08-21T18-10.md new file mode 100644 index 000000000..b09321abf --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-baseline.2026-08-21T18-10.md @@ -0,0 +1,99 @@ +# Phase 1 — Consolidated Pre-Fix Baseline (P1-T5) + +Timestamp: 2026-08-22T10-26 + +This artifact consolidates P1-T3 (ten class-filtered runs) and P1-T4 (ten full nine-assembly suite +runs) into a single twenty-row pre-fix table. Every cell was read from that run's own TRX file. No +value in this artifact is predicted; every value was observed. + +`IsHandleCreated` is derived from the probe +`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`, which asserts that +`harness.Viewer.IsHandleCreated` is `true` and that `harness.Viewer.InvokeRequired`, evaluated on the +pump thread, is `false`. A passing probe therefore establishes `IsHandleCreated: true` for that run. + +Column abbreviations: **Bool** = `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState`; +**NineArg** = `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates`; +**Probe** = `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`. + +| # | Run index | Scope | Bool | NineArg | Probe | `IsHandleCreated` | +| --- | --- | --- | --- | --- | --- | --- | +| 1 | 1 | class-filtered | Passed | Passed | Passed | true | +| 2 | 2 | class-filtered | Passed | Passed | Passed | true | +| 3 | 3 | class-filtered | Passed | Passed | Passed | true | +| 4 | 4 | class-filtered | Passed | Passed | Passed | true | +| 5 | 5 | class-filtered | Passed | Passed | Passed | true | +| 6 | 6 | class-filtered | Passed | Passed | Passed | true | +| 7 | 7 | class-filtered | Passed | Passed | Passed | true | +| 8 | 8 | class-filtered | Passed | Passed | Passed | true | +| 9 | 9 | class-filtered | Passed | Passed | Passed | true | +| 10 | 10 | class-filtered | Passed | Passed | Passed | true | +| 11 | 1 | full suite | Passed | Passed | Passed | true | +| 12 | 2 | full suite | Passed | Passed | Passed | true | +| 13 | 3 | full suite | Passed | Passed | Passed | true | +| 14 | 4 | full suite | Passed | Passed | Passed | true | +| 15 | 5 | full suite | Passed | Passed | Passed | true | +| 16 | 6 | full suite | Passed | Passed | Passed | true | +| 17 | 7 | full suite | Passed | Passed | Passed | true | +| 18 | 8 | full suite | Passed | Passed | Passed | true | +| 19 | 9 | full suite | Passed | Passed | Passed | true | +| 20 | 10 | full suite | Passed | Passed | Passed | true | + +Row count: **20** (ten class-filtered, ten full suite). No cell is empty. + +## Observed failure rate, stated as a fraction of the runs actually executed + +Twenty runs were executed and twenty runs were recorded. The rates below are measurements over those +twenty runs and nothing else. + +| Test | Failures / runs executed | Rate | +| --- | --- | --- | +| `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` | 0 / 20 | **0%** | +| `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` | 0 / 20 | **0%** | +| `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` | 0 / 20 | **0%** | +| `IsHandleCreated` observed `true` | 20 / 20 | **100%** | + +Split by scope: 0 / 10 in the class-filtered scope, 0 / 10 in the full-suite scope. + +## Explicit statement of what was and was not measured + +The measured pre-fix failure rate across these twenty runs is **zero**. This plan deliberately made no +prediction about the rate before measuring it, and this artifact claims no rate that was not observed +in these twenty runs. + +Two facts constrain how far that zero generalizes, and both are recorded so no reader over-reads the +table: + +1. **A pre-fix failure of both named tests was observed in this same execution, outside these twenty + runs.** The second invocation of `scripts/vscode/Invoke-MSTestWithCoverage.ps1` during P0-T16 + reported `Total tests: 6437, Passed: 6430, Failed: 7, Test Run Failed.`, with all seven failures + being 60,000 ms `PumpTimeoutMs` expiries, and both named tests among them. That run is recorded in + `evidence/baseline/coverage.2026-08-21T18-10.md`. It is **not** counted in the twenty rows above, + because it is neither a P1-T3 class-filtered run nor a P1-T4 full-suite run and was executed under + a different harness (`dotnet-coverage` instrumentation rather than plain + `vstest.console.exe /EnableCodeCoverage`). Counting it would misreport the denominator; omitting it + from the analysis entirely would misreport the phenomenon. It is therefore excluded from the table + and carried into P1-T6. + +2. **The zero rate is a property of these twenty runs on this machine at this load level.** The one + observed failing run differed from its immediately preceding and following passing runs only in + machine load: 17 idle MSBuild node-reuse processes were resident during it and were stopped before + the next invocation, which then passed. The twenty runs above were all executed after those + processes were cleared. No stray `testhost`, `vstest.console`, or `dotnet-coverage` process + belonging to another agent was present at any point during this execution. + +The plan's instruction is followed exactly: the green pre-fix runs are recorded as data about the race +window, not as evidence the defect is absent, and the chosen remedy is not narrowed, widened, or +abandoned on the basis of this result. Disposition of the mechanism question is recorded separately in +`intermittency-question.2026-08-21T18-10.md` (P1-T6). + +## Provenance + +| Source | Path | +| --- | --- | +| Class-filtered per-run detail | `evidence/regression-testing/prefix-classfiltered.2026-08-21T18-10.md` | +| Class-filtered TRX files (10) | `evidence/regression-testing/p1-t3/` | +| Class-filtered machine-readable rows | `coverage\p1-t3-rows.json` | +| Full-suite per-run detail | `evidence/regression-testing/prefix-fullsuite.2026-08-21T18-10.md` | +| Full-suite TRX files (10) | `evidence/regression-testing/p1-t4/` | +| Full-suite machine-readable rows | `coverage\p1-t4-rows.json` | +| The out-of-table failing run | `evidence/baseline/coverage.2026-08-21T18-10.md` | diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-classfiltered.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-classfiltered.2026-08-21T18-10.md new file mode 100644 index 000000000..b9c64616c --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-classfiltered.2026-08-21T18-10.md @@ -0,0 +1,102 @@ +# Phase 1 — Pre-Fix Behaviour, Class-Filtered Scope (P1-T3, `[expect-fail]`) + +Timestamp: 2026-08-22T09-53 + +Command (executed ten consecutive times): + +``` +"C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe" ^ + QuickFiler.Test\bin\Debug\QuickFiler.Test.dll ^ + /InIsolation ^ + "/TestCaseFilter:FullyQualifiedName~QfcItemController_InitializationTests" ^ + /Logger:trx ^ + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t3 +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243` through +`pwsh -NoProfile`. `vstest.console.exe` was resolved with `vswhere`. `/EnableCodeCoverage` is +deliberately absent: the task specifies it only for the full-suite run in P1-T4. + +EXIT_CODE: 0 + +ExpectedExitCode: 1 + +Output Summary: + +## The expectation was not met, and that is the measurement + +This task is tagged `[expect-fail]` and the plan therefore declares `ExpectedExitCode: 1`. **The +observed exit code was 0 on all ten runs.** The two named tests, and the new probe, **passed on every +one of the ten class-filtered runs.** The declared expectation and the observed result diverge, and +the observed result is recorded verbatim rather than reconciled. + +Per the plan's explicit Phase 1 instruction, a green pre-fix run is treated as **data about the race +window, not as evidence the defect is absent**, and the remedy is neither narrowed, widened, nor +abandoned on this basis. + +## Per-run table (ten rows, no empty cell) + +`IsHandleCreated` is derived from the probe outcome: the probe asserts +`harness.Viewer.IsHandleCreated` is `true` and that `harness.Viewer.InvokeRequired` evaluated on the +pump thread is `false`. A passing probe therefore establishes `IsHandleCreated: true` for that run. + +| Run | Scope | Exit | `InitializeBool_...CompletesAndInitializesState` | `InitializeNineArgOverload_...SavesParametersAndDelegates` | `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` | `IsHandleCreated` | Total | Passed | Failed | TRX | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 1 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_52_25_net481.trx` | +| 2 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_52_28_net481.trx` | +| 3 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_52_33_net481.trx` | +| 4 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_52_41_net481.trx` | +| 5 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_52_51_net481.trx` | +| 6 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_52_55_net481.trx` | +| 7 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_52_59_net481.trx` | +| 8 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_53_04_net481.trx` | +| 9 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_53_08_net481.trx` | +| 10 | class-filtered | 0 | Passed | Passed | Passed | true | 10 | 10 | 0 | `2026-08-22_09_53_16_net481.trx` | + +Observed failure rate in this scope: **0 of 10 runs** for each of the three tracked tests. + +Each row's outcomes were read from that run's own TRX by matching the `testName` attribute on +`UnitTestResult` elements, and each run's TRX was identified by diffing the results directory before +and after the run, so no row is attributed to the wrong file. The machine-readable row set is at +`coverage\p1-t3-rows.json`. + +## Scope contents + +The filter `FullyQualifiedName~QfcItemController_InitializationTests` matched exactly 10 tests on +every run: + +``` +AsyncFlagConstructor_AssignsFieldsViaSaveParameters +BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread +InitializeAsync_ThroughThePumpHost_RunsToTheMockedWebViewSeamAndFaults +InitializeBool_ThroughThePumpHost_CompletesAndInitializesState +InitializeGraphicsAsync_ThroughThePumpHost_CompletesAndAppliesDarkTheme +InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates +InitializeSequentialAsync_ThroughThePumpHost_CompletesAndInitializesState +PredeterminedFolderConstructor_StoresPredeterminedFolder +PrimaryConstructor_AssignsFieldsAndSetsControllerBackReference +SaveParameters_AssignsAllFieldsAndResolvesCollaborators +``` + +## Acceptance conditions + +1. **The subdirectory holds exactly ten TRX files and no others** — met. Directory inventory: + 10 files matching `*.trx`, **0** non-TRX files, and **0** subdirectories. (`/EnableCodeCoverage` + was not passed in this scope, so no `.coverage` attachment folder was created.) +2. **The table has exactly ten rows with no empty cell** — met; 10 rows, every cell populated. +3. **A run in which the probe passes is recorded as `IsHandleCreated: true`** — met; all ten rows + record `true`. + +## What this measures, stated no more strongly than the evidence supports + +In the **isolated class-filtered scope**, with only `QuickFiler.Test.dll` loaded and only these ten +tests selected, the harness viewer's window handle was present on all ten runs without any fix. The +probe's `InvokeRequired == false` assertion also held on all ten, so the handle was owned by the pump +thread. + +This establishes that *something* in the current initialization path creates the handle under these +conditions. It does **not** establish what, and it does **not** generalize to the full-suite scope, +which P1-T4 measures separately — and the P0-T16 coverage-script invocation already recorded a run in +which both named tests failed with 60,000 ms timeouts. Attribution of the mechanism is deferred to +P1-T6, which is required to cite an observation rather than close the question by assertion. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-fullsuite.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-fullsuite.2026-08-21T18-10.md new file mode 100644 index 000000000..6c1c3653a --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-fullsuite.2026-08-21T18-10.md @@ -0,0 +1,116 @@ +# Phase 1 — Pre-Fix Behaviour, Full Nine-Assembly Suite (P1-T4, `[expect-fail]`) + +Timestamp: 2026-08-22T10-24 + +Command (executed ten consecutive times): + +``` +"C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe" ^ + QuickFiler.Test\bin\Debug\QuickFiler.Test.dll ^ + SVGControl.Test\bin\Debug\SVGControl.Test.dll ^ + Tags.Test\bin\Debug\Tags.Test.dll ^ + TaskMaster.Test\bin\Debug\TaskMaster.Test.dll ^ + TaskTree.Test\bin\Debug\TaskTree.Test.dll ^ + TaskVisualization.Test\bin\Debug\TaskVisualization.Test.dll ^ + ToDoModel.Test\bin\Debug\ToDoModel.Test.dll ^ + UtilitiesCS.Test\bin\Debug\UtilitiesCS.Test.dll ^ + VBFunctions.Test\bin\Debug\VBFunctions.Test.dll ^ + /EnableCodeCoverage /InIsolation "/TestCaseFilter:TestCategory!=LiveOutlook" ^ + /Logger:trx ^ + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t4 +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243` through +`pwsh -NoProfile`. All nine assembly paths come from the plan's canonical assembly list. + +EXIT_CODE: 0 + +ExpectedExitCode: 1 + +Output Summary: + +## The expectation was not met, and that is the measurement + +This task is tagged `[expect-fail]` and the plan declares `ExpectedExitCode: 1`. **The observed exit +code was 0 on all ten runs.** All three tracked tests passed on every one of the ten full-suite runs. +The divergence between the declared expectation and the observed result is recorded verbatim. + +Per the plan's explicit Phase 1 instruction, these green pre-fix runs are treated as **data about the +race window, not as evidence the defect is absent**, and the remedy is neither narrowed, widened, nor +abandoned on this basis. + +## Per-run table (ten rows, no empty cell) + +`IsHandleCreated` is derived from the probe outcome: the probe asserts +`harness.Viewer.IsHandleCreated` is `true` and that `harness.Viewer.InvokeRequired` evaluated on the +pump thread is `false`. A passing probe therefore establishes `IsHandleCreated: true` for that run. + +| Run | Scope | Exit | `InitializeBool_...CompletesAndInitializesState` | `InitializeNineArgOverload_...SavesParametersAndDelegates` | `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` | `IsHandleCreated` | Total | Passed | Failed | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| 1 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 2 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 3 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 4 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 5 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 6 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 7 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 8 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 9 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | +| 10 | full suite | 0 | Passed | Passed | Passed | true | 6438 | 6438 | 0 | + +Observed failure rate in this scope: **0 of 10 runs** for each of the three tracked tests. + +The total of **6438** is the P0-T15 baseline total of 6437 plus the one probe added in P1-T1, +confirming both that all nine assemblies loaded on every run and that the probe executed on every +run. + +Each row's outcomes were read from that run's own TRX by matching the `testName` attribute on +`UnitTestResult` elements, with the run's TRX identified by diffing the results directory before and +after the run. The machine-readable row set is at `coverage\p1-t4-rows.json`. + +## `/InIsolation` confirmation + +`/InIsolation` was supplied on all ten runs. The phantom-failure signature the plan warns about +(roughly 1,695 failures with empty messages and sub-millisecond durations, surfacing as a Moq +`TypeInitializationException` via `System.Threading.Tasks.Extensions`) did not appear on any run. + +## Acceptance conditions + +1. **The subdirectory holds exactly ten TRX files and no others** — met. Inventory of + `.../evidence/regression-testing/p1-t4/`: + + | Item | Count | + | --- | --- | + | `*.trx` files | **10** | + | non-TRX files at top level | **0** | + | subdirectories | 20 | + + "No others" is satisfied in the sense the plan's Toolchain section defines it — the condition is a + TRX count scoped to this task's own subdirectory, and there are exactly ten TRX files and no + eleventh. The 20 subdirectories are the attachment folders `vstest.console.exe` creates + automatically under `/ResultsDirectory` when `/EnableCodeCoverage` is passed: one binary + `.coverage` folder and one per-test attachment folder per run. The plan mandates + `/EnableCodeCoverage` with this exact `/ResultsDirectory`, so they are a required by-product of the + specified command rather than stray output. + +2. **The table has exactly ten rows with no empty cell** — met. + +## Size hazard flagged for the phase that commits evidence + +Reported, not acted on, because remediation is outside Phase 0 and Phase 1 scope: + +| Directory | Size | +| --- | --- | +| `evidence/regression-testing/p1-t4/` | **479 MB** | +| `evidence/baseline/p0-t15/` | 48 MB | +| `evidence/regression-testing/p1-t3/` | 284 KB | +| `evidence/` total | **528 MB** | + +Nearly all of it is binary `.coverage` attachments, which carry no information this plan reads: +numeric coverage comes from the Cobertura XML produced by +`scripts/vscode/Invoke-MSTestWithCoverage.ps1`, not from these files. Committing 528 MB of binary +attachments into `docs/features/active/` would be a substantial and permanent repository-size cost. +The phase that commits evidence and asserts a clean tree (P6-T18) should decide whether to retain +only the ten TRX files and prune the attachment subdirectories. This artifact records the condition so +that decision is made deliberately rather than by accident. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-authored.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-authored.2026-08-21T18-10.md new file mode 100644 index 000000000..a56f29d74 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-authored.2026-08-21T18-10.md @@ -0,0 +1,142 @@ +# Phase 1 — Regression Probe Authored (P1-T1, `[expect-fail]`) + +Timestamp: 2026-08-22T09-55 + +Command: + +``` +# Edit, then the mandatory formatting step, then verification +dotnet tool run csharpier check . +dotnet tool run csharpier format . +dotnet tool run csharpier check . +grep -n "InitializeBool_ThroughThePumpHost_CompletesAndInitializesState|InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates|BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread" QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs +pwsh -NoProfile -Command "@(Get-Content -LiteralPath 'QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs').Count" +git diff --stat -- QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs +``` + +EXIT_CODE: 0 + +ExpectedExitCode: 0 + +Note on the expectation field: P1-T1 is an **authoring** task, not a test-execution task. Its own +exit code is the toolchain's, which must be 0. The `[expect-fail]` tag concerns the authored test's +*runtime* outcome, which is measured and recorded by P1-T3 and P1-T4; those artifacts carry +`ExpectedExitCode: 1`. + +Output Summary: + +## What was authored + +`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` was appended to +`QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, after the last existing +method in the partial class. The diff is **49 insertions, 0 deletions** — purely additive, no existing +line altered. + +Post-format text of the added method: + +```csharp + /// + /// #511/#571 regression probe: the shared pump harness must hand back an + /// ItemViewer whose window handle already exists, created on the pump thread. + /// Every pump-hosted test in this class marshals work through the viewer, and + /// Control.Invoke throws on a handle-less control, so a harness that returns a + /// viewer with no handle makes those tests fail. This probe reports the harness viewer's + /// handle state directly, so a run in which the end-to-end tests happen to pass still + /// records whether the handle was present. + /// + [TestMethod] + [Timeout(PumpTimeoutMs)] + public async Task BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread() + { + // Arrange + WinFormsPumpHost host = new WinFormsPumpHost(); + PumpHarness harness = null; + try + { + harness = await BuildPumpHarnessAsync(host, darkMode: false).ConfigureAwait(false); + + // Act — read the marshalling predicate on the pump thread that owns the viewer. + bool invokeRequiredOnPumpThread = await host.InvokeAsync(() => + harness.Viewer.InvokeRequired + ) + .ConfigureAwait(false); + + // Assert — the handle exists, so Control.Invoke cannot throw for want of one. + harness + .Viewer.IsHandleCreated.Should() + .BeTrue( + because: "the harness must create the viewer's window handle on the pump thread" + ); + invokeRequiredOnPumpThread + .Should() + .BeFalse( + because: "the pump thread owns the viewer's handle, so no marshalling is required there" + ); + } + finally + { + if (harness != null) + { + harness.Restore(); + } + + await host.StopAsync().ConfigureAwait(false); + } + } +``` + +## Acceptance conditions, each verified + +| Condition | Result | +| --- | --- | +| Method exists in that file with exactly that name | **Met** — declared at line 301 | +| Uses `[TestMethod]` | **Met** — with `[Timeout(PumpTimeoutMs)]` | +| `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` still declared at line 131 | **Met** | +| `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` still declared at line 175 | **Met** | +| File line count less than 500 | **Met** — 339 lines (161 of headroom) | + +Both spec-cited line numbers were re-derived from the file rather than taken on trust, both before and +**after** the CSharpier format step, and both are unchanged at 131 and 175. Appending after the last +method rather than inserting between existing methods is what preserves them. + +## Shape conformance + +- Follows the Arrange-Act-Assert shape of the existing tests in the file. +- Constructs `WinFormsPumpHost`, calls `BuildPumpHarnessAsync(host, darkMode: false)`, restores in + `finally` via `harness.Restore()`, and awaits `host.StopAsync()` — the same fixture protocol as + every other test in this partial class. This preserves the `UiThreadDispatcherGate` + acquire-and-release structure that Binding Constraint 4 protects. +- Asserts with FluentAssertions: `harness.Viewer.IsHandleCreated.Should().BeTrue(...)` and + `invokeRequiredOnPumpThread.Should().BeFalse(...)`, where the second value comes from + `await host.InvokeAsync(() => harness.Viewer.InvokeRequired)`. +- Both assertions carry a `because:` reason, so a failure message states the expected invariant. + +## Prohibited constructs — none present + +A scan of the diff for `Sleep`, `Delay`, `SpinWait`, `Retry`, and `retry` returned only the single +line `+ [Timeout(PumpTimeoutMs)]`. There is **no sleep, no retry, no `SpinWait`, and no timing +tolerance**. `PumpTimeoutMs` is the pre-existing `internal const int PumpTimeoutMs = 60000` declared at +`QuickFiler.Test/Controllers/QfcItemController.InitializationTests.cs:38`; its value was **not** +changed, consistent with Binding Constraint 6. + +No temporary file is created by the test. No production file under `QuickFiler/` was touched. No +`.csproj` was touched: `QfcItemController.InitializationTests.Part3.cs` already carries a +`` entry, which is why it is the only permitted home for new tests. + +## Toolchain step 1 (formatting) + +`csharpier check .` initially reported this one file as `Was not formatted` — CSharpier prefers the +lambda placed as `InvokeAsync(() =>` with the body on the following line. `csharpier format .` was +applied and the subsequent `csharpier check .` reported `Checked 1517 files in 6284ms.` with zero +unformatted files. `git status --porcelain` confirms the format step modified **only** this one source +file; no other tracked file changed, consistent with the P0-T12 baseline of zero unformatted files. + +## Why this test is authored in Phase 1 rather than Phase 3 + +Recorded so a reviewer does not read it as phase drift. Two reasons, both from the plan: + +1. The repository Bugfix Workflow requires a failing regression test **before** the fix. +2. It is the only instrument that reports the harness viewer's `IsHandleCreated` value on a run where + the two end-to-end tests happen to pass — which the P0-T15 baseline already showed can occur. + +Phase 3 authors the second named test and verifies both. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-flips-green.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-flips-green.2026-08-21T18-10.md new file mode 100644 index 000000000..c5deba39a --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-flips-green.2026-08-21T18-10.md @@ -0,0 +1,62 @@ +# P2-T6 — Probe Outcome, Pre-Fix vs Post-Fix + +Timestamp: 2026-08-22T10-22 + +Command: + +``` +pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU"' + +vstest.console.exe QuickFiler.Test\bin\Debug\QuickFiler.Test.dll /InIsolation /Logger:trx ` + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p2-t6 ` + /TestCaseFilter:"FullyQualifiedName~BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread" +``` + +`msbuild` was invoked through its absolute resolved path +`C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe`; +`vstest.console.exe` through +`C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe`. +Both went through `pwsh -NoProfile` from the worktree root. + +EXIT_CODE: 0 (rebuild), 0 (test run) + +Output Summary: + +| Stage | Measure | Value | +| --- | --- | --- | +| Rebuild | Exit code | **0** | +| Rebuild | `error` occurrences in `coverage\p2-t6-build.log` | **0** | +| Rebuild | `Skipping target "CoreCompile"` occurrences | **0** | +| Test run | Total tests | 1 | +| Test run | Passed | **1** | +| Test run | Failed | **0** | +| Test run | Duration | 2.78 s | +| Test run | TRX | `evidence/regression-testing/p2-t6/2026-08-22_10_22_48_net481.trx` | + +## Pre-fix and post-fix side by side + +| Test | Pre-fix (P1-T5 table, 20 runs) | Post-fix (this task) | +| --- | --- | --- | +| `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` | Passed 20 / 20; `IsHandleCreated: true` on every run; measured failure rate **0%** | Passed 1 / 1 | + +## Mandatory flag: this probe was already green pre-fix + +The plan requires that a probe already green on every pre-fix run be recorded as such and flagged, +because in that case it proves nothing about the fix. + +**The probe was green on all twenty P1-T5 pre-fix runs.** It is therefore flagged here: the +post-fix pass recorded above is a consistency check, not the fail-before/pass-after proof for the +fixture change. This task is not evidence that the fix altered behaviour. + +P1-T6's disposition governs. Its two recorded facts are the load-bearing ones: + +1. A genuine pre-fix failure of both named end-to-end tests **was** observed in this execution, + outside the twenty-row table: the second P0-T16 coverage invocation reported + `Total tests: 6437, Passed: 6430, Failed: 7`, with all seven failures being 60,000 ms + `PumpTimeoutMs` expiries and both named tests among them. +2. That failing run differed from the passing runs either side of it only in machine load — + 17 idle MSBuild node-reuse processes were resident during it. Clearing them restored 6437 / 6437. + +The remedy is unchanged, per the plan's explicit instruction: forcing the handle removes the +dependency in the passing direction under either candidate explanation, so a green pre-fix run does +not narrow, widen, or abandon it. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-rebuild.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-rebuild.2026-08-21T18-10.md new file mode 100644 index 000000000..ca2ada312 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-rebuild.2026-08-21T18-10.md @@ -0,0 +1,66 @@ +# Phase 1 — Rebuild So The Probe Is Compiled (P1-T2) + +Timestamp: 2026-08-22T09-50 + +Command: + +``` +pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU"' +``` + +Run from the worktree root +`\.claude\worktrees\agent-ad37a256a0fb60243`, with `msbuild` +invoked through its absolute resolved path +`C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe`. Log captured +to `coverage\p1-t2-rebuild.log`. + +EXIT_CODE: 0 + +Output Summary: + +| Measure | Value | +| --- | --- | +| Exit code | **0** | +| Error count | 0 | +| Warning count | 5 (the same pre-existing System.Reactive notices recorded in P0-T13) | +| `Skipping target "CoreCompile"` count | 0 | + +## Acceptance conditions + +1. **`EXIT_CODE: 0`** — met. +2. **`QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` has a write time later than the P1-T1 edit + time** — met: + + | Timestamp | Value | + | --- | --- | + | P1-T1 edit time (`QfcItemController.InitializationTests.Part3.cs`) | `2026-08-22T09:47:46.4058177-04:00` | + | `QuickFiler.Test.dll` before the rebuild | `2026-08-22T09:25:35.8789100-04:00` | + | `QuickFiler.Test.dll` after the rebuild | `2026-08-22T09:50:34.1433036-04:00` | + | DLL newer than the edit | **True** | + + The pre-rebuild DLL timestamp (09:25:35) predates the edit (09:47:46), so the comparison is + non-vacuous: the assembly genuinely did not contain the probe before this task ran, and does after. + + The `Skipping target "CoreCompile"` count of 0 additionally confirms `/t:Rebuild` really + recompiled rather than short-circuiting on incrementality. + +## Independent confirmation that the probe is in the assembly + +A timestamp comparison alone does not prove the new method is present, so discovery was checked +directly against the built assembly: + +``` +vstest.console.exe QuickFiler.Test\bin\Debug\QuickFiler.Test.dll /ListTests /InIsolation +``` + +Results: + +``` +PROBE_LISTED_COUNT=1 + BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread +NAMED1_LISTED_COUNT=1 +NAMED2_LISTED_COUNT=1 +``` + +The probe is discoverable exactly once, and both tests named by #511 and #571 remain discoverable +exactly once each. The subsequent P1-T3 and P1-T4 measurement runs therefore execute all three tests. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/pumphost-selftests.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/pumphost-selftests.2026-08-21T18-10.md new file mode 100644 index 000000000..0635beaac --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/pumphost-selftests.2026-08-21T18-10.md @@ -0,0 +1,44 @@ +# P3-T6 — `WinFormsPumpHostTests` Self-Tests + +Timestamp: 2026-08-22T10-37 + +Command: +``` +vstest.console.exe QuickFiler.Test\bin\Debug\QuickFiler.Test.dll /InIsolation /Logger:trx ` + /ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t6 ` + /TestCaseFilter:"FullyQualifiedName~WinFormsPumpHostTests" +``` + +EXIT_CODE: 0 + +Output Summary: + +TRX: `evidence/regression-testing/p3-t6/2026-08-22_10_37_02_net481.trx` + +TRX `` verbatim: + +``` +total="13" executed="13" passed="13" failed="0" error="0" timeout="0" aborted="0" +inconclusive="0" passedButRunAborted="0" notRunnable="0" notExecuted="0" +``` + +| # | Test | Outcome | Duration | +| --- | --- | --- | --- | +| 1 | `Constructor_WhenHostStarts_CapturesWinFormsContextOnADistinctThread` | Passed | 112 ms | +| 2 | `InvokeAsyncAction_WhenPosted_RunsOnThePumpThread` | Passed | 7 ms | +| 3 | `InvokeAsyncFactory_WhenPosted_RunsOnThePumpThreadAndReturnsTheValue` | Passed | 5 ms | +| 4 | `RunAsyncVoid_WhenPosted_StartsAndResumesOnThePumpThread` | Passed | 7 ms | +| 5 | `RunAsyncResult_WhenPosted_RunsOnThePumpThreadAndReturnsTheValue` | Passed | 8 ms | +| 6 | `AwaitingSyncContext_FromTheTestThread_ResumesOnThePumpThread` | Passed | 5 ms | +| 7 | `BothMarshalRoutes_WpfDispatcherAndSyncContext_ExecuteOnThePumpThread` | Passed | 47 ms | +| 8 | `InvokeAsync_WhenWorkThrows_FaultsTheAwaitedTaskWithTheOriginalException` | Passed | 64 ms | +| 9 | `RunAsyncVoid_WhenWorkFaults_SurfacesTheOriginalUnwrappedException` | Passed | 6 ms | +| 10 | `RunAsyncResult_WhenWorkFaults_SurfacesTheOriginalUnwrappedException` | Passed | 8 ms | +| 11 | `PostingMembers_AfterStop_FaultWithObjectDisposedException` | Passed | 7 ms | +| 12 | `Dispose_CalledTwice_IsANoOp` | Passed | 7 ms | +| 13 | `StopAsync_WhenThePumpLoopRecordedAnException_RethrowsIt` | Passed | 8 ms | + +Acceptance: exactly 13 executed, 13 passed, 0 failed, 0 skipped (`notExecuted="0"`). + +`WinFormsPumpHostTests.cs` was not edited by this plan (443 lines, at the plan's do-not-touch list), +and `TimeoutMs = 30000` retains its current value; P3-T8 records that check. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md new file mode 100644 index 000000000..1589add64 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md @@ -0,0 +1,47 @@ +# P4-T5 — The Two Regression Tests Across the Ten Runs + +Timestamp: 2026-08-22T14-35 + +Command: +```powershell +Get-ChildItem docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/*.trx | + Sort-Object Name | + ForEach-Object { + [xml]$x = Get-Content -Raw $_.FullName + # map TestDefinitions/UnitTest id -> TestMethod name, then read Results/UnitTestResult outcome + } +``` + +Each cell was read from that run's own TRX by resolving the result's `testId` against the run's +`TestDefinitions`. + +EXIT_CODE: 0 + +Output Summary: + +Column abbreviations: **Forces** = `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`; +**NoChildHandles** = `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles`. + +| # | TRX | Forces | NoChildHandles | +| --- | --- | --- | --- | +| 1 | `2026-08-22_11_53_56_net481.trx` | passed | passed | +| 2 | `2026-08-22_12_12_50_net481.trx` | passed | passed | +| 3 | `2026-08-22_12_30_40_net481.trx` | passed | passed | +| 4 | `2026-08-22_12_37_28_net481.trx` | passed | passed | +| 5 | `2026-08-22_12_53_39_net481.trx` | passed | passed | +| 6 | `2026-08-22_13_10_45_net481.trx` | passed | passed | +| 7 | `2026-08-22_13_17_44_net481.trx` | passed | passed | +| 8 | `2026-08-22_13_32_03_net481.trx` | passed | passed | +| 9 | `2026-08-22_13_39_20_net481.trx` | passed | passed | +| 10 | `2026-08-22_14_03_59_net481.trx` | passed | passed | + +Acceptance: the table has exactly ten rows and every cell reads passed. + +Both regression tests carry `[Timeout(PumpTimeoutMs)]` with `PumpTimeoutMs = 60000`, and neither was +recorded as a timeout in any of the ten runs, despite every run being between 6x and 26x slower than +the unloaded baseline. + +`BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` is the corrected form described in +`webview-child-handle-measurement.2026-08-21T18-10.md`; it asserts the measured handle state of both +named `Microsoft.Web.WebView2.WinForms.WebView2` children rather than the unmeasured prediction the +plan's P3-T1 body stated. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-comment-fix.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-comment-fix.2026-08-23T20-57.md new file mode 100644 index 000000000..2d38410e1 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-comment-fix.2026-08-23T20-57.md @@ -0,0 +1,43 @@ +# Scope Lock After the Phase 1 Comment Corrections + +Timestamp: 2026-08-23T19-03 + +Command: +```bash +MB=f85a36faebaaec29fe5233c9d9f69d223d80e4c5 # $MergeBase, recorded by P0-T6 +git diff --name-only $MB +git diff --name-only $MB | grep -E '\.(cs|csproj|props|targets|config)$' +git diff --name-only $MB | grep -c '^QuickFiler/' +git diff --name-only $MB | grep -c '\.csproj$' +git diff --name-only $MB | grep '^\.claude/' | grep -vc '^\.claude/agent-memory/' +``` + +EXIT_CODE: 0 + +Output Summary: + +Filtered set (paths ending `.cs`, `.csproj`, `.props`, `.targets`, or `.config`) — exactly 3 members, +matching the three paths the scope lock admits: + +| # | Path | +| --- | --- | +| 1 | `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` | +| 2 | `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` | +| 3 | `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | + +Prohibited counts, measured against the unfiltered `git diff --name-only $MergeBase` list: + +| Prohibited class | Count | Required | +| --- | --- | --- | +| paths beginning `QuickFiler/` (production) | 0 | 0 | +| paths ending `.csproj` | 0 | 0 | +| paths beginning `.claude/` other than `.claude/agent-memory/` | 0 | 0 | + +The unfiltered list additionally carries 22 `.claude/agent-memory/` Markdown files and 46 paths under +`docs/features/active/winformspumphost-suite-determinism-511/` (the feature's own documentation and +evidence tree, including the `evidence/.gitignore` appended by P0-T9). Both classes are permitted by +plan prohibition 6 and are excluded from the scope-lock filter, which admits only `.cs`, `.csproj`, +`.props`, `.targets`, and `.config` paths. + +The scope lock holds: the executable-code diff against the merge base is exactly the three +`QuickFiler.Test/` files, unchanged in membership from before Phase 1. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-phase2.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-phase2.2026-08-21T18-10.md new file mode 100644 index 000000000..05ab1e2d3 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-phase2.2026-08-21T18-10.md @@ -0,0 +1,48 @@ +# P2-T5 — Production-File Scope Lock After the Phase 2 Fixture Change + +Timestamp: 2026-08-22T10-19 + +Command: +``` +git diff --name-only c551eabab0aa0a6b1a284252811a2e1de819634e +git diff --name-only c551eabab0aa0a6b1a284252811a2e1de819634e | grep -c '^QuickFiler/' +git diff --name-only c551eabab0aa0a6b1a284252811a2e1de819634e | grep -c '\.csproj$' +``` + +Merge base used: `c551eabab0aa0a6b1a284252811a2e1de819634e` (recorded by P0-T6). + +Note on diff form: the merge base currently equals `HEAD` because nothing is committed on this +branch yet, so a `..HEAD` form would compare two identical commits and report nothing. +The working-tree form `git diff ` is used instead, so the comparison actually sees the +uncommitted edits. + +EXIT_CODE: 0 + +Output Summary: + +Changed paths against the merge base (5 tracked files): + +``` +.claude/agent-memory/atomic-executor/project_winformspumphost_tests_load_flaky.md +QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs +QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs +QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs +docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md +``` + +| Count | Value | +| --- | --- | +| Paths beginning `QuickFiler/` | **0** | +| Paths ending `.csproj` | **0** | + +Both recorded counts are exactly 0, so the acceptance condition holds. + +Corollaries verified by the same enumeration: + +- `QuickFiler/Controllers/QfcItemController.Initialization.cs` and + `QuickFiler/Controllers/QfcItemController.ViewerSetup.cs` show a zero diff; neither appears in the + changed-path list. The coverage justifications sibling issue #571 depends on are untouched. +- `QuickFiler.Test/QuickFiler.Test.csproj` shows a zero diff, so the regions owned by sibling + children #491 and #449 are untouched. +- The only `.claude/` path in the diff is under `.claude/agent-memory/`, which Binding Constraint 3 + carves out explicitly. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/supplementary-msbuild-node-contention-ten-runs.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/supplementary-msbuild-node-contention-ten-runs.2026-08-21T18-10.md new file mode 100644 index 000000000..74bd5e3bd --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/supplementary-msbuild-node-contention-ten-runs.2026-08-21T18-10.md @@ -0,0 +1,136 @@ +# Supplementary Evidence — Ten-Run Confirmation Under MSBuild Node Contention + +Timestamp: 2026-08-22T15-03 + +## This artifact is supplementary + +It is **not** a plan task. It satisfies no acceptance condition in +`plan.2026-08-21T18-10.md`, changes no task's acceptance condition, and licenses no edit to the +plan. It is additive evidence recorded to close a gap between two conditions: + +- **The condition the plan mandates.** P4-T1 mandates a CPU load generator, and P4-T2's ten runs + execute under it. +- **The condition empirically observed to reproduce the defect.** The only genuine pre-fix failure + seen anywhere in this execution was the second P0-T16 coverage invocation, which reported + `Total tests: 6437, Passed: 6430, Failed: 7` with all seven failures being 60,000 ms + `PumpTimeoutMs` expiries and both named tests among them. That run differed from the passing runs + immediately either side of it in exactly one respect: **17 idle MSBuild node-reuse processes were + resident**. Clearing them restored 6437 / 6437. + +The ten mandated P4-T2 runs executed with an MSBuild node count of **0** throughout (the 17 nodes +left by the P2-T6 and P3-T3 rebuilds reached their idle timeout and exited before the completed +window began). Ten green runs at a zero node count would not have exercised the only condition known +to reproduce the defect, so the determinism gate would be weaker than it looks. These two +supplementary passes exercise it directly. + +## Method + +Two ten-run passes were executed with the same nine-assembly command as P4-T2, **without** the CPU +load generator (which had already been stopped by P4-T3), and with MSBuild node-reuse processes +deliberately present. Nodes exit on an idle timeout, so a single preceding build does not keep them +resident across ten runs; the runner therefore re-established them immediately before each run. + +``` +# before each run, if the node count had decayed below the pass's floor: +MSBuild.exe /t:Build /m /p:Configuration=Debug /p:Platform= /v:q /nologo + +vstest.console.exe /EnableCodeCoverage /InIsolation /Logger:trx ` + /ResultsDirectory: /TestCaseFilter:"TestCategory!=LiveOutlook" +``` + +| Pass | Node-spawning build | Node floor | Observed node count | Results directory | +| --- | --- | --- | --- | --- | +| A | `QuickFiler.Test\QuickFiler.Test.csproj` | 8 | **3** per run | `evidence/regression-testing/supplementary-node-contention/` | +| B | `TaskMaster.sln` | 15 | **17** per run | `evidence/regression-testing/supplementary-node-contention-b/` | + +Pass A was run first and reached only 3 nodes, because a single-project `/m` build spawns far fewer +nodes than a solution build. Rather than discard it, it is recorded as executed and pass B was added +to reach a node count matching the 17 observed at reproduction. Both passes are reported; neither is +a re-run of the other to obtain a better result. + +Each pass directory holds exactly ten `.trx` files. + +EXIT_CODE: 0 (pass A, all ten runs); 1 on two of ten runs in pass B (see the table) + +## Output Summary — Pass A, 3 MSBuild nodes + +| # | Total | Passed | Failed | Duration (s) | Nodes before / after | Four tracked tests | +| --- | --- | --- | --- | --- | --- | --- | +| 1 | 6439 | 6439 | 0 | 56.7 | 3 / 3 | all Passed | +| 2 | 6439 | 6439 | 0 | 76.6 | 3 / 3 | all Passed | +| 3 | 6439 | 6439 | 0 | 54.6 | 3 / 3 | all Passed | +| 4 | 6439 | 6439 | 0 | 57.0 | 3 / 3 | all Passed | +| 5 | 6439 | 6439 | 0 | 55.9 | 3 / 3 | all Passed | +| 6 | 6439 | 6439 | 0 | 54.4 | 3 / 3 | all Passed | +| 7 | 6439 | 6439 | 0 | 59.5 | 3 / 3 | all Passed | +| 8 | 6439 | 6439 | 0 | 54.3 | 3 / 3 | all Passed | +| 9 | 6439 | 6439 | 0 | 54.9 | 3 / 3 | all Passed | +| 10 | 6439 | 6439 | 0 | 54.8 | 3 / 3 | all Passed | + +Ten of ten green, suite-wide. + +## Output Summary — Pass B, 17 MSBuild nodes (the reproduction condition) + +| # | Total | Passed | Failed | Duration (s) | Nodes before / after | Four tracked tests | +| --- | --- | --- | --- | --- | --- | --- | +| 1 | 6439 | 6438 | **1** | 57.2 | 17 / 17 | all Passed | +| 2 | 6439 | 6439 | 0 | 55.1 | 17 / 17 | all Passed | +| 3 | 6439 | 6439 | 0 | 56.9 | 17 / 17 | all Passed | +| 4 | 6439 | 6439 | 0 | 56.2 | 17 / 17 | all Passed | +| 5 | 6439 | 6439 | 0 | 56.3 | 17 / 17 | all Passed | +| 6 | 6439 | 6439 | 0 | 56.8 | 17 / 17 | all Passed | +| 7 | 6439 | 6439 | 0 | 54.3 | 17 / 17 | all Passed | +| 8 | 6439 | 6439 | 0 | 58.4 | 17 / 17 | all Passed | +| 9 | 6439 | 6438 | **1** | 55.5 | 17 / 17 | all Passed | +| 10 | 6439 | 6439 | 0 | 56.8 | 17 / 17 | all Passed | + +The four tracked tests are +`InitializeBool_ThroughThePumpHost_CompletesAndInitializesState`, +`InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates`, +`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` and +`BuildPumpHarness_DoesNotCreateTheWebViewChildHandles`. Every one of them passed in **all twenty** +supplementary runs, including both runs that recorded a suite-wide failure. + +## The two pass-B failures + +| Run | Failing test | Message | +| --- | --- | --- | +| 1 | `UtilitiesCS.Test.OutlookObjects.FilterDASL.DASLFilterParserTests.PrintTree_WritesIndentedTreeToConsole` | `Expected writer.ToString() "" to contain "AND".` | +| 9 | `UtilitiesCS.Test.ReusableTypeClasses.StackGeek_Tests.Main_RunsSampleScenarioWithoutThrowing` | `Expected writer.ToString() "" to contain "Middle Element :".` | + +Both are in `UtilitiesCS.Test`, both assert on the contents of a redirected `Console.Out` writer, +and in both the writer was **empty**. That is the signature of a shared-`Console.Out` race between +parallel test classes: one test's redirection is displaced by another's before the assertion reads +it. Neither is a `[Timeout]` expiry, neither is a pump-harness test, and neither is reachable from +this change's diff, which is confined to three files under `QuickFiler.Test/Controllers/`. + +## Finding: three independent pre-existing flaky tests in `UtilitiesCS.Test` + +Across the mandated P4-T2 window and these two supplementary passes, three distinct +`UtilitiesCS.Test` tests failed intermittently, none of them related to #511: + +1. `Extensions.DfDeedle_COM_Tests.GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform` + — `System.NullReferenceException`, in P4-T2 run 5 (under 100% CPU load). +2. `OutlookObjects.FilterDASL.DASLFilterParserTests.PrintTree_WritesIndentedTreeToConsole` + — empty redirected `Console.Out`, in supplementary pass B run 1. +3. `ReusableTypeClasses.StackGeek_Tests.Main_RunsSampleScenarioWithoutThrowing` + — empty redirected `Console.Out`, in supplementary pass B run 9. + +Items 2 and 3 share a root cause class (shared `Console.Out` redirection under class-level +parallelization). All three are pre-existing, out-of-scope for this child issue, and are reported to +the caller for promotion rather than fixed here. + +## Conclusion, stated no more strongly than the evidence supports + +Under the exact condition observed to reproduce the #511 failure — 17 resident MSBuild node-reuse +processes — the two named tests and the two regression tests passed in **10 of 10** runs, and did so +again in the 3-node pass A and in the 10 mandated 100%-CPU-load runs of P4-T2. That is 30 of 30 +post-fix runs with all four tracked tests green, spanning zero-node, 3-node, 17-node and +CPU-saturated conditions. + +This is not a fail-before / pass-after proof, and it is not presented as one: the pre-fix +measurement in P1-T5 recorded no failure of the named tests across its twenty runs, so there is no +measured pre-fix failure rate for these conditions to be compared against. What the 30 runs +establish is that the fixture change holds under the reproduction condition, and that the residual +suite-level instability observed in this execution is located in `UtilitiesCS.Test`, not in the +pump harness. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md new file mode 100644 index 000000000..b8baa7f75 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md @@ -0,0 +1,115 @@ +# P3-T1 — Measured WebView2 Child Handle State, and the Correction It Forced + +Timestamp: 2026-08-22T10-34 + +## Why this artifact exists + +P3-T1 as authored instructs that +`BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` assert +`harness.Viewer.L0v2h2_WebView2.IsHandleCreated` is `false` and +`harness.Viewer.L0vhBreadcrumb_WebView2.IsHandleCreated` is `false`. + +Authored exactly that way, the test **fails**. The failure is not caused by the Phase 2 fixture +change. It is caused by the plan asserting a world-state value that was never measured. This +artifact records the measurement that established that, so no reader has to take the correction on +trust. + +## Commands + +``` +# 1. Authored form (BeFalse / BeFalse), fix present +vstest.console.exe QuickFiler.Test\bin\Debug\QuickFiler.Test.dll /InIsolation ` + /TestCaseFilter:"FullyQualifiedName~BuildPumpHarness_DoesNotCreateTheWebViewChildHandles" + +# 2. Same test, Part2.cs handle-forcing statement commented out, project rebuilt +# 3. Same test, both assertions flipped to BeTrue, fix present +# 4. Same test with harness.Viewer replaced by a bare `new QuickFiler.ItemViewer()` on the pump, +# no harness, no SaveParameters, no .Handle read +``` + +Runs 2, 3 and 4 were diagnostics. `Part2.cs` and `Part3.cs` were each restored byte-for-byte from a +scratchpad backup afterwards; no temporary file was created anywhere in the repository. + +EXIT_CODE: 0 (measurement complete; see the per-run codes below) + +## Output Summary — the four measurements + +| # | Configuration | `L0v2h2_WebView2.IsHandleCreated` | `L0vhBreadcrumb_WebView2.IsHandleCreated` | Exit | +| --- | --- | --- | --- | --- | +| 1 | Harness viewer, Phase 2 fix **present**, assertions `BeFalse` | **true** (assertion failed) | not reached | 1 | +| 2 | Harness viewer, Phase 2 fix **absent** (statement commented out), assertions `BeFalse` | **true** (assertion failed) | not reached | 1 | +| 3 | Harness viewer, Phase 2 fix present, assertions `BeTrue` / `BeTrue` | **true** | **true** | 0 | +| 4 | **Bare** `new QuickFiler.ItemViewer()` on the pump — no harness, no `SaveParameters`, no `.Handle` read — assertions `BeTrue` / `BeTrue` | **true** | **true** | 0 | + +Run 2 is the decisive one for attribution: with the Phase 2 statement removed, the body WebView2 +child's handle is **already created**. Run 4 is the decisive one for provenance: a bare `ItemViewer` +that has never been through the harness at all already reports both children as handle-created. + +## Findings + +1. **Both WebView2 child handles are created by `ItemViewer` construction**, inside + `InitializeComponent`, via the third-party `((ISupportInitialize)(...)).EndInit()` calls the + Designer emits for `_l0v2h2_WebView2` and `_l0vhBreadcrumb_WebView2`. Neither the pump harness + nor the Phase 2 `viewer.Handle` read creates them. + +2. **The Phase 2 change does not alter either child's handle state.** Runs 1 and 2 are identical on + the measured value; the only difference between them is the presence of the inserted statement. + The minimality claim the plan makes for `.Handle` over `CreateControl()` is therefore not + observable through these two properties in this fixture, because construction has already + created both handles before either instrument could run. + +3. **This measurement closes the open question P1-T6 left.** P1-T6 recorded that + `harness.Viewer.IsHandleCreated` was `true` on all twenty pre-fix runs and named third-party + WebView2 `ISupportInitialize` behaviour as the unverified prime suspect for a handle appearing + outside the traced initialization sequence. Run 4 verifies that suspect directly. WinForms + creates a parent's window handle when a child's handle is created, so the children's + `EndInit`-driven handle creation forces the `ItemViewer`'s own handle as a side effect. That is + why the viewer already had a handle on every pre-fix run, and why the two named end-to-end tests + passed on those runs. + +4. **The defect #511 describes is not thereby explained away.** The one genuine pre-fix failure + recorded in this execution (the second P0-T16 coverage invocation, 6430 / 6437 with seven + 60,000 ms `PumpTimeoutMs` expiries including both named tests) remains a timing failure under + machine load, not a missing-handle failure. Forcing the handle deterministically on the pump + thread is still correct: it removes the dependency on a third-party side effect that this + repository does not control and whose timing it cannot observe. + +## The correction applied to P3-T1 + +The method keeps the name P3-T1 and P4-T5 both cite, +`BuildPumpHarness_DoesNotCreateTheWebViewChildHandles`, and keeps its `[TestMethod]`, +`[Timeout(PumpTimeoutMs)]`, its Arrange-Act-Assert shape, and its two reads of the two named +WebView2 properties on the pump thread through `host.InvokeAsync`. Exactly two things changed from +the authored form: + +- `BeFalse` became `BeTrue` on both assertions. +- The `because` clauses and the doc comment now record the measured provenance instead of the + unmeasured prediction. + +The method name remains accurate under the measurement: `BuildPumpHarness` does **not** create +these handles — `ItemViewer` construction does. The test now pins the state the harness inherits, +and it fails if a future change makes the children handle-less at construction and so invalidates +the assumption the fixture rests on. + +P3-T1's own acceptance condition is satisfied verbatim by the corrected form: the method exists in +`QfcItemController.InitializationTests.Part3.cs` with exactly that name, it asserts on both named +WebView2 properties, `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` is still +declared at line 131, and +`InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` at line 175. + +## Escalation + +This is a plan-contradiction, and it is escalated rather than absorbed silently. The instruction in +P3-T1's body (`assert false`) and the acceptance condition of P3-T4 (`2 passed, 0 failed`) cannot +both be satisfied, because the world-state the first predicts does not hold. The plan's own +governing rules were applied to break the tie: + +- the Open Question section directs that a measurement contradicting the plan's static reading be + recorded and execution continued, not that the remedy be narrowed, widened, or abandoned; +- the fail-closed evidence rule and the coverage-numbers section both require measured values and + forbid asserting a figure that was not observed. + +The remedy itself is untouched. No sleep, retry, `SpinWait`, or raised timeout constant was +introduced, no production file was changed, and no test was weakened to obtain a pass: the corrected +assertion states a stronger, measured fact than the authored one, which stated an unmeasured +prediction that is false. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/evidence-gitignore.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/evidence-gitignore.2026-08-23T20-57.md new file mode 100644 index 000000000..9ef6ed96e --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/evidence-gitignore.2026-08-23T20-57.md @@ -0,0 +1,50 @@ +# Remediation Baseline — Evidence `.gitignore` Verification and Append + +Timestamp: 2026-08-23T18-59 + +Command: +```bash +G=docs/features/active/winformspumphost-suite-determinism-511/evidence/.gitignore +# verify the five dictated lines each exist as their own non-comment line +for L in '*.trx' '*.coverage' '*.coveragexml' 'Deploy_*/' '20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_*/'; do grep -cxF "$L" $G; done +# append the Phase 3 scratch-directory pattern only if absent +grep -qxF 'r1-p*-t*/' $G || printf 'r1-p*-t*/\n' >> $G +git diff --stat -- $G +git check-ignore -q docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/r1-p3-t6/probe.trx +git check-ignore -q $G +``` + +EXIT_CODE: 0 + +Output Summary: + +The file already existed at 929 bytes, created alongside the raw-artifact disposition recorded in +`docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`. +It was not rewritten. Verification of the five dictated lines, each measured as an exact whole-line +match against a non-comment line: + +| Line | Whole-line match count | Verified | +| --- | --- | --- | +| `*.trx` | 1 | yes | +| `*.coverage` | 1 | yes | +| `*.coveragexml` | 1 | yes | +| `Deploy_*/` | 1 | yes | +| `20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_*/` | 1 | yes | + +Append performed: **yes**. The single line `r1-p*-t*/` was absent and was appended at the end of the +file, covering the Phase 3 per-run scratch directory `evidence/qa-gates/r1-p3-t6/`. Whole-line match +count after the append: 1. File size after the append: 939 bytes (929 + 10). + +No pre-existing line was removed, reordered, or altered. `git diff --stat` on the file reports +`1 file changed, 1 insertion(+)` with zero deletions, and the diff hunk is the single added line +`+r1-p*-t*/` at the end of the file. + +`Deploy_*/` was retained deliberately: it is the vstest deployment scratch directory whose default +name embeds the account and host, so removing that line would reintroduce a host-identifier leak. + +Ignore-behaviour verification: + +| Check | Exit code | Meaning | +| --- | --- | --- | +| `git check-ignore -q .../evidence/qa-gates/r1-p3-t6/probe.trx` | 0 | the new Phase 3 TRX path is ignored, closing the `git add -A` hazard | +| `git check-ignore -q .../evidence/.gitignore` | 1 | the `.gitignore` itself is not ignored and remains committable | diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/git-identity.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/git-identity.2026-08-23T20-57.md new file mode 100644 index 000000000..bc668c8c2 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/git-identity.2026-08-23T20-57.md @@ -0,0 +1,43 @@ +# Remediation Baseline — Git Identity + +Timestamp: 2026-08-23T18-59 + +Command: +``` +git rev-parse --abbrev-ref HEAD +git rev-parse HEAD +git merge-base origin/main HEAD +git status --porcelain | wc -l +``` + +EXIT_CODE: 0 + +Output Summary: + +| Field | Value | +| --- | --- | +| Branch | `bug/winformspumphost-suite-determinism-511-exec` | +| HEAD sha (provenance only) | `733b91ca71393f6723e2cdbf20a1e8ebee7cd1fc` | +| Merge base with `origin/main` (`$MergeBase`) | `f85a36faebaaec29fe5233c9d9f69d223d80e4c5` | +| `git status --porcelain` line count | 6 | + +The recorded merge-base sha is a 40-character hexadecimal string and is the commit `main` sits on +(`f85a36fa`), confirming the branch is rebased current. All later scope-lock tasks in this cycle gate +on tree invariants measured against `$MergeBase = f85a36faebaaec29fe5233c9d9f69d223d80e4c5`, never +against a pinned HEAD. + +The six porcelain lines at baseline are: + +``` + M .claude/agent-memory/atomic-planner/MEMORY.md + M .claude/agent-memory/atomic-planner/project_csharp_coverage_gate_jacoco_format.md + M docs/features/active/winformspumphost-suite-determinism-511/remediation-plan.2026-08-23T20-57.md +?? .claude/agent-memory/atomic-planner/csharpier-formatted-n-is-processed-count.md +?? .claude/agent-memory/atomic-planner/project_511_r1_preflight_delta_seams.md +?? docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/ +``` + +Two of them are prior-agent memory writes under `.claude/agent-memory/` (permitted by plan +prohibition 6 and admitted to the P4-T9 commit), one is this cycle's own plan file carrying the +P0-T1 through P0-T5 check-offs, and one is the evidence directory this artifact is being written +into. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/phase0-instructions-read.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/phase0-instructions-read.md new file mode 100644 index 000000000..f066b8388 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/phase0-instructions-read.md @@ -0,0 +1,150 @@ +# Phase 0 — Instructions Read (remediation cycle 1) + +Timestamp: 2026-08-23T18-59 + +Policy Order: `CLAUDE.md` -> `.claude/rules/general-code-change.md` -> `.claude/rules/general-unit-test.md` -> `.claude/rules/csharp.md` -> `docs/features/active/winformspumphost-suite-determinism-511/remediation-inputs.2026-08-23T20-57.md` + +## Files read in full + +| # | Path | Lines | Task | +| --- | --- | --- | --- | +| 1 | `CLAUDE.md` | 447 | P0-T1 | +| 2 | `.claude/rules/general-code-change.md` | 80 | P0-T2 | +| 3 | `.claude/rules/general-unit-test.md` | 105 | P0-T3 | +| 4 | `.claude/rules/csharp.md` | 96 | P0-T4 | +| 5 | `docs/features/active/winformspumphost-suite-determinism-511/remediation-inputs.2026-08-23T20-57.md` | 265 | P0-T4 | + +--- + +## P0-T1 — `CLAUDE.md` + +The file embeds four numbered policy sections that apply to every session without an explicit skill load: + +1. General Code Change Policy +2. General Unit Test Policy +3. C# Code Change Policy +4. C# Unit Test Policy + +### Policy Compliance Order (quoted verbatim from `CLAUDE.md`) + +> The four core policies below are embedded directly in this file and apply to every session without requiring explicit skill loads. Apply them in this order: +> +> 1. This file (CLAUDE.md) — all sections +> 2. General Code Change Policy (§ below) +> 3. General Unit Test Policy (§ below) +> 4. For C#: C# Code Change Policy (§ below) and C# Unit Test Policy (§ below) + +### C# Toolchain (quoted verbatim from `CLAUDE.md`) + +> 1. **Format**: `dotnet tool run csharpier format .` (verify: `dotnet tool run csharpier check .`; always via `dotnet tool run`, never a global install) +> 2. **Analyze**: `msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true` +> 3. **Type-check**: `msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true` +> 4. **Test**: `vstest.console.exe /EnableCodeCoverage` +> +> If any step fails, fix and restart from step 1. + +Also recorded from `CLAUDE.md` section C#6 (Naming, Docs, and Comments): "Comment **why**, not what. Keep comments synchronized with behavior." That clause is what makes remediation Finding D blocking. + +--- + +## P0-T2 — `.claude/rules/general-code-change.md` + +### File Size Limit (quoted verbatim) + +> ## File Size Limit +> +> - No production code, test code, or reusable script file may exceed **500 lines**. +> - Exceptions: temporary throwaway scripts created and deleted within an agent session; raw text fixtures for language-processing test data; Markdown documentation files. + +### Mandatory Toolchain Loop (quoted verbatim) + +> Run the full seven-stage toolchain in this exact order and repeat until all stages pass in a single pass: +> +> 1. **Formatting** (e.g., Black, Prettier, CSharpier, Invoke-Formatter) +> 2. **Linting** (e.g., Ruff, ESLint, PSScriptAnalyzer, .NET analyzers) +> 3. **Type checking** (e.g., Pyright, TSC, nullable analysis; skip for PowerShell) +> 4. **Architecture-boundary tests** (e.g., dependency-cruiser, NetArchTest.Rules) +> 5. **Unit tests** (e.g., Pytest, Jest, MSTest, Pester) including property-based tests where applicable per `quality-tiers.md` +> 6. **Contract / schema compatibility checks** (e.g., oasdiff, schema-snapshot diff) +> 7. **Integration tests** +> +> **Restart from step 1** if any stage fails or auto-fixes any files. Do not stop the loop until all seven stages complete without errors in a single pass. + +--- + +## P0-T3 — `.claude/rules/general-unit-test.md` + +### Coverage thresholds (quoted verbatim) + +> - **Line coverage must remain >= 85% across all tiers (T1–T4).** +> - **Branch coverage must remain >= 75% across all tiers (T1–T4) for languages whose coverage tooling measures branch coverage.** PowerShell (Pester) and bash (kcov) are the exceptions: neither tool measures branch coverage in any output format, so only the line threshold applies to them and there is no branch-coverage gate. This is a threshold exemption only; PowerShell and bash production files remain in the coverage denominator under the Coverage Exclusion Policy below. +> - Code changes or refactors must not reduce coverage for the lines that were changed. + +`CLAUDE.md` section UT2 additionally states "Repository-wide line coverage must remain `>= 80%`" and "Any new modules, classes, or methods added must target `>= 90%` coverage." The stricter 85% line / 75% branch figures from this rule file are the ones this cycle's P3-T9 gate asserts. + +### Determinism Infrastructure — banned APIs in test code (quoted verbatim) + +> - **Banned APIs in test code** — `setTimeout`, `Thread.Sleep`, `Task.Delay`, real wall-clock waits, and `Date.now()` outside the clock interface are prohibited in tests. + +That clause is the basis of remediation prohibition 5: this cycle introduces no `Thread.Sleep`, `Task.Delay`, `SpinWait`, retry loop, or raised timeout constant. + +--- + +## P0-T4a — `.claude/rules/csharp.md` + +### The four toolchain commands (quoted verbatim) + +> 1. **Formatting — CSharpier**: All C# source files must be formatted with CSharpier. Do not use `dotnet format`. Run `dotnet tool restore` first when the manifest tool has not been restored. Apply formatting with `dotnet tool run csharpier format .` and verify read-only with `dotnet tool run csharpier check .`. Always invoke through `dotnet tool run` so the manifest-pinned CSharpier version is used. +> 2. **Linting — .NET Analyzers**: C# code must pass Roslyn/.NET analyzer diagnostics. Command: `msbuild .sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true`. `/t:Rebuild` is intentional for a warm local worktree: `/t:Build` can skip `CoreCompile` through MSBuild incrementality and exit 0 without running analyzers. CI may retain `/t:Build` on a cold checkout. +> 3. **Type Checking — Nullable Analysis**: Compiler and nullable-flow diagnostics must pass with warnings as errors. Command: `msbuild .sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true`. `/t:Rebuild` is required locally so compiler and nullable-flow diagnostics actually run. Projects opt into nullable per file with `#nullable enable`; do not pass `/p:Nullable=enable`, which opts every unannotated file in at once. +> 4. **Testing — MSTest + Moq + FluentAssertions**: Run tests with: `vstest.console.exe /EnableCodeCoverage` + +### The six "Prohibited Behaviors" bullets (quoted verbatim) + +> - Broad refactors across unrelated projects or files. +> - Introducing heavy generic abstraction frameworks without need. +> - Creating analyzer debt and deferring cleanup. +> - Weakening assertions or relaxing test expectations to make tests pass. +> - Adding sleeps, retries, or timing hacks to mask flaky behavior. +> - Reporting success without running the required toolchain. + +--- + +## P0-T4b — `remediation-inputs.2026-08-23T20-57.md` (sole requirements source) + +### The seven remediation exit criteria, Part 5 (quoted verbatim; criterion 7 added by the Part 6 addendum) + +> The cycle exits when the re-audit (`code-review`, `feature-audit`, `policy-audit`) reports a +> combined blocking count of zero. Specifically: +> +> 1. Both comment blocks state the measured truth, including the present redundancy of the read. +> 2. Spec AC 6 is revised to the measured inherited state; AC 3 is revised to the owned-class scope +> citing #594; AC 8, AC 13 and AC 14 are satisfied and checked off with cited evidence. +> 3. P4-T2's zero condition is narrowed to owned classes and recorded as satisfied on existing +> evidence. +> 4. The Phase 5 toolchain completes green in a single final pass with numeric coverage recorded. +> 5. The evidence `.gitignore` exists and the raw `.trx` / `.coverage` files are removed. +> 6. No artifact claims this branch repairs #511 or #571, and no closing keyword for either appears +> anywhere in the branch or in the pull-request body. +> 7. The spec's `## Scope & Non-Goals` "In scope" bullets no longer assert the falsified premise +> (see Part 6). + +Note on the quotation above: exit criterion 6 is reproduced here with its two verb phrases restated +("repairs" in place of the source's closing-keyword stem) so that this artifact carries no match of +the scan regex `(fix|clos|resolv)[a-z]* #(511|571)`. The requirements input itself is exempt from +the scan by the plan-preamble carve-out; this artifact is not among the five files P4-T8 scans, and +is written to carry zero matches regardless. + +### Findings carried into this cycle + +- **A, B, C** — accepted as accurate; addressed by re-scoping the claim, not by changing code. +- **D** (blocking) — two inserted comment blocks assert the opposite of what was measured. Addressed by Phase 1. +- **E** (blocking) — spec acceptance criterion 6 is unsatisfiable as worded, plus the Part 6 `## Scope & Non-Goals` addendum. Addressed by Phase 2. +- **F** (resolvable) — the absolute-zero gate spans a sibling-owned assembly. Addressed by P2-T3. + +### Orchestrator decisions consumed + +1. The pull request targets `main`, not the epic integration branch; CI is a real gate. +2. The defensive handle read is retained, not deleted; only its comment changes. +3. Raw vstest artifacts are gitignored at the evidence root, then deleted (P0-T9, P4-T10). +4. Follow-up issues #592, #594, #597 already exist; no `gh issue create` is executed in this cycle. Issues #511 and #571 are both CLOSED as NOT_PLANNED, superseded by #592. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/toolchain-precheck.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/toolchain-precheck.2026-08-23T20-57.md new file mode 100644 index 000000000..aeb6932d9 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/toolchain-precheck.2026-08-23T20-57.md @@ -0,0 +1,35 @@ +# Remediation Baseline — Toolchain Precheck + +Timestamp: 2026-08-23T18-59 + +Command: +```powershell +dotnet --version +Test-Path -LiteralPath "packages" -PathType Container +Test-Path -LiteralPath "packages/Meziantou.Analyzer.3.0.156/analyzers/dotnet/roslyn5.0/cs/Meziantou.Analyzer.dll" -PathType Leaf +Test-Path -LiteralPath "packages/Roslynator.Analyzers.4.16.0/analyzers/dotnet/roslyn4.7/cs/Roslynator.CSharp.Analyzers.dll" -PathType Leaf +``` +(run from the worktree root `.claude/worktrees/agent-ad37a256a0fb60243`) + +EXIT_CODE: 0 + +Output Summary: + +| Check | Result | Expected | +| --- | --- | --- | +| `dotnet --version` | `8.0.205` | `8.0.205` | +| `packages/` directory exists at worktree root | True | True | +| `packages/Meziantou.Analyzer.3.0.156/analyzers/dotnet/roslyn5.0/cs/Meziantou.Analyzer.dll` exists | True | True | +| `packages/Roslynator.Analyzers.4.16.0/analyzers/dotnet/roslyn4.7/cs/Roslynator.CSharp.Analyzers.dll` exists | True | True | + +All four prerequisites the original Phase 0 provisioned are still in place. No re-provisioning was +required, and no tracked file was edited by this task. + +Raw command output: + +``` +dotnet --version = 8.0.205 +packages dir = True +meziantou = True +roslynator = True +``` diff --git a/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/touched-files-state.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/touched-files-state.2026-08-23T20-57.md new file mode 100644 index 000000000..cd669bead --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/touched-files-state.2026-08-23T20-57.md @@ -0,0 +1,36 @@ +# Remediation Baseline — Touched-Files State + +Timestamp: 2026-08-23T18-59 + +Command: +```powershell +$files = @( + "QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs", + "QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs", + "QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs") +foreach ($f in $files) { + $lc = (Get-Content -LiteralPath $f).Count + $hc = (Select-String -LiteralPath $f -SimpleMatch "viewer.Handle").Count + Write-Output ("{0} lines={1} viewerHandle={2}" -f $f, $lc, $hc) +} +``` + +EXIT_CODE: 0 + +Output Summary: + +| File | `Get-Content` line count | Expected | `viewer.Handle` matches | +| --- | --- | --- | --- | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` | 416 | 416 | 1 | +| `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` | 470 | 470 | 1 | +| `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` | 398 | 398 | 0 (not asserted; this file carries no defensive read) | + +All five asserted counts match the plan's expected values exactly. No drift is recorded. + +Raw command output: + +``` +QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs lines=416 viewerHandle=1 +QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs lines=470 viewerHandle=1 +QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs lines=398 viewerHandle=0 +``` diff --git a/docs/features/active/winformspumphost-suite-determinism-511/feature-audit.2026-08-24T00-01.md b/docs/features/active/winformspumphost-suite-determinism-511/feature-audit.2026-08-24T00-01.md new file mode 100644 index 000000000..f374a56f2 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/feature-audit.2026-08-24T00-01.md @@ -0,0 +1,69 @@ +# Feature Audit — winformspumphost-suite-determinism-511 + +- Timestamp: 2026-08-24T00-01 (UTC) +- Review cycle: re-audit after remediation cycle 1 + +## Scope and Baseline + +- Base branch (resolved): `main` +- Merge base: `f85a36faebaaec29fe5233c9d9f69d223d80e4c5` +- Head: `b4d47adc369d021f6fb4eff092f419dc49e9a5e5` (branch `bug/winformspumphost-suite-determinism-511-exec`; verified equal to `git rev-parse HEAD`; working tree clean) +- Work mode: `full-bug` (persisted `- Work Mode: full-bug` marker in `issue.md`) +- Acceptance-criteria source: `docs/features/active/winformspumphost-suite-determinism-511/spec.md`, section `## Acceptance Criteria` — the sole authoritative source for this mode. `user-story.md` does not exist and is not required. +- Branch diff: 97 files — 3 C# test files under `QuickFiler.Test/Controllers/` (+124/-0), 68 files under the feature folder (spec re-scope, decision record, remediation inputs/plan, evidence tree), 26 files under `.claude/agent-memory/`. +- Context: issues #511 and #571 are CLOSED as NOT_PLANNED, superseded by #592 (open). #594 and #597 are open. The recorded decision (`decision-record.2026-08-23T20-40.md`) is that this branch does not claim to repair #511/#571; its delivered value is the fixture hardening, the two regression tests pinning the measured inherited handle state, and the mechanism finding. +- `origin/main` has advanced two commits past the merge base (PR #600, a 1,989-file documentation archive move). Verified non-intersecting with this branch's diff paths; the merge base remains a valid baseline for this audit. + +## Acceptance Criteria Inventory + +`spec.md` `## Acceptance Criteria` contains 14 checkbox criteria. At review time all 14 are +checked (`[x]`). Criteria 3 and 6 carry dated revision markers ("Revised 2026-08-23 per +remediation Finding F / Finding E"); the revisions were ratified through +`remediation-inputs.2026-08-23T20-57.md` and the maintainer decision record. + +## Acceptance Criteria Evaluation + +| # | Criterion (abbreviated) | Verdict | Evidence | +| --- | --- | --- | --- | +| 1 | `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` passes in 10/10 consecutive full nine-assembly runs, TRX evidence under `evidence/regression-testing/` | PASS | `named-tests-ten-runs.2026-08-21T18-10.md` (Passed 10/10, per-TRX). Note: the raw TRX were subsequently deleted at maintainer instruction after fidelity verification; the distilled record is the evidence of record (`raw-vstest-artifact-disposition.2026-08-23T21-40.md`). Wording drift recorded as CR-2, non-blocking. | +| 2 | `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` passes in the same 10/10 runs | PASS | Same records as AC 1. | +| 3 | Ten runs under induced CPU load with `/EnableCodeCoverage /InIsolation /TestCaseFilter:"TestCategory!=LiveOutlook"`; zero failures in `QuickFiler.Test`; run 5's single sibling `UtilitiesCS.Test` failure attributed to #594 (revised per Finding F) | PASS | `determinism-ten-runs.2026-08-21T18-10.md` (9/10 suite-green; run 5 failed=1, FQN matches the #594 flake); `load-generator-start/stop` records; `p4-t2-narrowing-rationale.2026-08-23T20-57.md`. The revised wording matches the measured record exactly; the narrowing follows the ratified owned-class precedent. | +| 4 | Empirical pre-fix baseline: per-run pass/fail of both named tests plus observed `IsHandleCreated`, across ten runs | PASS | `prefix-baseline.2026-08-21T18-10.md` — twenty-row measured table (10 class-filtered + 10 full-suite), every cell observed from TRX, `IsHandleCreated: true` on every run — the measurement that falsified the premise. | +| 5 | `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` exists in Part3.cs, asserts `IsHandleCreated` true, and passes | PASS | Present at `Part3.cs:301`; asserts `IsHandleCreated.Should().BeTrue()` and `InvokeRequired` false on the pump thread; Passed 10/10 (`regression-tests-ten-runs`) and in the final 6,459/6,459 run. | +| 6 | `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` exists, asserts the measured inherited state (both WebView2 children handle-created at construction via `ISupportInitialize.EndInit()`), and passes (revised per Finding E) | PASS | Present at `Part3.cs:356`; asserts both children `IsHandleCreated` true with mechanism-stating `because:` messages and a "Measured, not predicted" remarks block; Passed 10/10 and in the final run; measurement provenance in `webview-child-handle-measurement.2026-08-21T18-10.md`. | +| 7 | Zero diff hunks in `QfcItemController.Initialization.cs` and `QfcItemController.ViewerSetup.cs`; #230 de-exemption blocks and retained `[ExcludeFromCodeCoverage]` intact | PASS | Reviewer re-ran `git diff --numstat` on both files: zero output. `#230` literals present (8 occurrences in Initialization.cs; ViewerSetup.cs block at `:254`); `ExcludeFromCodeCoverage` retained (`ViewerSetup.cs:41`). | +| 8 | All 21 pump-host call sites pass in the final run (13 self-tests + 8 consumer tests) | PASS | `pumphost-selftests.2026-08-21T18-10.md` (13/13), `consumer-tests.2026-08-21T18-10.md` (8/8), corroborated by the final 0-failure suite run (`remediation-suite-run.2026-08-23T20-57.md`). | +| 9 | Diff lists exactly three code files, all under `QuickFiler.Test/`; no `QuickFiler/` file, no `*.csproj`, no `.claude/` path other than `.claude/agent-memory/` | PASS | Reviewer re-ran `git diff --name-only f85a36fa..b4d47adc`: code-file set is exactly the three named paths; prohibited counts all zero; `.claude/` paths are exclusively `agent-memory/`. Matches `scope-lock-after-comment-fix.2026-08-23T20-57.md`. | +| 10 | `QfcItemController_SeamFactoryTests` and `QfcItemController_InitializationTests` both pass in the same run; `UiThreadDispatcherGate` and `SwapUiThreadDispatcher` retain acquire-and-release structure | PASS | Final run 6,459/6,459 with 0 failures covers both classes; structure verified at `Part2.cs:51` (gate) and `:148` (swap helper; spec cites the pre-insertion line `:139` — drift noted as CR-5, structure intact). `gate-structure-part2` / `gate-serialization` records corroborate. | +| 11 | Every changed file under 500 lines (was 409 / 467 / 290) | PASS | Independently re-measured: 418 / 474 / 398. Matches `remediation-file-size-audit.2026-08-23T20-57.md`. | +| 12 | No `Thread.Sleep`, `Task.Delay`, `SpinWait`, retry loop, or raised timeout constant; `PumpTimeoutMs = 60000`, `TimeoutMs = 30000` unchanged | PASS | Reviewer added-line scan of the branch diff: only `[Timeout(PumpTimeoutMs)]` references to the existing constant; constants verified unchanged at 60000. `no-timing-hacks.2026-08-21T18-10.md` corroborates. | +| 13 | Five-step toolchain green in a single final pass; coverage captured under `evidence/qa-gates/`; `QuickFiler` line coverage >= pre-fix baseline | PASS | `remediation-clean-pass.2026-08-23T20-57.md` (single pass, 0 restarts); `remediation-coverage.2026-08-23T20-57.md` (85.59% repo line / 79.06% repo branch / 81.08% QuickFiler package); delta vs. baseline +0.15 pp package, +0.04 pp repo, no per-class regression (`remediation-coverage-delta`). | +| 14 | `## Rollout & Follow-up` records the visible-window half as out of scope with its re-attribution and names the filed follow-up issue | PASS | Spec `## Rollout & Follow-up` names #592 (superseding #511/#571), #594, and #597; the visible-window re-attribution to `UtilitiesCS.Test/Threading/ProgressViewer_Tests.cs` is recorded with the section stating no new issue remains to be filed. | + +## Summary + +- 14 of 14 acceptance criteria evaluate PASS. 0 FAIL, 0 PARTIAL, 0 UNVERIFIED. +- The two criteria revised this cycle (AC 3, AC 6) were revised through the ratified remediation + process with dated markers, and the revised text matches the measured evidence exactly. +- Non-blocking residuals are recorded in `code-review.2026-08-24T00-01.md` (CR-1 stale Root Cause + Analysis narrative; CR-2 AC-wording drift against the maintainer-instructed raw-TRX deletion; + CR-5 stale line citation in AC 10). +- Blocking findings contributed by this feature audit: 0. +- The branch honours the recorded decision that it does not claim to repair #511 or #571: no + closing keyword appears in any commit message in range, and the PR is to be opened against + `main` without closing keywords for either issue. + +## Acceptance Criteria Check-off + +All 14 criteria were already checked (`[x]`) in `spec.md` by remediation cycle 1's executor +(tasks P4-T1 through P4-T6 of `remediation-plan.2026-08-23T20-57.md`), each with cited evidence +recorded in `evidence/other/ac-status-summary.2026-08-23T20-57.md`. This review verified each +check-off independently and confirms the checkbox state matches the PASS evaluations above. No +new check-offs were required and none were made; no criterion was un-checked. + +### Acceptance Criteria Status +- Source: docs/features/active/winformspumphost-suite-determinism-511/spec.md +- Total AC items: 14 +- Checked off (delivered): 14 +- Remaining (unchecked): 0 +- Items remaining: none diff --git a/docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md b/docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md index 78640ecb1..f46d4e98f 100644 --- a/docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md +++ b/docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md @@ -121,66 +121,68 @@ Non-negotiable command facts: ### Phase 0 — Policy Reads and Baseline Capture -- [ ] [P0-T1] Read `CLAUDE.md` in full and record the four numbered policy sections it embeds (General Code Change, General Unit Test, C# Code Change, C# Unit Test). Acceptance: the file has been read end to end and its Policy Compliance Order list is quoted in the Phase 0 artifact. -- [ ] [P0-T2] Read `.claude/rules/general-code-change.md` in full. Acceptance: the 500-line file-size limit and the mandatory toolchain loop are quoted in the Phase 0 artifact. -- [ ] [P0-T3] Read `.claude/rules/general-unit-test.md` in full. Acceptance: the coverage thresholds and the Determinism Infrastructure banned-API list are quoted in the Phase 0 artifact. -- [ ] [P0-T4] Read `.claude/rules/csharp.md` in full. Acceptance: the four toolchain commands and the six "Prohibited Behaviors" bullets are quoted in the Phase 0 artifact. -- [ ] [P0-T5] Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/phase0-instructions-read.md` carrying `Timestamp:`, `Policy Order:` (the four files in the order read), and an explicit list of the files read with the quoted content required by P0-T1 through P0-T4. Acceptance: the file exists and all three required fields are present and non-empty. -- [ ] [P0-T6] Record git identity baseline: current branch name, `git rev-parse HEAD`, `git merge-base origin/epic/quickfiler-suite-determinism-foundation-integration HEAD` (falling back to `git merge-base origin/main HEAD` and recording which was used), and `git status --porcelain`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/git-identity.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` carrying the branch, the HEAD sha, the merge-base sha, and the porcelain line count. Acceptance: the artifact exists, all four fields are present, and the recorded merge-base sha is a 40-character hex string. Note: the HEAD sha is recorded as provenance only. No later task gates on a pinned sha; later scope-lock tasks gate on tree invariants against the recorded merge base. -- [ ] [P0-T7] Record the pre-change line count of each of the three files by running `Get-Content -LiteralPath QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs, QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs, QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` once per file and counting the returned lines. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/file-size-budget.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing the three counts. Acceptance: the artifact exists and the three recorded counts are 409, 467, and 290 respectively; a different count is recorded verbatim and flagged as drift rather than silently adjusted. -- [ ] [P0-T8] Provision the worktree-local .NET SDK that `global.json` requires. `global.json` pins `sdk.version` to `8.0.205` with `rollForward: latestFeature` and a `paths` list naming `.dotnet-sdk` ahead of the host fallback. The directory `.dotnet-sdk` does not exist in this worktree and the host SDK cannot satisfy that pin, so `dotnet --version` run from the worktree root currently prints the `global.json` error message instead of a version, and every `dotnet` and CSharpier task in this plan is unrunnable until the condition is fixed. Confirm that pre-state, then run `pwsh -NoProfile -File .\scripts\vscode\Install-RepoDotNetSdk.ps1` from the worktree root; alternatively mirror the already-populated `.dotnet-sdk` tree from the main checkout at `C:\Users\DanMoisan\repos\TaskMaster` into the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/dotnet-sdk-bootstrap.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the pre-state, the provisioning method used, and the post-state. Acceptance: `dotnet --version` executed from the worktree root prints `8.0.205`, `dotnet --list-sdks` executed from the worktree root includes an entry whose path ends `.dotnet-sdk\sdk`, and `git status --porcelain` reports no entry for `.dotnet-sdk` because `.gitignore:350` ignores it. CI is unaffected by this condition because the `windows-latest` image preinstalls an 8.0.x SDK that satisfies the host fallback; this is a worktree-provisioning gap only. -- [ ] [P0-T9] Restore the solution's NuGet packages, which are absent in this worktree. Confirm that the directory `packages` does not exist at the worktree root, then run `pwsh -NoProfile -Command 'nuget restore TaskMaster.sln'` from the worktree root. This mirrors the CI step at `.github/workflows/_build-analyzers.yml:45` and is required because every project declares an `EnsureNuGetPackageBuildImports` target whose `Error` fires at `BeforeTargets="PrepareForBuild"` when the `packages` tree is missing; `QuickFiler.Test/QuickFiler.Test.csproj:452-460` is the representative instance. Without the restore, every msbuild task in this plan hard-fails before compilation and every `Reference` hint path under the `packages` tree is unresolvable. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nuget-restore.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the installed-package count. Acceptance: `EXIT_CODE: 0`, the `packages` directory exists at the worktree root after the run, and `git status --porcelain` reports zero entries whose path begins with the restored packages directory name, because `.gitignore:191` carries the pattern that ignores its contents. Restoring therefore does not dirty the tree and does not endanger the clean-tree acceptance in P6-T18. -- [ ] [P0-T10] Back-fill the two analyzer package versions the project files reference but `packages.config` no longer pins. All 16 first-party project files carry unconditional `Analyzer` entries for `..\packages\Meziantou.Analyzer.3.0.156\analyzers\dotnet\roslyn5.0\cs\Meziantou.Analyzer.dll` and the four `..\packages\Roslynator.Analyzers.4.16.0\analyzers\dotnet\roslyn4.7\cs\` DLLs (`QuickFiler.Test/QuickFiler.Test.csproj:474-478`), while all 16 `packages.config` files pin `Meziantou.Analyzer 3.0.174` and `Roslynator.Analyzers 4.16.1`. csc receives every `Analyzer` path unconditionally and reports `error CS0006` when the file is absent, so the P0-T9 restore alone leaves every msbuild task in this plan red. Run `pwsh -NoProfile -Command 'nuget install Meziantou.Analyzer -Version 3.0.156 -OutputDirectory packages'` and `pwsh -NoProfile -Command 'nuget install Roslynator.Analyzers -Version 4.16.0 -OutputDirectory packages'` from the worktree root; alternatively copy the two already-populated folders from the main checkout at `C:\Users\DanMoisan\repos\TaskMaster\packages\`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-package-backfill.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording both commands and the resulting folder names. Acceptance: both commands record `EXIT_CODE: 0`; the files `packages/Meziantou.Analyzer.3.0.156/analyzers/dotnet/roslyn5.0/cs/Meziantou.Analyzer.dll` and `packages/Roslynator.Analyzers.4.16.0/analyzers/dotnet/roslyn4.7/cs/Roslynator.CSharp.Analyzers.dll` both exist; and `git status --porcelain` reports zero entries whose path begins with the packages directory name, because `.gitignore:191` ignores that tree. This back-fill installs into the untracked packages tree and edits no tracked file, so Binding Constraint 1 and the P6-T11 scope lock are both preserved. -- [ ] [P0-T11] Run `dotnet tool restore` from the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/tool-restore.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` naming the restored CSharpier version. Acceptance: `EXIT_CODE: 0` and the recorded CSharpier version is 1.2.6. -- [ ] [P0-T12] Run `dotnet tool run csharpier check .` read-only from the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/csharpier-check.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the number of files reported as unformatted. Acceptance: the artifact exists with all four fields; the exit code is recorded verbatim whatever it is, and a non-zero baseline exit code is recorded as a pre-existing condition rather than repaired here. -- [ ] [P0-T13] Run `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true'` from the worktree root, capturing the full build log to `coverage\analyzer-baseline.log`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-gate.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the warning count, the error count, and the count of log lines matching `Skipping target "CoreCompile"`. Acceptance: `EXIT_CODE: 0` and the recorded `Skipping target "CoreCompile"` count is exactly 0, proving the analyzers actually ran. This plan makes no prediction about the warning count; record whatever the build reports. The analyzer version skew described in the Binding Constraints note is already remedied by the P0-T10 back-fill, so every `Analyzer` item path resolves by the time this task runs and no `CS0006` diagnostic from that cause should appear. If one does, the back-fill did not take effect: return to P0-T10 rather than editing any project file. -- [ ] [P0-T14] Run `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true'` from the worktree root, capturing the log to `coverage\nullable-baseline.log`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nullable-gate.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the error count and the count of log lines matching `Skipping target "CoreCompile"`. Acceptance: `EXIT_CODE: 0` and the recorded `Skipping target "CoreCompile"` count is exactly 0. Confirm in the artifact that the command carried no `/p:Nullable=enable`. -- [ ] [P0-T15] Run the full nine-assembly suite once with the mandated command shape: the resolved `vstest.console.exe`, the nine assembly paths from the canonical assembly list above, `/EnableCodeCoverage`, `/InIsolation`, `/TestCaseFilter:"TestCategory!=LiveOutlook"`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/p0-t15`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/suite-run.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording total, passed, failed, and skipped counts plus the TRX path. Acceptance: the artifact exists with all four fields, the TRX file named in `Output Summary:` exists under `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/p0-t15/` and is the only TRX file in that subdirectory, and the recorded total exceeds 1,000 tests, confirming all nine assemblies loaded. If roughly 1,695 failures appear with empty messages, `/InIsolation` was omitted; re-run with the flag and record the correction. Do not "fix" the phantom failures. -- [ ] [P0-T16] Capture baseline numeric coverage by running `pwsh -NoProfile -File .\scripts\vscode\Invoke-MSTestWithCoverage.ps1 -SearchRoot . -CoverageOutput coverage\baseline.cobertura.xml` from the worktree root, then read the root `line-rate` and `branch-rate` attributes, the `QuickFiler` package `line-rate`, and the `line-rate` of every Cobertura class whose `filename` begins `QuickFiler\Controllers\QfcItemController`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording all four figures as numeric percentages to two decimal places. Acceptance: the artifact exists, the script reported exactly 9 discovered test assemblies, and no coverage field contains the token `UNVERIFIED` or an empty value. -- [ ] [P0-T17] Record the Python-toolchain absence finding. Confirm by directory listing that `scripts/dev_tools/` does not exist and that no `pyproject.toml` exists at the worktree root, then write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/no-python-toolchain.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` stating that any skill step naming a Python dev-tools module is unrunnable by absence and is reported as such rather than fabricated or silently skipped. Acceptance: the artifact exists with all four fields and records both negative existence checks. +- [x] [P0-T1] Read `CLAUDE.md` in full and record the four numbered policy sections it embeds (General Code Change, General Unit Test, C# Code Change, C# Unit Test). Acceptance: the file has been read end to end and its Policy Compliance Order list is quoted in the Phase 0 artifact. +- [x] [P0-T2] Read `.claude/rules/general-code-change.md` in full. Acceptance: the 500-line file-size limit and the mandatory toolchain loop are quoted in the Phase 0 artifact. +- [x] [P0-T3] Read `.claude/rules/general-unit-test.md` in full. Acceptance: the coverage thresholds and the Determinism Infrastructure banned-API list are quoted in the Phase 0 artifact. +- [x] [P0-T4] Read `.claude/rules/csharp.md` in full. Acceptance: the four toolchain commands and the six "Prohibited Behaviors" bullets are quoted in the Phase 0 artifact. +- [x] [P0-T5] Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/phase0-instructions-read.md` carrying `Timestamp:`, `Policy Order:` (the four files in the order read), and an explicit list of the files read with the quoted content required by P0-T1 through P0-T4. Acceptance: the file exists and all three required fields are present and non-empty. +- [x] [P0-T6] Record git identity baseline: current branch name, `git rev-parse HEAD`, `git merge-base origin/epic/quickfiler-suite-determinism-foundation-integration HEAD` (falling back to `git merge-base origin/main HEAD` and recording which was used), and `git status --porcelain`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/git-identity.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` carrying the branch, the HEAD sha, the merge-base sha, and the porcelain line count. Acceptance: the artifact exists, all four fields are present, and the recorded merge-base sha is a 40-character hex string. Note: the HEAD sha is recorded as provenance only. No later task gates on a pinned sha; later scope-lock tasks gate on tree invariants against the recorded merge base. +- [x] [P0-T7] Record the pre-change line count of each of the three files by running `Get-Content -LiteralPath QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs, QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs, QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` once per file and counting the returned lines. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/file-size-budget.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing the three counts. Acceptance: the artifact exists and the three recorded counts are 409, 467, and 290 respectively; a different count is recorded verbatim and flagged as drift rather than silently adjusted. +- [x] [P0-T8] Provision the worktree-local .NET SDK that `global.json` requires. `global.json` pins `sdk.version` to `8.0.205` with `rollForward: latestFeature` and a `paths` list naming `.dotnet-sdk` ahead of the host fallback. The directory `.dotnet-sdk` does not exist in this worktree and the host SDK cannot satisfy that pin, so `dotnet --version` run from the worktree root currently prints the `global.json` error message instead of a version, and every `dotnet` and CSharpier task in this plan is unrunnable until the condition is fixed. Confirm that pre-state, then run `pwsh -NoProfile -File .\scripts\vscode\Install-RepoDotNetSdk.ps1` from the worktree root; alternatively mirror the already-populated `.dotnet-sdk` tree from the main checkout at `` into the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/dotnet-sdk-bootstrap.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the pre-state, the provisioning method used, and the post-state. Acceptance: `dotnet --version` executed from the worktree root prints `8.0.205`, `dotnet --list-sdks` executed from the worktree root includes an entry whose path ends `.dotnet-sdk\sdk`, and `git status --porcelain` reports no entry for `.dotnet-sdk` because `.gitignore:350` ignores it. CI is unaffected by this condition because the `windows-latest` image preinstalls an 8.0.x SDK that satisfies the host fallback; this is a worktree-provisioning gap only. +- [x] [P0-T9] Restore the solution's NuGet packages, which are absent in this worktree. Confirm that the directory `packages` does not exist at the worktree root, then run `pwsh -NoProfile -Command 'nuget restore TaskMaster.sln'` from the worktree root. This mirrors the CI step at `.github/workflows/_build-analyzers.yml:45` and is required because every project declares an `EnsureNuGetPackageBuildImports` target whose `Error` fires at `BeforeTargets="PrepareForBuild"` when the `packages` tree is missing; `QuickFiler.Test/QuickFiler.Test.csproj:452-460` is the representative instance. Without the restore, every msbuild task in this plan hard-fails before compilation and every `Reference` hint path under the `packages` tree is unresolvable. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nuget-restore.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the installed-package count. Acceptance: `EXIT_CODE: 0`, the `packages` directory exists at the worktree root after the run, and `git status --porcelain` reports zero entries whose path begins with the restored packages directory name, because `.gitignore:191` carries the pattern that ignores its contents. Restoring therefore does not dirty the tree and does not endanger the clean-tree acceptance in P6-T18. +- [x] [P0-T10] Back-fill the two analyzer package versions the project files reference but `packages.config` no longer pins. All 16 first-party project files carry unconditional `Analyzer` entries for `..\packages\Meziantou.Analyzer.3.0.156\analyzers\dotnet\roslyn5.0\cs\Meziantou.Analyzer.dll` and the four `..\packages\Roslynator.Analyzers.4.16.0\analyzers\dotnet\roslyn4.7\cs\` DLLs (`QuickFiler.Test/QuickFiler.Test.csproj:474-478`), while all 16 `packages.config` files pin `Meziantou.Analyzer 3.0.174` and `Roslynator.Analyzers 4.16.1`. csc receives every `Analyzer` path unconditionally and reports `error CS0006` when the file is absent, so the P0-T9 restore alone leaves every msbuild task in this plan red. Run `pwsh -NoProfile -Command 'nuget install Meziantou.Analyzer -Version 3.0.156 -OutputDirectory packages'` and `pwsh -NoProfile -Command 'nuget install Roslynator.Analyzers -Version 4.16.0 -OutputDirectory packages'` from the worktree root; alternatively copy the two already-populated folders from the main checkout at `\packages\`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-package-backfill.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording both commands and the resulting folder names. Acceptance: both commands record `EXIT_CODE: 0`; the files `packages/Meziantou.Analyzer.3.0.156/analyzers/dotnet/roslyn5.0/cs/Meziantou.Analyzer.dll` and `packages/Roslynator.Analyzers.4.16.0/analyzers/dotnet/roslyn4.7/cs/Roslynator.CSharp.Analyzers.dll` both exist; and `git status --porcelain` reports zero entries whose path begins with the packages directory name, because `.gitignore:191` ignores that tree. This back-fill installs into the untracked packages tree and edits no tracked file, so Binding Constraint 1 and the P6-T11 scope lock are both preserved. +- [x] [P0-T11] Run `dotnet tool restore` from the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/tool-restore.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` naming the restored CSharpier version. Acceptance: `EXIT_CODE: 0` and the recorded CSharpier version is 1.2.6. +- [x] [P0-T12] Run `dotnet tool run csharpier check .` read-only from the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/csharpier-check.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the number of files reported as unformatted. Acceptance: the artifact exists with all four fields; the exit code is recorded verbatim whatever it is, and a non-zero baseline exit code is recorded as a pre-existing condition rather than repaired here. +- [x] [P0-T13] Run `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true'` from the worktree root, capturing the full build log to `coverage\analyzer-baseline.log`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/analyzer-gate.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the warning count, the error count, and the count of log lines matching `Skipping target "CoreCompile"`. Acceptance: `EXIT_CODE: 0` and the recorded `Skipping target "CoreCompile"` count is exactly 0, proving the analyzers actually ran. This plan makes no prediction about the warning count; record whatever the build reports. The analyzer version skew described in the Binding Constraints note is already remedied by the P0-T10 back-fill, so every `Analyzer` item path resolves by the time this task runs and no `CS0006` diagnostic from that cause should appear. If one does, the back-fill did not take effect: return to P0-T10 rather than editing any project file. +- [x] [P0-T14] Run `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true'` from the worktree root, capturing the log to `coverage\nullable-baseline.log`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/nullable-gate.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the error count and the count of log lines matching `Skipping target "CoreCompile"`. Acceptance: `EXIT_CODE: 0` and the recorded `Skipping target "CoreCompile"` count is exactly 0. Confirm in the artifact that the command carried no `/p:Nullable=enable`. +- [x] [P0-T15] Run the full nine-assembly suite once with the mandated command shape: the resolved `vstest.console.exe`, the nine assembly paths from the canonical assembly list above, `/EnableCodeCoverage`, `/InIsolation`, `/TestCaseFilter:"TestCategory!=LiveOutlook"`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/p0-t15`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/suite-run.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording total, passed, failed, and skipped counts plus the TRX path. Acceptance: the artifact exists with all four fields, the TRX file named in `Output Summary:` exists under `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/p0-t15/` and is the only TRX file in that subdirectory, and the recorded total exceeds 1,000 tests, confirming all nine assemblies loaded. If roughly 1,695 failures appear with empty messages, `/InIsolation` was omitted; re-run with the flag and record the correction. Do not "fix" the phantom failures. +- [x] [P0-T16] Capture baseline numeric coverage by running `pwsh -NoProfile -File .\scripts\vscode\Invoke-MSTestWithCoverage.ps1 -SearchRoot . -CoverageOutput coverage\baseline.cobertura.xml` from the worktree root, then read the root `line-rate` and `branch-rate` attributes, the `QuickFiler` package `line-rate`, and the `line-rate` of every Cobertura class whose `filename` begins `QuickFiler\Controllers\QfcItemController`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording all four figures as numeric percentages to two decimal places. Acceptance: the artifact exists, the script reported exactly 9 discovered test assemblies, and no coverage field contains the token `UNVERIFIED` or an empty value. +- [x] [P0-T17] Record the Python-toolchain absence finding. Confirm by directory listing that `scripts/dev_tools/` does not exist and that no `pyproject.toml` exists at the worktree root, then write `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/no-python-toolchain.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` stating that any skill step naming a Python dev-tools module is unrunnable by absence and is reported as such rather than fabricated or silently skipped. Acceptance: the artifact exists with all four fields and records both negative existence checks. ### Phase 1 — Empirical Pre-Fix Behaviour The spec requires that the pre-fix failure behaviour be established **by execution**, not by static reading. The first named regression test is authored here rather than in Phase 3 for two reasons that are recorded so a reviewer does not read it as phase drift: the repository Bugfix Workflow requires a failing regression test **before** the fix, and it is the only instrument that reports the harness viewer's `IsHandleCreated` value on a run where the two end-to-end tests happen to pass. Phase 3 authors the second named test and verifies both. -- [ ] [P1-T1] [expect-fail] Author `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` in `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` as a `[TestMethod]` carrying `[Timeout(PumpTimeoutMs)]`, following the Arrange-Act-Assert shape of the existing tests in that file (construct `WinFormsPumpHost`, call `BuildPumpHarnessAsync(host, darkMode: false)`, restore in `finally`, `await host.StopAsync()`). It must assert with FluentAssertions that `harness.Viewer.IsHandleCreated` is `true` and that `await host.InvokeAsync(() => harness.Viewer.InvokeRequired)` is `false`. Append it after the last existing method in the partial class rather than inserting it between existing methods, so the line numbers spec AC 1 and AC 2 cite (`Part3.cs:175` and `Part3.cs:131`) remain accurate. It must contain no sleep, no retry, and no timing tolerance. Acceptance: the method exists in that file with exactly that name, uses `[TestMethod]`, `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` is still declared at line 131 and `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` at line 175, and the file's line count is less than 500. -- [ ] [P1-T2] Rebuild so the new probe is compiled, using `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU"'`. Acceptance: `EXIT_CODE: 0` and `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` has a write time later than the P1-T1 edit time. -- [ ] [P1-T3] [expect-fail] Run the class-filtered scope ten consecutive times with the resolved `vstest.console.exe`, the assembly `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll`, `/InIsolation`, `/Logger:trx`, `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t3`, and `/TestCaseFilter:"FullyQualifiedName~QfcItemController_InitializationTests"`. Record, per run, the pass or fail outcome of `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState`, of `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates`, and of `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`, together with the observed harness viewer `IsHandleCreated` value derived from the probe outcome. Write the ten TRX files and a per-run table to `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-classfiltered.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, `ExpectedExitCode: 1`, and `Output Summary:`. Acceptance: the subdirectory `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t3/` holds exactly ten TRX files and no others, and the table has exactly ten rows with no empty cell. A run in which the probe passes is recorded as `IsHandleCreated: true` for that run and is data about the race window, not evidence the defect is absent. -- [ ] [P1-T4] [expect-fail] Run the full nine-assembly suite ten consecutive times with the resolved `vstest.console.exe`, the nine assembly paths from the canonical assembly list, `/EnableCodeCoverage`, `/InIsolation`, `/Logger:trx`, `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t4`, and `/TestCaseFilter:"TestCategory!=LiveOutlook"`. Record the same three per-test outcomes plus the derived `IsHandleCreated` value per run. Write the ten TRX files and the per-run table to `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-fullsuite.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, `ExpectedExitCode: 1`, and `Output Summary:`. Acceptance: the subdirectory `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t4/` holds exactly ten TRX files and no others, and the table has exactly ten rows with no empty cell. -- [ ] [P1-T5] Consolidate P1-T3 and P1-T4 into the single pre-fix baseline artifact `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-baseline.2026-08-21T18-10.md`, carrying `Timestamp:`, a twenty-row table (ten class-filtered runs and ten full-suite runs) with columns for run index, scope, the two named tests' outcomes, the probe outcome, and the observed `IsHandleCreated` value, plus the observed failure rate stated as a fraction of the runs actually executed. Acceptance: the artifact exists, the table has exactly twenty rows, and the failure rate is stated as a measured fraction rather than as a prediction. No sentence in the artifact may claim a rate that was not observed in these twenty runs. -- [ ] [P1-T6] Record the disposition of the open intermittency question in `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/intermittency-question.2026-08-21T18-10.md`, carrying `Timestamp:` and, in prose, which of the two candidate explanations the measured data supports, which it rules out, and which remains open. If the probe reported `IsHandleCreated: true` on any pre-fix run, name that run and state that some path outside the traced initialization sequence created the handle, with the third-party WebView2 `ISupportInitialize` route named as the unverified prime suspect. Acceptance: the artifact exists and does not close the question by assertion; a sentence claiming a mechanism must cite an observation from P1-T5's table. +- [x] [P1-T1] [expect-fail] Author `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` in `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` as a `[TestMethod]` carrying `[Timeout(PumpTimeoutMs)]`, following the Arrange-Act-Assert shape of the existing tests in that file (construct `WinFormsPumpHost`, call `BuildPumpHarnessAsync(host, darkMode: false)`, restore in `finally`, `await host.StopAsync()`). It must assert with FluentAssertions that `harness.Viewer.IsHandleCreated` is `true` and that `await host.InvokeAsync(() => harness.Viewer.InvokeRequired)` is `false`. Append it after the last existing method in the partial class rather than inserting it between existing methods, so the line numbers spec AC 1 and AC 2 cite (`Part3.cs:175` and `Part3.cs:131`) remain accurate. It must contain no sleep, no retry, and no timing tolerance. Acceptance: the method exists in that file with exactly that name, uses `[TestMethod]`, `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` is still declared at line 131 and `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` at line 175, and the file's line count is less than 500. +- [x] [P1-T2] Rebuild so the new probe is compiled, using `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU"'`. Acceptance: `EXIT_CODE: 0` and `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` has a write time later than the P1-T1 edit time. +- [x] [P1-T3] [expect-fail] Run the class-filtered scope ten consecutive times with the resolved `vstest.console.exe`, the assembly `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll`, `/InIsolation`, `/Logger:trx`, `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t3`, and `/TestCaseFilter:"FullyQualifiedName~QfcItemController_InitializationTests"`. Record, per run, the pass or fail outcome of `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState`, of `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates`, and of `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`, together with the observed harness viewer `IsHandleCreated` value derived from the probe outcome. Write the ten TRX files and a per-run table to `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-classfiltered.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, `ExpectedExitCode: 1`, and `Output Summary:`. Acceptance: the subdirectory `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t3/` holds exactly ten TRX files and no others, and the table has exactly ten rows with no empty cell. A run in which the probe passes is recorded as `IsHandleCreated: true` for that run and is data about the race window, not evidence the defect is absent. +- [x] [P1-T4] [expect-fail] Run the full nine-assembly suite ten consecutive times with the resolved `vstest.console.exe`, the nine assembly paths from the canonical assembly list, `/EnableCodeCoverage`, `/InIsolation`, `/Logger:trx`, `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t4`, and `/TestCaseFilter:"TestCategory!=LiveOutlook"`. Record the same three per-test outcomes plus the derived `IsHandleCreated` value per run. Write the ten TRX files and the per-run table to `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-fullsuite.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, `ExpectedExitCode: 1`, and `Output Summary:`. Acceptance: the subdirectory `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p1-t4/` holds exactly ten TRX files and no others, and the table has exactly ten rows with no empty cell. +- [x] [P1-T5] Consolidate P1-T3 and P1-T4 into the single pre-fix baseline artifact `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/prefix-baseline.2026-08-21T18-10.md`, carrying `Timestamp:`, a twenty-row table (ten class-filtered runs and ten full-suite runs) with columns for run index, scope, the two named tests' outcomes, the probe outcome, and the observed `IsHandleCreated` value, plus the observed failure rate stated as a fraction of the runs actually executed. Acceptance: the artifact exists, the table has exactly twenty rows, and the failure rate is stated as a measured fraction rather than as a prediction. No sentence in the artifact may claim a rate that was not observed in these twenty runs. +- [x] [P1-T6] Record the disposition of the open intermittency question in `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/intermittency-question.2026-08-21T18-10.md`, carrying `Timestamp:` and, in prose, which of the two candidate explanations the measured data supports, which it rules out, and which remains open. If the probe reported `IsHandleCreated: true` on any pre-fix run, name that run and state that some path outside the traced initialization sequence created the handle, with the third-party WebView2 `ISupportInitialize` route named as the unverified prime suspect. Acceptance: the artifact exists and does not close the question by assertion; a sentence claiming a mechanism must cite an observation from P1-T5's table. ### Phase 2 — Handle-Forcing Fixture Change -- [ ] [P2-T1] Edit `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`, inside `BuildPumpHarnessCoreAsync`, inserting the statement `_ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false);` immediately after the viewer is constructed on the pump thread and strictly before the `SwapUiThreadDispatcher(viewer.UiDispatcher)` call. Precede it with a comment recording why: `Control.Invoke` throws on a handle-less control, `Application.Run(new ApplicationContext())` never creates one, reading `.Handle` is non-recursive so the two WebView2 children are not dragged in, and `CreateControl()` would recurse into them. Acceptance: the file contains the exact statement text quoted above exactly once, that statement's line index is greater than the line index of the viewer construction and less than the line index of the `SwapUiThreadDispatcher` call, and no other line of the file is changed. -- [ ] [P2-T2] Verify the `Part2.cs` invariants survived the edit: `UiThreadDispatcherGate` is still declared as a `SemaphoreSlim(1, 1)`, `BuildPumpHarnessAsync` still calls `UiThreadDispatcherGate.WaitAsync` before delegating and still calls `UiThreadDispatcherGate.Release` in its `catch`, `PumpHarness.Restore` still calls `UiThreadDispatcherGate.Release` exactly once behind its `_restored` guard, and the file's line count is less than 500. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-structure-part2.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the four findings and the post-edit line count. Acceptance: all four invariants hold and the recorded line count is less than 500. -- [ ] [P2-T3] Edit `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`, in the standalone arrange block of `ResolveControlGroupsAsync_ThroughThePumpHost_PopulatesTipsAndControlGroups` (near lines 432 through 435, where the viewer is constructed through `host.InvokeAsync`), inserting the same statement `_ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false);` immediately after the viewer construction and before the `HarnessController` is created. Keep the accompanying comment to at most two lines: this file has 33 lines of headroom against the 500-line cap. Acceptance: the file contains the exact statement text exactly once and its line count is less than 500. -- [ ] [P2-T4] Verify the post-edit line count of all three touched files by counting the lines returned by `Get-Content -LiteralPath` for each of `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`, `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`, and `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, and write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-fixture-change.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing each file with its pre-change and post-change count. Acceptance: each of the three recorded post-change counts is less than 500, and `QfcItemController.ViewerSetupTests.cs` is recorded at 475 or fewer lines. -- [ ] [P2-T5] Confirm the production-file scope lock holds after the fixture change: run `git diff --name-only $MergeBase` using the merge-base sha recorded in P0-T6 and confirm the result contains zero paths beginning `QuickFiler/` and zero paths ending `.csproj`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-phase2.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording both counts. Acceptance: both recorded counts are exactly 0. -- [ ] [P2-T6] Rebuild with `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU"'`, then run `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` alone using `/TestCaseFilter:"FullyQualifiedName~BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p2-t6`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-flips-green.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the pre-fix outcome from P1-T5 and the post-fix outcome side by side. Acceptance: the build exits 0, the TRX records `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` as passed with zero failures, and the artifact states the pre-fix outcome for the same test from the P1-T5 table. This is the fail-proof for the fixture change: a probe that was already green on every pre-fix run must be recorded as such and flagged, because it then proves nothing about the fix and P1-T6's disposition governs. +- [x] [P2-T1] Edit `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`, inside `BuildPumpHarnessCoreAsync`, inserting the statement `_ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false);` immediately after the viewer is constructed on the pump thread and strictly before the `SwapUiThreadDispatcher(viewer.UiDispatcher)` call. Precede it with a comment recording why: `Control.Invoke` throws on a handle-less control, `Application.Run(new ApplicationContext())` never creates one, reading `.Handle` is non-recursive so the two WebView2 children are not dragged in, and `CreateControl()` would recurse into them. Acceptance: the file contains the exact statement text quoted above exactly once, that statement's line index is greater than the line index of the viewer construction and less than the line index of the `SwapUiThreadDispatcher` call, and no other line of the file is changed. +- [x] [P2-T2] Verify the `Part2.cs` invariants survived the edit: `UiThreadDispatcherGate` is still declared as a `SemaphoreSlim(1, 1)`, `BuildPumpHarnessAsync` still calls `UiThreadDispatcherGate.WaitAsync` before delegating and still calls `UiThreadDispatcherGate.Release` in its `catch`, `PumpHarness.Restore` still calls `UiThreadDispatcherGate.Release` exactly once behind its `_restored` guard, and the file's line count is less than 500. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-structure-part2.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the four findings and the post-edit line count. Acceptance: all four invariants hold and the recorded line count is less than 500. +- [x] [P2-T3] Edit `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`, in the standalone arrange block of `ResolveControlGroupsAsync_ThroughThePumpHost_PopulatesTipsAndControlGroups` (near lines 432 through 435, where the viewer is constructed through `host.InvokeAsync`), inserting the same statement `_ = await host.InvokeAsync(() => viewer.Handle).ConfigureAwait(false);` immediately after the viewer construction and before the `HarnessController` is created. Keep the accompanying comment to at most two lines: this file has 33 lines of headroom against the 500-line cap. Acceptance: the file contains the exact statement text exactly once and its line count is less than 500. +- [x] [P2-T4] Verify the post-edit line count of all three touched files by counting the lines returned by `Get-Content -LiteralPath` for each of `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`, `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`, and `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, and write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-fixture-change.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing each file with its pre-change and post-change count. Acceptance: each of the three recorded post-change counts is less than 500, and `QfcItemController.ViewerSetupTests.cs` is recorded at 475 or fewer lines. +- [x] [P2-T5] Confirm the production-file scope lock holds after the fixture change: run `git diff --name-only $MergeBase` using the merge-base sha recorded in P0-T6 and confirm the result contains zero paths beginning `QuickFiler/` and zero paths ending `.csproj`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-phase2.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording both counts. Acceptance: both recorded counts are exactly 0. +- [x] [P2-T6] Rebuild with `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU"'`, then run `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` alone using `/TestCaseFilter:"FullyQualifiedName~BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p2-t6`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/probe-flips-green.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the pre-fix outcome from P1-T5 and the post-fix outcome side by side. Acceptance: the build exits 0, the TRX records `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` as passed with zero failures, and the artifact states the pre-fix outcome for the same test from the P1-T5 table. This is the fail-proof for the fixture change: a probe that was already green on every pre-fix run must be recorded as such and flagged, because it then proves nothing about the fix and P1-T6's disposition governs. ### Phase 3 — Regression Tests -- [ ] [P3-T1] Author `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` in `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` as a `[TestMethod]` carrying `[Timeout(PumpTimeoutMs)]`, following the same Arrange-Act-Assert shape. It must assert with FluentAssertions, reading both values on the pump thread through `host.InvokeAsync`, that `harness.Viewer.L0v2h2_WebView2.IsHandleCreated` is `false` and that `harness.Viewer.L0vhBreadcrumb_WebView2.IsHandleCreated` is `false`, each with a `because` clause recording that this pins the minimality of `.Handle` over `CreateControl()`. Append it after the method added by P1-T1 rather than inserting it between existing methods, so the line numbers spec AC 1 and AC 2 cite remain accurate. It must contain no sleep, no retry, and no timing tolerance. Acceptance: the method exists in that file with exactly that name, asserts on both named WebView2 properties, and `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` is still declared at line 131 with `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` at line 175. -- [ ] [P3-T2] Verify `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` line count after both new tests. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-part3.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the pre-change count of 290 and the post-change count. Acceptance: the recorded post-change count is less than 500. -- [ ] [P3-T3] Rebuild with `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU"'`. Acceptance: `EXIT_CODE: 0` with zero compile errors. -- [ ] [P3-T4] Run both named regression tests using `/TestCaseFilter:"FullyQualifiedName~BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread|FullyQualifiedName~BuildPumpHarness_DoesNotCreateTheWebViewChildHandles"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t4`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-regression-tests.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording each test's outcome. Acceptance: the TRX records exactly 2 executed tests, 2 passed, 0 failed, and 0 skipped. A skipped or not-run test is a failure of this task, not a pass. -- [ ] [P3-T5] Run the eight pump-hosted consumer tests using `/TestCaseFilter:"FullyQualifiedName~ThroughThePumpHost|FullyQualifiedName~WithFaultingWebViewSeam|FullyQualifiedName~WithInjectedSeams"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t5`. This is where the known side effect surfaces: forcing the handle flips `Theme.cs:433` `_lblItemNumber.InvokeRequired` and `ViewerSetup.cs:361` `_itemViewer.InvokeRequired` from `false` to `true` on off-pump evaluation, so those paths now marshal instead of running inline. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/consumer-tests.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing each test name and outcome. Acceptance: the recorded failed count is 0 and the recorded executed count is at least 8. -- [ ] [P3-T6] Run the thirteen `WinFormsPumpHostTests` self-tests using `/TestCaseFilter:"FullyQualifiedName~WinFormsPumpHostTests"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t6`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/pumphost-selftests.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing each test name and outcome. Acceptance: the TRX records exactly 13 executed tests, 13 passed, 0 failed, and 0 skipped. -- [ ] [P3-T7] Run `QfcItemController_SeamFactoryTests` and `QfcItemController_InitializationTests` in the **same** invocation using `/TestCaseFilter:"FullyQualifiedName~QfcItemController_SeamFactoryTests|FullyQualifiedName~QfcItemController_InitializationTests"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t7`, so class-level parallelization exercises the shared `UiThreadDispatcherGate`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-serialization.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the per-class pass counts and total wall-clock duration. Acceptance: the recorded failed count is 0, both class names appear in the TRX with at least one passed test each, and no test is recorded as failing on its `[Timeout]`. A `[Timeout]`-attributed failure here indicates the unmitigated gate cascade rather than the handle race and must be recorded as such before any retry. -- [ ] [P3-T8] Assert the diff of the three touched files introduces no prohibited timing construct. Run `git diff --unified=0 $MergeBase -- QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` and search the added lines only for each of the four literals `Thread.Sleep`, `Task.Delay`, `SpinWait`, and `PumpTimeoutMs =`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/no-timing-hacks.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording one count per literal. Acceptance: the counts for `Thread.Sleep`, `Task.Delay`, and `SpinWait` in added lines are each exactly 0; the count for `PumpTimeoutMs =` in added lines is exactly 0; and file inspection confirms `PumpTimeoutMs = 60000` in `QfcItemController.InitializationTests.cs`, `QfcItemController.ViewerSetupTests.cs`, and `QfcItemController.SeamFactoryTests.cs`, and `TimeoutMs = 30000` in `WinFormsPumpHostTests.cs`, each retaining its current value. The four literals are quoted verbatim here so the search is over text this plan states rather than over paraphrase. +- [x] [P3-T1] Author `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` in `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` as a `[TestMethod]` carrying `[Timeout(PumpTimeoutMs)]`, following the same Arrange-Act-Assert shape. It must assert with FluentAssertions, reading both values on the pump thread through `host.InvokeAsync`, that `harness.Viewer.L0v2h2_WebView2.IsHandleCreated` is `false` and that `harness.Viewer.L0vhBreadcrumb_WebView2.IsHandleCreated` is `false`, each with a `because` clause recording that this pins the minimality of `.Handle` over `CreateControl()`. Append it after the method added by P1-T1 rather than inserting it between existing methods, so the line numbers spec AC 1 and AC 2 cite remain accurate. It must contain no sleep, no retry, and no timing tolerance. Acceptance: the method exists in that file with exactly that name, asserts on both named WebView2 properties, and `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` is still declared at line 131 with `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` at line 175. +- [x] [P3-T2] Verify `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` line count after both new tests. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-part3.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the pre-change count of 290 and the post-change count. Acceptance: the recorded post-change count is less than 500. +- [x] [P3-T3] Rebuild with `pwsh -NoProfile -Command 'msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU"'`. Acceptance: `EXIT_CODE: 0` with zero compile errors. +- [x] [P3-T4] Run both named regression tests using `/TestCaseFilter:"FullyQualifiedName~BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread|FullyQualifiedName~BuildPumpHarness_DoesNotCreateTheWebViewChildHandles"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t4`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-regression-tests.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording each test's outcome. Acceptance: the TRX records exactly 2 executed tests, 2 passed, 0 failed, and 0 skipped. A skipped or not-run test is a failure of this task, not a pass. +- [x] [P3-T5] Run the eight pump-hosted consumer tests using `/TestCaseFilter:"FullyQualifiedName~ThroughThePumpHost|FullyQualifiedName~WithFaultingWebViewSeam|FullyQualifiedName~WithInjectedSeams"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t5`. This is where the known side effect surfaces: forcing the handle flips `Theme.cs:433` `_lblItemNumber.InvokeRequired` and `ViewerSetup.cs:361` `_itemViewer.InvokeRequired` from `false` to `true` on off-pump evaluation, so those paths now marshal instead of running inline. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/consumer-tests.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing each test name and outcome. Acceptance: the recorded failed count is 0 and the recorded executed count is at least 8. +- [x] [P3-T6] Run the thirteen `WinFormsPumpHostTests` self-tests using `/TestCaseFilter:"FullyQualifiedName~WinFormsPumpHostTests"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t6`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/pumphost-selftests.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing each test name and outcome. Acceptance: the TRX records exactly 13 executed tests, 13 passed, 0 failed, and 0 skipped. +- [x] [P3-T7] Run `QfcItemController_SeamFactoryTests` and `QfcItemController_InitializationTests` in the **same** invocation using `/TestCaseFilter:"FullyQualifiedName~QfcItemController_SeamFactoryTests|FullyQualifiedName~QfcItemController_InitializationTests"` against `QuickFiler.Test\bin\Debug\QuickFiler.Test.dll` with `/InIsolation`, `/Logger:trx`, and `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p3-t7`, so class-level parallelization exercises the shared `UiThreadDispatcherGate`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/gate-serialization.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the per-class pass counts and total wall-clock duration. Acceptance: the recorded failed count is 0, both class names appear in the TRX with at least one passed test each, and no test is recorded as failing on its `[Timeout]`. A `[Timeout]`-attributed failure here indicates the unmitigated gate cascade rather than the handle race and must be recorded as such before any retry. +- [x] [P3-T8] Assert the diff of the three touched files introduces no prohibited timing construct. Run `git diff --unified=0 $MergeBase -- QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` and search the added lines only for each of the four literals `Thread.Sleep`, `Task.Delay`, `SpinWait`, and `PumpTimeoutMs =`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/no-timing-hacks.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording one count per literal. Acceptance: the counts for `Thread.Sleep`, `Task.Delay`, and `SpinWait` in added lines are each exactly 0; the count for `PumpTimeoutMs =` in added lines is exactly 0; and file inspection confirms `PumpTimeoutMs = 60000` in `QfcItemController.InitializationTests.cs`, `QfcItemController.ViewerSetupTests.cs`, and `QfcItemController.SeamFactoryTests.cs`, and `TimeoutMs = 30000` in `WinFormsPumpHostTests.cs`, each retaining its current value. The four literals are quoted verbatim here so the search is over text this plan states rather than over paraphrase. ### Phase 4 — Determinism Verification -- [ ] [P4-T1] Start a CPU load generator so the ten-run determinism record is captured under contention, matching the #511 observation conditions. Start `[Environment]::ProcessorCount - 1` background PowerShell jobs, each running a pure busy loop with no sleep and no file I/O, then sample utilization with `Get-Counter '\Processor(_Total)\% Processor Time' -SampleInterval 1 -MaxSamples 5`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-start.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the job count and the five sampled utilization values. Acceptance: the recorded job count equals `[Environment]::ProcessorCount - 1` and the mean of the five sampled utilization values is at least 80. The load generator is test-harness scaffolding, not test code; it introduces no sleep, retry, or timing tolerance into any test and creates no temporary file. -- [ ] [P4-T2] Under that load, run the full nine-assembly suite ten consecutive times with the resolved `vstest.console.exe`, the nine assembly paths from the canonical assembly list, `/EnableCodeCoverage`, `/InIsolation`, `/Logger:trx`, `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2`, and `/TestCaseFilter:"TestCategory!=LiveOutlook"`, writing each run's TRX under `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`. That subdirectory is private to this task, so it is unambiguous which ten files the acceptance condition refers to; the `[expect-fail]` Phase 1 TRX files sit in their own `p1-t3` and `p1-t4` subdirectories and are never counted here. Acceptance: the subdirectory `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/` holds exactly ten TRX files and no others, and each of those ten records a failed count of exactly 0. A single failing run fails this task; do not re-run to obtain a tenth green result without recording every attempt. -- [ ] [P4-T3] Stop the load generator: sample `Get-Counter '\Processor(_Total)\% Processor Time' -SampleInterval 1 -MaxSamples 5` once more before stopping, then `Stop-Job` and `Remove-Job` every job started in P4-T1. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-stop.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the pre-stop utilization samples and the post-stop job count. Acceptance: the recorded mean pre-stop utilization is at least 80, sampled immediately before the load generator is stopped, and the recorded post-stop job count is exactly 0. The P4-T1 and P4-T3 samples bracket the ten-run window rather than covering it continuously, so they are evidence that the generator was still loading the machine at both ends, not a continuous measurement across the window. -- [ ] [P4-T4] Assert `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` and `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` are recorded as passed in each of the ten TRX files in `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` carrying a ten-row table with one column per named test. Acceptance: the table has exactly ten rows and every cell reads passed. -- [ ] [P4-T5] Assert `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` and `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` are recorded as passed in each of the same ten TRX files in `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` carrying a ten-row table with one column per test. Acceptance: the table has exactly ten rows and every cell reads passed. -- [ ] [P4-T6] Consolidate the determinism record into `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md`, carrying `Timestamp:`, the ten TRX paths under `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`, per-run total and failed counts, per-run wall-clock duration, the sustained CPU-utilization figures from P4-T1 and P4-T3, and a direct comparison against the P1-T5 pre-fix table. Acceptance: the artifact exists, names all ten TRX paths, and states the pre-fix and post-fix outcomes for both named tests side by side using measured values only. +- [x] [P4-T1] Start a CPU load generator so the ten-run determinism record is captured under contention, matching the #511 observation conditions. Start `[Environment]::ProcessorCount - 1` background PowerShell jobs, each running a pure busy loop with no sleep and no file I/O, then sample utilization with `Get-Counter '\Processor(_Total)\% Processor Time' -SampleInterval 1 -MaxSamples 5`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-start.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the job count and the five sampled utilization values. Acceptance: the recorded job count equals `[Environment]::ProcessorCount - 1` and the mean of the five sampled utilization values is at least 80. The load generator is test-harness scaffolding, not test code; it introduces no sleep, retry, or timing tolerance into any test and creates no temporary file. +- [x] [P4-T2] Under that load, run the full nine-assembly suite ten consecutive times with the resolved `vstest.console.exe`, the nine assembly paths from the canonical assembly list, `/EnableCodeCoverage`, `/InIsolation`, `/Logger:trx`, `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2`, and `/TestCaseFilter:"TestCategory!=LiveOutlook"`, writing each run's TRX under `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`. That subdirectory is private to this task, so it is unambiguous which ten files the acceptance condition refers to; the `[expect-fail]` Phase 1 TRX files sit in their own `p1-t3` and `p1-t4` subdirectories and are never counted here. Acceptance: the subdirectory `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/` holds exactly ten TRX files and no others, and each of those ten records zero failed tests within the `QuickFiler.Test` assembly, with both named end-to-end tests (`InitializeBool_ThroughThePumpHost_CompletesAndInitializesState`, `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates`) and both named regression tests (`BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`, `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles`) recorded as passed in every TRX, and any failure in a sibling assembly recorded by fully qualified name and attributed to issue #594 rather than failing the task (narrowed 2026-08-23 per remediation Finding F). A single failing run fails this task; do not re-run to obtain a tenth green result without recording every attempt. +- [x] [P4-T3] Stop the load generator: sample `Get-Counter '\Processor(_Total)\% Processor Time' -SampleInterval 1 -MaxSamples 5` once more before stopping, then `Stop-Job` and `Remove-Job` every job started in P4-T1. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/load-generator-stop.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the pre-stop utilization samples and the post-stop job count. Acceptance: the recorded mean pre-stop utilization is at least 80, sampled immediately before the load generator is stopped, and the recorded post-stop job count is exactly 0. The P4-T1 and P4-T3 samples bracket the ten-run window rather than covering it continuously, so they are evidence that the generator was still loading the machine at both ends, not a continuous measurement across the window. +- [x] [P4-T4] Assert `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` and `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` are recorded as passed in each of the ten TRX files in `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` carrying a ten-row table with one column per named test. Acceptance: the table has exactly ten rows and every cell reads passed. +- [x] [P4-T5] Assert `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` and `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` are recorded as passed in each of the same ten TRX files in `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` carrying a ten-row table with one column per test. Acceptance: the table has exactly ten rows and every cell reads passed. +- [x] [P4-T6] Consolidate the determinism record into `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md`, carrying `Timestamp:`, the ten TRX paths under `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/`, per-run total and failed counts, per-run wall-clock duration, the sustained CPU-utilization figures from P4-T1 and P4-T3, and a direct comparison against the P1-T5 pre-fix table. Acceptance: the artifact exists, names all ten TRX paths, and states the pre-fix and post-fix outcomes for both named tests side by side using measured values only. ### Phase 5 — Final QC Loop +Note (2026-08-23): the remaining unchecked tasks of this phase are executed under `remediation-plan.2026-08-23T20-57.md` per `remediation-inputs.2026-08-23T20-57.md`. + This loop is unconditional. Every command-bearing task below must execute its stated command and record the result; `SKIPPED` is not a valid completion state for any of them. If any step fails or changes files, restart from P5-T1. - [ ] [P5-T1] Run `dotnet tool restore` from the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/final-tool-restore.2026-08-21T18-10.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:`. Acceptance: `EXIT_CODE: 0`. @@ -196,7 +198,9 @@ This loop is unconditional. Every command-bearing task below must execute its st ### Phase 6 — Acceptance Criteria and Audit Handoff -- [ ] [P6-T1] File the follow-up GitHub issue for #511's visible-window half with `gh issue create`, titled for the re-attribution to `UtilitiesCS.Test/Threading/ProgressViewer_Tests.cs`, whose body records that the only enabled call showing a real top-level `Form` in the nine-assembly corpus is `viewer.Show()` at `ProgressViewer_Tests.cs:73` on a `ProgressViewer : Form`, that a headless helper `CreateHeadlessViewer` already exists at `ProgressViewer_Tests.cs:33-34`, that the re-attribution is a code reading rather than a reproduced observation, and that `epic.md` forbids any child of this epic from writing under `docs/features/potential/`. Mirror the posted text to `docs/features/active/winformspumphost-suite-determinism-511/evidence/issue-updates/followup-progressviewer.2026-08-21T18-10.md` with `Timestamp:`, the exact posted text, `PostedAs: body`, and the issue URL. Acceptance: the mirror artifact exists and records a concrete issue number and URL; if `gh` is unavailable, the artifact carries a `POSTING BLOCKED` header with the reason and this task is not checked off. +Note (2026-08-23): the remaining unchecked tasks of this phase are executed under `remediation-plan.2026-08-23T20-57.md` per `remediation-inputs.2026-08-23T20-57.md`. + +- [x] [P6-T1] Discharged 2026-08-23: issue #592 already exists and carries this follow-up; no new issue is created. File the follow-up GitHub issue for #511's visible-window half with `gh issue create`, titled for the re-attribution to `UtilitiesCS.Test/Threading/ProgressViewer_Tests.cs`, whose body records that the only enabled call showing a real top-level `Form` in the nine-assembly corpus is `viewer.Show()` at `ProgressViewer_Tests.cs:73` on a `ProgressViewer : Form`, that a headless helper `CreateHeadlessViewer` already exists at `ProgressViewer_Tests.cs:33-34`, that the re-attribution is a code reading rather than a reproduced observation, and that `epic.md` forbids any child of this epic from writing under `docs/features/potential/`. Mirror the posted text to `docs/features/active/winformspumphost-suite-determinism-511/evidence/issue-updates/followup-progressviewer.2026-08-21T18-10.md` with `Timestamp:`, the exact posted text, `PostedAs: body`, and the issue URL. Acceptance: the mirror artifact exists and records a concrete issue number and URL; if `gh` is unavailable, the artifact carries a `POSTING BLOCKED` header with the reason and this task is not checked off. - [ ] [P6-T2] Update `docs/features/active/winformspumphost-suite-determinism-511/spec.md`, section `## Rollout & Follow-up`, required follow-up item 1, replacing the instruction to record the number with the concrete issue number filed in P6-T1. Acceptance: the spec's item 1 names a concrete issue number and no longer contains an unfilled instruction to record one. - [ ] [P6-T3] Check off spec AC 1 (`InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` passes in every one of ten consecutive full nine-assembly runs, with the ten TRX results stored under `evidence/regression-testing/`) in `spec.md`, citing the P4-T4 artifact and the ten TRX paths. Acceptance: exactly one AC checkbox changes state and the evidence pointer resolves to an existing file. - [ ] [P6-T4] Check off spec AC 2 (`InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` passes in every one of those same ten runs), citing the P4-T4 artifact. Acceptance: exactly one AC checkbox changes state and the evidence pointer resolves to an existing file. @@ -215,7 +219,7 @@ This loop is unconditional. Every command-bearing task below must execute its st - [ ] [P6-T17] Write the acceptance-criteria status summary to `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/ac-status-summary.2026-08-21T18-10.md` with `Timestamp:` and one row per criterion carrying the criterion number, its verbatim first line, its state, and its evidence artifact path. Acceptance: the summary has exactly 14 rows, every row names an artifact path that resolves to an existing file, and the row states agree with the checkbox states in `spec.md`. - [ ] [P6-T18] Commit every source and evidence change on `bug/winformspumphost-suite-determinism-511` with a message naming issues #511 and #571, then confirm the tree is clean. Acceptance: `git status --porcelain` produces zero output lines, and `git diff --name-only $MergeBase` still satisfies the P6-T11 scope-lock conditions after the commit. - [ ] [P6-T19] Hand off to feature review with an evidence index listing every artifact path produced by Phases 0 through 6, the branch name, the merge-base sha from P0-T6, the head sha after P6-T18, and the four residual conditions the spec records as stated rather than fixed: the unmitigated MSTest `[Timeout]` and `UiThreadDispatcherGate` cascade, residual CPU-contention sensitivity, #511's re-attributed visible-window half, and the `InvokeBeginInvoke` production asymmetry. Write the index to `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/review-handoff.2026-08-21T18-10.md` with `Timestamp:`. Acceptance: the index exists, every listed artifact path resolves to an existing file, and all four residual conditions are named. No pull-request creation and no CI monitoring is performed by this plan; both are handled outside it. -- [ ] [P6-T20] File the follow-up GitHub issue for the repository-wide analyzer version skew with `gh issue create`, discharging the obligation recorded in item 6 of the Binding Constraints analyzer note. The posted body must record all four findings: that all 16 first-party project files carry unconditional `Analyzer` items naming `Meziantou.Analyzer.3.0.156` and `Roslynator.Analyzers.4.16.0` while all 16 `packages.config` files pin `Meziantou.Analyzer 3.0.174` and `Roslynator.Analyzers 4.16.1`; that csc reports `error CS0006` for a missing `Analyzer` path rather than degrading to a warning, so a clean checkout cannot build; that Dependabot commit `f8e22af7` is the origin, having updated the `Condition`-guarded `Import` and `Error` lines and the `packages.config` entries but not the hand-authored Issue-#181 `Analyzer` items; and that the green CI signal is explained by the prefix `restore-keys` fallback at `.github/workflows/_build-analyzers.yml:40-41` restoring a pre-bump packages tree rather than by compiler tolerance. `epic.md` forbids any child of this epic from writing under `docs/features/potential/`, so `gh issue create` is the instrument and no potential-folder entry is created. Write the mirror first to `docs/features/active/winformspumphost-suite-determinism-511/evidence/issue-updates/followup-analyzer-version-skew.2026-08-21T18-10.md` with `Timestamp:`, the exact posted text, `PostedAs: body`, and the issue URL; then append that mirror path to the evidence index at `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/review-handoff.2026-08-21T18-10.md` written by P6-T19, which leaves that index's every-path-resolves condition satisfied because the mirror already exists when the line is appended. Acceptance: the mirror artifact exists and records a concrete issue number and URL, and the review-handoff index contains the mirror path; if `gh` is unavailable, the mirror artifact instead carries a `POSTING BLOCKED` header with the reason and this task is not checked off. This task files an issue and writes one Markdown mirror plus one appended index line; it edits no `.csproj` and does not relax Binding Constraint 1 or the P6-T11 scope lock. +- [x] [P6-T20] Discharged 2026-08-23: issue #597 already exists and carries this follow-up; no new issue is created. File the follow-up GitHub issue for the repository-wide analyzer version skew with `gh issue create`, discharging the obligation recorded in item 6 of the Binding Constraints analyzer note. The posted body must record all four findings: that all 16 first-party project files carry unconditional `Analyzer` items naming `Meziantou.Analyzer.3.0.156` and `Roslynator.Analyzers.4.16.0` while all 16 `packages.config` files pin `Meziantou.Analyzer 3.0.174` and `Roslynator.Analyzers 4.16.1`; that csc reports `error CS0006` for a missing `Analyzer` path rather than degrading to a warning, so a clean checkout cannot build; that Dependabot commit `f8e22af7` is the origin, having updated the `Condition`-guarded `Import` and `Error` lines and the `packages.config` entries but not the hand-authored Issue-#181 `Analyzer` items; and that the green CI signal is explained by the prefix `restore-keys` fallback at `.github/workflows/_build-analyzers.yml:40-41` restoring a pre-bump packages tree rather than by compiler tolerance. `epic.md` forbids any child of this epic from writing under `docs/features/potential/`, so `gh issue create` is the instrument and no potential-folder entry is created. Write the mirror first to `docs/features/active/winformspumphost-suite-determinism-511/evidence/issue-updates/followup-analyzer-version-skew.2026-08-21T18-10.md` with `Timestamp:`, the exact posted text, `PostedAs: body`, and the issue URL; then append that mirror path to the evidence index at `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/review-handoff.2026-08-21T18-10.md` written by P6-T19, which leaves that index's every-path-resolves condition satisfied because the mirror already exists when the line is appended. Acceptance: the mirror artifact exists and records a concrete issue number and URL, and the review-handoff index contains the mirror path; if `gh` is unavailable, the mirror artifact instead carries a `POSTING BLOCKED` header with the reason and this task is not checked off. This task files an issue and writes one Markdown mirror plus one appended index line; it edits no `.csproj` and does not relax Binding Constraint 1 or the P6-T11 scope lock. - [ ] [P6-T21] Commit the artifacts produced after P6-T18 on `bug/winformspumphost-suite-determinism-511` using explicit pathspecs, with a message naming issues #511 and #571. The set is at minimum `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/review-handoff.2026-08-21T18-10.md` from P6-T19 and `docs/features/active/winformspumphost-suite-determinism-511/evidence/issue-updates/followup-analyzer-version-skew.2026-08-21T18-10.md` from P6-T20; include any other artifact written after the P6-T18 commit. Both paths are Markdown under the feature folder, so neither enters the P6-T11 filtered set and neither disturbs the three prohibited counts. This task exists because P6-T18's clean-tree acceptance is measured before P6-T19 and P6-T20 write, and P6-T19 cannot move ahead of P6-T18 because its index records the head sha produced by that commit. Acceptance: `git status --porcelain` produces zero output lines, and `git diff --name-only $MergeBase` still satisfies the P6-T11 scope-lock conditions after the commit. --- diff --git a/docs/features/active/winformspumphost-suite-determinism-511/policy-audit.2026-08-24T00-01.md b/docs/features/active/winformspumphost-suite-determinism-511/policy-audit.2026-08-24T00-01.md new file mode 100644 index 000000000..f15ce4e94 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/policy-audit.2026-08-24T00-01.md @@ -0,0 +1,219 @@ +# Policy Audit — winformspumphost-suite-determinism-511 + +- Timestamp: 2026-08-24T00-01 (UTC) +- Feature folder: `docs/features/active/winformspumphost-suite-determinism-511` +- Branch: `bug/winformspumphost-suite-determinism-511-exec` +- Base branch (resolved): `main` +- Merge base: `f85a36faebaaec29fe5233c9d9f69d223d80e4c5` +- Head: `b4d47adc369d021f6fb4eff092f419dc49e9a5e5` (verified against `git rev-parse HEAD`; tree clean) +- Work mode: `full-bug` (persisted marker in `issue.md`; AC source is `spec.md` only) +- Review cycle: re-audit after remediation cycle 1 (inputs: `remediation-inputs.2026-08-23T20-57.md`) + +> Template provenance. The MCP tool `resolve_policy_audit_template_asset` is not reachable from +> this review subagent's environment; the artifact was authored directly against the canonical +> heading set required by `.claude/skills/policy-audit-template-usage/SKILL.md`, with the template +> instruction block omitted. All 13 canonical major headings are present. + +## Executive Summary + +The branch diff against `main` at merge base `f85a36fa` contains 3 C# test files (+124 lines, all +in `QuickFiler.Test/`), 68 documentation/evidence files under the feature folder, and 26 +agent-memory bookkeeping files under `.claude/agent-memory/`. No production code, project file, +workflow, or script file changed. The change corrects two falsified comment blocks, adds two +regression tests pinning the measured WebView2 handle-inheritance state, and re-scopes the +feature's claims per the maintainer decision recorded in `decision-record.2026-08-23T20-40.md`. + +All policy sections below are PASS. The remediation cycle 1 exit criteria (remediation-inputs +Part 5, criteria 1-7) were each independently re-verified against the working tree and are +satisfied. **Blocking findings in this audit: 0.** + +## Rejected Scope Narrowing + +None detected. The caller prompt supplied repository facts and explicitly declined to assert +scope. The audit scope is the full branch diff `f85a36fa..b4d47adc` against `main`. One +generator defect was found and corrected rather than accepted: `artifacts/pr_context.summary.txt` +classified the branch as "Core logic changes: 0 files" and omitted the three changed `.cs` files +from its changed-files bullets. The summary was corrected in place (reviewer correction block, +dated 2026-08-24 UTC) and the C# language gates below were applied in full. + +## 1. General Unit Test Policy Compliance + +| Check | Verdict | Evidence | +| --- | --- | --- | +| Independence / isolation | PASS | Both new tests build a private `WinFormsPumpHost` + `PumpHarness`, restore state in `finally` (`harness.Restore()`, `host.StopAsync()`); the process-wide `UiThreadDispatcherGate` serialization is preserved (`Part2.cs:51`, `SwapUiThreadDispatcher` now at `:148`). | +| Determinism | PASS | Both new tests recorded `Passed` in 10/10 full nine-assembly runs under induced CPU load (`evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md`) and in the final 6,459/6,459 suite run (`evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md`). | +| Banned timing APIs | PASS | Added-line scan of the branch diff: zero `Thread.Sleep`, `Task.Delay`, `SpinWait`, retry loops, or raised timeout constants. Only `[Timeout(PumpTimeoutMs)]` attributes referencing the existing 60,000 ms constant, unchanged (`ViewerSetupTests.cs:34` et al.). | +| No temporary files in tests | PASS | Diff adds no filesystem access. | +| No external dependencies | PASS | New tests exercise in-process WinForms fixtures only; WebView2 core initialization remains behind the sentinel mock. | +| AAA structure and documented intent | PASS | Both new tests carry Arrange/Act/Assert comments, XML doc summaries, and FluentAssertions `because:` messages. | +| Test files excluded from coverage denominator | PASS | Cobertura packages enumerate production assemblies only; `QuickFiler.Test` is not a package in `artifacts/csharp/coverage.xml`. | + +## 2. General Code Change Policy Compliance + +| Check | Verdict | Evidence | +| --- | --- | --- | +| 500-line file cap | PASS | Independently re-measured (`awk`, full line count): `Part2.cs` 418, `ViewerSetupTests.cs` 474, `Part3.cs` 398 — all under 500. Matches `evidence/qa-gates/remediation-file-size-audit.2026-08-23T20-57.md`. | +| Toolchain loop, full pass | PASS | `evidence/qa-gates/remediation-clean-pass.2026-08-23T20-57.md`: P3-T1..P3-T10 green in a single consecutive pass, 0 loop restarts, `SKIPPED` unused. | +| Comments state the truth (why, synchronized) | PASS | Both formerly-false comment blocks (`Part2.cs:87-93`, `ViewerSetupTests.cs:436-442`) now state the measured inherited-handle truth and the deliberate redundancy of the retained read, discharging remediation Finding D verbatim, including the required redundancy statement. | +| Simplicity / minimal diff | PASS | Code diff is +124 lines across 3 test files; no production edits (`git diff -- QuickFiler/` is empty). | +| No policy-document edits | PASS | Diff touches no `.claude/rules/**` and no `.github/instructions/**`. `.claude/` paths in the diff are exclusively `.claude/agent-memory/**`, the subtree spec AC 9 and epic hard constraint 1 explicitly permit. | +| Fail fast / logging / contracts | PASS | Not exercised: no production logic changed. | + +## 3. Language-Specific Code Change Policy Compliance + +C# is the only code language with changed files on the branch. + +| Check | Verdict | Evidence | +| --- | --- | --- | +| CSharpier formatting | PASS | `remediation-csharpier-format` (hash-derived rewritten count 0) and `remediation-csharpier-check` (0 unformatted of 1,519 files), both exit 0, pinned tool via `dotnet tool run`. | +| .NET analyzers (`/t:Rebuild`, `EnableNETAnalyzers`, `EnforceCodeStyleInBuild`) | PASS | `remediation-analyzer-gate.2026-08-23T20-57.md`: exit 0, error count 0, `Skipping target "CoreCompile"` count 0 (cold rebuild proven). | +| Nullable / type gate (`/t:Rebuild`, `TreatWarningsAsErrors`, no `/p:Nullable=enable`) | PASS | `remediation-nullable-gate.2026-08-23T20-57.md`: exit 0, error count 0, `CoreCompile` skip count 0, command carried no `/p:Nullable=enable`. | +| No `dotnet format` use | PASS | All evidence records CSharpier via `dotnet tool run`. | +| Legacy project-file protection | PASS | Zero `*.csproj` / `*.props` / `*.targets` files in the diff. | + +## 4. Language-Specific Unit Test Policy Compliance + +| Check | Verdict | Evidence | +| --- | --- | --- | +| MSTest framework | PASS | New tests use `[TestMethod]`, `[Timeout]` (`Part3.cs:299-300, 354-355`). | +| Moq for mocks | PASS | Harness continues to inject `Mock`, `Mock`, sentinel `Mock`; no new mocking library. | +| FluentAssertions | PASS | All new assertions use `.Should().BeTrue()/.BeFalse()` with `because:` messages. | +| No xUnit/NUnit introduction | PASS | Diff adds no new test-framework references. | + +## 5. Test Coverage Detail + +Changed-language enumeration from `git diff --name-only f85a36fa..b4d47adc`: C# only (3 `.cs` +files, all pre-existing test files; 0 new files, 0 production files). TypeScript, Python, and +PowerShell each have zero changed files on this branch, so no per-language verdict attaches to +them and no artifact is required for them. + +| Language | Artifact | Repo-wide line | Repo-wide branch | Verdict | +| --- | --- | --- | --- | --- | +| C# | `artifacts/csharp/coverage.xml` (Cobertura, produced 2026-08-23 19:24, root `line-rate=0.855916`, `branch-rate=0.790598`) | 85.59% (>= 85%) | 79.06% (>= 75%) | C# repo-wide coverage PASS | + +- C# new-code coverage: PASS — the diff adds no new production files or production lines; the two + added tests raise executed-line counts (`QuickFiler` package +0.15 pp) and add nothing to the + denominator. +- C# modified-file / changed-line coverage: PASS — zero production lines changed + (`git diff -- QuickFiler/` empty); no changed-line regression is possible, and the measured + per-class deltas for all 10 `QfcItemController*` classes are exactly +0.00 pp with package and + repo-wide deltas positive (`evidence/qa-gates/remediation-coverage-delta.2026-08-23T20-57.md`, + baseline `evidence/baseline/coverage.2026-08-21T18-10.md`, same-session methodology, identical + deduplicated counting method, matched class count 10 = 10). +- Artifact-vs-record integrity: PASS — the on-disk `artifacts/csharp/coverage.xml` root attributes + were read directly by this review and match the committed evidence figures byte-for-byte. +- TypeScript: zero changed files on the branch; no verdict attaches. +- Python: zero changed files on the branch; no verdict attaches (constraint 7 of `issue.md`: no + Python toolchain exists in this repository). +- PowerShell: zero changed files on the branch; no verdict attaches. + +## 6. Test Execution Metrics + +| Run | Result | +| --- | --- | +| Final nine-assembly suite (P3-T6, `/InIsolation`, `TestCategory!=LiveOutlook`) | 6,459 total / 6,459 passed / 0 failed, exit 0 (`remediation-suite-run.2026-08-23T20-57.md`) | +| Coverage run (P3-T7, `Invoke-MSTestWithCoverage.ps1`) | 6,459/6,459, 0 failed, exit 0, single attempt | +| Ten-run determinism record under induced load (pre-remediation source; comment-only delta since, proven) | `QuickFiler.Test` failed count 0 in 10/10; suite-wide 9/10 green; run 5: one sibling `UtilitiesCS.Test` failure attributed to issue #594 (`determinism-ten-runs.2026-08-21T18-10.md`; comment-only-delta proof in `p4-t2-narrowing-rationale.2026-08-23T20-57.md`) | +| Both new regression tests + both named end-to-end tests | `Passed` in 10/10 runs (`regression-tests-ten-runs`, `named-tests-ten-runs`) | + +## 7. Code Quality Checks + +| Gate | Verdict | Detail | +| --- | --- | --- | +| Formatting | PASS | 0 unformatted files repo-wide (CSharpier 1.2.6 pinned) | +| Linting / analyzers | PASS | 0 errors; 5 pre-existing warnings, not gated | +| Type checking | PASS | 0 errors under `TreatWarningsAsErrors` | +| Tests | PASS | 0 failures, final run | +| C# coverage gates | PASS | 85.59% line / 79.06% branch repo-wide; no regression | +| File-size budget | PASS | 418 / 474 / 398 lines | +| Host-identifier hygiene | PASS | Added-line scan of the full branch diff for real `C:\Users\...` paths, the account name, and the machine name: zero real identifiers added (the only matches are the placeholder examples inside the sanitization rule document itself). | +| Closing-keyword scan | PASS | `git log --format=%B f85a36fa..HEAD`: zero matches of the case-insensitive regex for closing keywords before `#511` or `#571`. File-content matches exist only in `remediation-inputs.2026-08-23T20-57.md` (three negations, exempt by the recorded carve-out) and `plan.2026-08-21T18-10.md:26` (pre-existing; file content cannot auto-close an issue). | +| `modified-workflow-needs-green-run` | PASS | The diff touches no `.github/workflows/**`, `scripts/benchmarks/**`, or `.github/actions/**` path, so the rule does not fire. | + +## Evidence Location Compliance + +- Diff scan: zero files in the branch diff under `artifacts/baselines/`, `artifacts/qa/`, + `artifacts/evidence/`, `artifacts/coverage/`, or any other forbidden `artifacts/` sub-path. + Every evidence artifact in the diff is under + `docs/features/active/winformspumphost-suite-determinism-511/evidence//` with canonical + kinds (`baseline`, `remediation-baseline`, `regression-testing`, `qa-gates`, `other`). +- `validate_evidence_locations.py` does not exist in this repository (there is no + `scripts/dev_tools/`); the scan above was performed directly against `git diff --name-only` + output. +- No evidence-path override was supplied by any caller; no `EVIDENCE_LOCATION_OVERRIDE_REJECTED` + entry is required. +- Raw-artifact hygiene: `evidence/.gitignore` excludes `*.trx`, `*.coverage`, `*.coveragexml`, and + the vstest scratch directories; zero raw TRX or binary coverage files are tracked or present on + disk under the evidence tree (verified with `git ls-files` and `find`). + +## 8. Gaps and Exceptions + +1. **Spec `## Root Cause Analysis` retains pre-measurement assertions** ("`IsHandleCreated` is + `false` for the whole test"; "The `ItemViewer`'s two WebView2 children never obtain a handle") + that the committed measurement and the revised AC 6 / Scope sections contradict. Non-blocking: + the remediation exit criteria deliberately scoped spec revision to the AC and Scope sections, + and the revised sections carry explicit "(Revised 2026-08-23...)" markers. Recorded as + code-review finding CR-1 with a follow-up recommendation. +2. **AC 1 / AC 3 literal wording** still says the ten TRX results are "stored under + `evidence/regression-testing/`", but the raw TRX were deleted at explicit maintainer + instruction after fidelity verification + (`evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`). The distilled markdown + is the evidence of record. Non-blocking; recorded as CR-2. +3. **Original plan Phases 5-6 checkboxes remain unchecked** in `plan.2026-08-21T18-10.md`; that + work was carried and completed by `remediation-plan.2026-08-23T20-57.md` (42/42 tasks checked), + as its header records. Non-blocking bookkeeping observation (CR-4). +4. **Template resolution**: the MCP template asset tool is unreachable from this environment; this + artifact reproduces the canonical heading set directly (provenance note above). + +## 9. Summary of Changes + +- `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs` (+9): corrected + comment block above the retained defensive `viewer.Handle` read. +- `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs` (+7): same correction at the + standalone arrange block. +- `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs` (+108): two new + regression tests — `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` (handle exists; + `InvokeRequired` false on the pump thread) and + `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` (pins the measured inherited + handle-created state of both WebView2 children). +- `docs/features/active/winformspumphost-suite-determinism-511/**`: spec re-scope, decision + record, remediation inputs/plan, and the full evidence tree (68 files). +- `.claude/agent-memory/**`: agent bookkeeping, including the host-identifier sanitization rule + and its index entries (26 files). + +## 10. Compliance Verdict + +**PASS.** Zero blocking findings. All seven remediation cycle 1 exit criteria are satisfied on +independently re-verified evidence. The branch is ready for a pull request against `main` that +does not claim to close #511 or #571, per the recorded decision. + +## Appendix A: Test Inventory + +New tests introduced by this branch (both in +`QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`): + +| Test | Location | Purpose | +| --- | --- | --- | +| `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` | `:301` | Asserts the harness viewer's `IsHandleCreated` is true and `InvokeRequired` is false on the pump thread, so `Control.Invoke` cannot throw for want of a handle. | +| `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` | `:356` | Pins the measured inherited state: both WebView2 children are handle-created by `ItemViewer` construction (`ISupportInitialize.EndInit`), not by the harness. | + +Modified tests: none (the Part2/ViewerSetup edits are comment blocks plus the previously-added +defensive read inside existing harness/arrange code). + +## Appendix B: Toolchain Commands Reference + +Commands recorded in the evidence of record (executor-run; this review verified the committed +artifacts and re-ran read-only checks rather than regenerating coverage): + +1. `dotnet tool restore` +2. `dotnet tool run csharpier format `; verify with `dotnet tool run csharpier check .` +3. `& '\MSBuild\Current\Bin\MSBuild.exe' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true` +4. `& '\MSBuild\Current\Bin\MSBuild.exe' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true` +5. `& '\...\Extensions\TestPlatform\vstest.console.exe' /EnableCodeCoverage /InIsolation /Logger:trx /TestCaseFilter:"TestCategory!=LiveOutlook"` +6. `pwsh -NoProfile -File .\scripts\vscode\Invoke-MSTestWithCoverage.ps1 -SearchRoot . -CoverageOutput coverage\remediation.cobertura.xml` (numeric C# coverage source; copied to `artifacts/csharp/coverage.xml`) + +Reviewer-run verification commands (read-only): `git diff --numstat f85a36fa..b4d47adc`; +`git diff f85a36fa..HEAD -- QuickFiler/` (empty); full line counts of the three changed files; +added-line scans for timing APIs, host identifiers, and closing keywords; direct reads of the +Cobertura root attributes in `artifacts/csharp/coverage.xml`; `git ls-files` / `find` raw-artifact +scans of the evidence tree. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/remediation-inputs.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/remediation-inputs.2026-08-23T20-57.md new file mode 100644 index 000000000..67b34b5f8 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/remediation-inputs.2026-08-23T20-57.md @@ -0,0 +1,265 @@ +# Remediation Inputs — cycle 1 (R1), feature `winformspumphost-suite-determinism-511` + +Timestamp: 2026-08-23T20-57 +Canonical issue number for this feature is 511. Secondary: 571. +Branch: `bug/winformspumphost-suite-determinism-511-exec` +Feature folder: `docs/features/active/winformspumphost-suite-determinism-511` +Approved plan: `docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md` + +This document opens remediation cycle 1. It is the sole requirements input for the cycle's +remediation plan. It consolidates the six blocking findings recorded at the 2026-08-22T18-05 halt, +the two human-interaction decisions recorded at 2026-08-23T20-40, and four further orchestrator +scope decisions established by verification on 2026-08-23T20-57. + +--- + +## Part 1 — Ground truth re-verified on 2026-08-23T20-57 + +Every claim below was re-measured in this worktree by the orchestrator before this document was +written. None of it is carried over on trust from a prior agent's summary. + +| # | Claim | How it was verified | Result | +| --- | --- | --- | --- | +| 1 | Branch head is `edb2e63f`, remote in sync, rebased onto `main` `f85a36fa` | `git log --oneline`, `git rev-parse origin/` | confirmed | +| 2 | Diff vs `main` is exactly three code files, all under `QuickFiler.Test/` | `git diff --stat f85a36fa..HEAD -- '*.cs' '*.csproj'` | confirmed: +118 lines, 3 files | +| 3 | The two false comment blocks are present as described | `sed -n '80,100p'` Part2.cs; `sed -n '428,448p'` ViewerSetupTests.cs | confirmed | +| 4 | `p4-t2` holds exactly ten TRX | `find`/count | confirmed | +| 5 | Nine of the ten runs report `failed=0`; run 5 reports `failed=1` | TRX `ResultSummary/Counters` parsed directly | confirmed | +| 6 | The single failure is `GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform` | TRX `UnitTestResult[@outcome='Failed']` | confirmed — it is in `UtilitiesCS.Test`, an assembly this diff cannot reach | +| 7 | All four of this child's named tests pass in 10 of 10 runs | TRX per-test outcome scan | confirmed: `{Passed}` only, for all four | +| 8 | The committed distilled record matches the raw TRX | `determinism-ten-runs.2026-08-21T18-10.md` compared against the values re-derived in rows 5-7 | confirmed identical | + +Row 8 is the finding that licenses the evidence disposition in Part 3, Decision 3: the committed +markdown is a faithful distillation, so the raw TRX carry no audit value that is not already in the +repository. + +--- + +## Part 2 — Findings carried into this cycle + +### Findings resolved by re-scoping the claim, requiring no code change + +**A — the remedy is a measured no-op.** The inserted +`_ = await host.InvokeAsync(() => viewer.Handle)` forces a window handle that already exists. +`ItemViewer.InitializeComponent` runs `ISupportInitialize.EndInit()` on both WebView2 children, +which creates their handles, and WinForms creates a parent's handle when a child's is created. + +**B — the observed defect is a different root cause.** The only genuine pre-fix failure was seven +expiries at the 60,000 ms `PumpTimeoutMs` under machine load. A missing handle makes +`Control.Invoke` throw immediately; it does not hang for sixty seconds. + +**C — the post-fix evidence is statistically weak.** Thirty consecutive green tracked runs is about +a 1-in-4 outcome under the null hypothesis that the change has no effect. + +A, B and C are **accepted as accurate**. They are addressed by correcting what this branch claims, +not by changing code. They are stated here so the remediation plan does not attempt to "fix" them +and so the feature review does not re-raise them as unaddressed. + +### Findings requiring action in this cycle + +**D — two inserted comment blocks assert the opposite of what was measured. (blocking)** + +Locations, re-verified 2026-08-23T20-57: + +- `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`, the comment block + immediately above the `viewer.Handle` read, currently claiming the viewer "can reach the act with + no window handle" and that the two WebView2 children "are not dragged into handle creation". +- `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`, the comment block + immediately above its `viewer.Handle` read, currently claiming the children "stay handle-less". + +Both are false, and both contradict the corrected assertions in +`QfcItemController.InitializationTests.Part3.cs`, which assert the children **are** handle-created. +`CLAUDE.md` C#6.3 requires comments to stay synchronized with behavior. + +Required correction: rewrite both blocks to state the measured truth, namely that both WebView2 +children, and therefore the parent `ItemViewer`, are already handle-created when construction +returns, via the Designer-emitted `ISupportInitialize.EndInit()` calls. The corrected comment +**must also state that the read is therefore redundant today and is retained deliberately as a +defensive measure**, so that the fixture does not silently depend on a third-party side effect this +repository neither controls nor observes. A comment that merely stops asserting a falsehood, but +still leaves a reader to infer the statement is load-bearing, does not discharge this finding. + +**E — spec acceptance criterion 6 is unsatisfiable as worded. (blocking)** + +AC 6 requires a test asserting "both WebView2 children remain handle-less". Measurement proves they +are handle-created at construction. Revise AC 6 to assert the measured inherited state. + +Three further acceptance criteria are unchecked and must be reconciled against the re-scoped claim +rather than left dangling: + +- **AC 3** — "the ten consecutive runs ... are all green". Nine of ten are suite-wide green; run 5 + carries one failure in a sibling-owned assembly. Revise per Decision F below and cite issue #594. +- **AC 8** — 21 pump-host call sites pass in the final run. Satisfied by the Phase 5 final run. +- **AC 13** — the five-step toolchain completes green in a single final pass with coverage captured. + Satisfied by the Phase 5 final run. +- **AC 14** — `## Rollout & Follow-up` names the filed follow-up issue. The issue now exists: **#592**. + +**F — the absolute-zero gate spans a sibling-owned assembly. (resolvable)** + +Plan task P4-T2 requires each of ten TRX to record "a failed count of exactly 0" across all nine +assemblies. Run 5's single failure is +`UtilitiesCS.Test.Extensions.DfDeedle_COM_Tests.GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform`, +which this child's three-file `QuickFiler.Test/` diff cannot reach or fix. + +Required correction: narrow P4-T2's zero condition to the classes this child owns, per the ratified +repository precedent that a child's absolute-zero gate is scoped to the classes it owns and the +residual is promoted as its own defect. The residual is already promoted as **#594**. The narrowed +condition is satisfied by the measured evidence in Part 1 rows 5-7 and requires **no re-run**. + +--- + +## Part 3 — Orchestrator scope decisions established 2026-08-23T20-57 + +These four decisions are made by the orchestrator on verified evidence. They are inputs to the +plan, not open questions. + +### Decision 1 — the pull request targets `main`, not the epic integration branch + +Verified: `origin/epic/quickfiler-suite-determinism-foundation-integration` is at `e7b4824a` and is +a **strict ancestor** of `origin/main` (`f85a36fa`). `git log integration..main` returns 7 commits; +`git log main..integration` returns 0. PR #595 already merged the integration branch into `main`, +and PR #596 merged the final epic-status document. The epic is closed, recorded as +`deliver_three_children_descope_511`. + +Consequences, all of which the plan must honour: + +- Opening a PR against the integration branch would produce an **85-file diff carrying 7 unrelated + `main` commits**, and would merge into a branch that is already fully merged. +- Against `main` the PR shows exactly this child's own commits and 63 files. +- `.github/workflows/ci.yml` triggers `pull_request` on `[main, development]` only. Targeting the + integration branch yields **zero checks**; targeting `main` runs the real CI workflow. The prior + checkpoint recorded `ci_gate.applicable: false` on the integration-branch premise. That premise + is now false: **CI is applicable and is a real gate.** +- `epic_mode` is set to `false` with this rationale recorded. The epic-mode merge-on-green step no + longer applies, because there is no live integration branch to merge into. + +### Decision 2 — the defensive handle read is retained, not deleted + +Finding A establishes the statement is a no-op today. The alternative to correcting its comment is +deleting the statement. It is **retained**, because the maintainer's recorded HI-1 decision is to +"keep the fixture hardening", and because the new Part3.cs regression test now pins the inherited +state loudly: if a future WebView2 change makes the children handle-less, that test fails and the +retained read keeps the two named tests working. The plan must not delete the statement. It must +make the comment tell the truth about it, including its present redundancy. + +### Decision 3 — raw vstest artifacts are gitignored at the evidence root, then deleted + +The worktree carries roughly 1.2 GB of untracked raw output under the evidence tree: 56 `.trx` and +42 `.coverage` files. `.gitignore:140` already excludes `*.coverage` repository-wide; `*.trx` is +**not** excluded, so a `git add -A` would stage roughly half a gigabyte of TRX. + +Disposition, in this order: + +1. Create `docs/features/active/winformspumphost-suite-determinism-511/evidence/.gitignore` + excluding `*.trx`, `*.coverage`, and the `vstest.console.exe` per-run scratch directories. This + closes the `git add -A` hazard for the **new** TRX that Phase 5 will produce, and it lives inside + the feature's own documentation tree, so it does not touch repository-root configuration and does + not disturb the three-code-file scope lock. +2. Retain the existing raw artifacts for the duration of this cycle so the re-audit can spot-check + them. +3. Delete every raw `.trx` and `.coverage` under the evidence tree as the **final** task of the + cycle, before the pull request is opened. + +Justification for deletion: Part 1 row 8 establishes that the committed distilled markdown reproduces +the raw data faithfully. Repository policy rejects committed raw machine coverage artifacts. The +distilled record is the evidence of record. + +### Decision 4 — the follow-up issues are already filed; do not re-file them + +Verified against GitHub on 2026-08-23T20-57: + +| Residual | Issue | State | +| --- | --- | --- | +| Load-induced 60 s `PumpTimeoutMs` cascade — the genuine #511 defect | **#592** | OPEN | +| Three pre-existing `UtilitiesCS.Test` flakes blocking any suite-wide zero gate | **#594** | OPEN | +| Repository-wide analyzer version skew (plan task P6-T20) | **#597** | OPEN | + +Also verified: **#511 and #571 are both already CLOSED as `NOT_PLANNED`** (2026-08-23T19:07), +superseded by #592, with the premise-correction comments already posted to both. + +The plan must therefore **not** file duplicates, and must **not** carry any closing keyword for +#511 or #571. Plan tasks P6-T1 and P6-T20, which instruct `gh issue create`, are discharged by +#592 and #597 respectively and must be recorded as already-satisfied with the issue number cited, +not re-executed. + +Two residuals remain unfiled and are to be promoted through the MCP promotion lifecycle by the +orchestrator, outside the plan's execution scope: + +- the orchestrator checkpoint `blocked_reason` enum cannot express a substantive halt; +- repository-wide host-identifier sanitization of the roughly 146 + 157 files outside this feature. + +--- + +## Part 4 — Remaining unexecuted work from the approved plan + +32 of 74 plan tasks are unchecked. The plan is otherwise complete through Phase 4. + +- **P4-T2** — narrow per Finding F; satisfied by existing measured evidence; **no re-run**. +- **Phase 5 (P5-T1 … P5-T10)** — the final QC loop, entirely unexecuted. Mandatory and + unconditional: `dotnet tool restore`, scoped `csharpier format`, repo-wide `csharpier check`, + `msbuild /t:Rebuild` with analyzers, `msbuild /t:Rebuild` with `TreatWarningsAsErrors`, the full + nine-assembly `vstest.console.exe` run, the coverage capture, the coverage delta check, the + 500-line re-audit, and the clean-pass attestation. `SKIPPED` is not a valid outcome for any of + them. +- **Phase 6 (P6-T1 … P6-T21)** — acceptance-criteria check-off, the `## Rollout & Follow-up` + update, the AC status summary, and the commits. Adjusted by Decision 4: the two `gh issue create` + tasks are already discharged. + +Note for Phase 5 and the re-audit: the ten-run determinism evidence in Phase 4 was produced from a +binary whose source differs from the post-remediation source **by comments only**. That is why no +re-run of Phase 4 is required. This must be stated explicitly in the evidence rather than left for +a reviewer to infer. + +--- + +## Part 5 — Exit criteria for this cycle + +The cycle exits when the re-audit (`code-review`, `feature-audit`, `policy-audit`) reports a +combined blocking count of zero. Specifically: + +1. Both comment blocks state the measured truth, including the present redundancy of the read. +2. Spec AC 6 is revised to the measured inherited state; AC 3 is revised to the owned-class scope + citing #594; AC 8, AC 13 and AC 14 are satisfied and checked off with cited evidence. +3. P4-T2's zero condition is narrowed to owned classes and recorded as satisfied on existing + evidence. +4. The Phase 5 toolchain completes green in a single final pass with numeric coverage recorded. +5. The evidence `.gitignore` exists and the raw `.trx` / `.coverage` files are removed. +6. No artifact claims this branch fixes #511 or #571, and no closing keyword for either appears + anywhere in the branch or in the pull-request body. +7. The spec's `## Scope & Non-Goals` "In scope" bullets no longer assert the falsified premise + (see Part 6). + +--- + +## Part 6 — Addendum: the spec's Scope section also asserts the falsified premise + +Added 2026-08-23T21-10 by the orchestrator after reading `spec.md` lines 90-137. This is a gap in +Part 2's Finding E, which addressed only the `## Acceptance Criteria` section. The following +`## Scope & Non-Goals` "In scope" bullets are contradicted by the measurement and must be revised +in the same cycle: + +1. **"Deterministic creation of the `ItemViewer` window handle on the pump thread inside the shared + pump harness, so that `Control.Invoke` has an existing handle before any act."** The handle + already exists at construction. Revise to state that the harness makes the *inherited* handle + state explicit and independent of a third-party side effect, rather than creating a handle that + would otherwise be absent. + +2. **"#571 in full: both named intermittent failures."** Not delivered. #571 is closed as + `NOT_PLANNED`, superseded by #592. Revise to state that this feature does not fix #571 and that + the real cause is tracked as #592. + +3. **"#511's load-flakiness half: removing the handle race removes one whole class of the + load-induced failures reported in #511."** There is no handle race; Finding A and Finding B + falsify this. Revise to state that the load-induced failures are a 60-second `PumpTimeoutMs` + expiry tracked as #592, which this feature does not address. + +The two bullets that remain accurate and should be retained are the regression tests in +`QfcItemController.InitializationTests.Part3.cs` and the empirical determinism record. + +Also revise the `## Out of scope / non-goals` bullet that refers to #511's visible-window half +"requiring its own issue" so that it names the issue that now exists (**#592**) rather than +describing one as still to be filed. + +The plan must treat this addendum as part of Finding E. A revision that corrects AC 6 but leaves +the Scope section asserting that this feature fixes #571 would leave the specification internally +contradictory, and the feature audit would correctly raise it. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/remediation-plan.2026-08-23T20-57.md b/docs/features/active/winformspumphost-suite-determinism-511/remediation-plan.2026-08-23T20-57.md new file mode 100644 index 000000000..adf064ee2 --- /dev/null +++ b/docs/features/active/winformspumphost-suite-determinism-511/remediation-plan.2026-08-23T20-57.md @@ -0,0 +1,244 @@ +# winformspumphost-suite-determinism — Remediation Plan, cycle 1 (R1) + +- **Issue:** #511 (canonical), #571 (secondary) — both already CLOSED as NOT_PLANNED, superseded by #592 +- **Parent:** epic `quickfiler-suite-determinism-foundation` (closed; recorded as `deliver_three_children_descope_511`) +- **Owner:** drmoisan +- **Last Updated:** 2026-08-23T23-05 +- **Status:** Ready for preflight (revision 1 — fifteen preflight deltas applied in place) +- **Version:** 1.2 +- **Work Mode:** `full-bug` +- **Branch:** `bug/winformspumphost-suite-determinism-511-exec` +- **Requirements source (sole):** `docs/features/active/winformspumphost-suite-determinism-511/remediation-inputs.2026-08-23T20-57.md` +- **Acceptance-criteria source:** `docs/features/active/winformspumphost-suite-determinism-511/spec.md`, section `## Acceptance Criteria` (14 criteria; 9 already checked, 5 reconciled by this cycle) +- **Original approved plan:** `docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md` (Phases 0-4 executed except P4-T2; Phases 5-6 unexecuted; this plan carries the remaining work as adjusted by the remediation inputs) + +**Fail-closed evidence rule:** Every baseline artifact, QA-gate artifact, and coverage-comparison artifact named below is mandatory. If any is missing or incomplete, the outcome is BLOCKED or INCOMPLETE, never PASS. + +**Evidence-location invariant (non-overridable).** All evidence goes under `docs/features/active/winformspumphost-suite-determinism-511/evidence//` where the kind is one of `remediation-baseline`, `regression-testing`, `qa-gates`, `other`, `issue-updates`, `baseline`. No `artifacts/` sub-path other than `artifacts/orchestration/` may hold evidence. The remediation inputs name only canonical paths; no override was supplied and none was rejected. + +**Feature root abbreviation.** `FEATURE` denotes `docs/features/active/winformspumphost-suite-determinism-511`. Every evidence path in a task body is written out in full. + +--- + +## What This Cycle Is and Is Not + +This cycle corrects claims, not code behaviour. Findings A, B, and C of the remediation inputs are accepted as accurate and are addressed by re-scoping what this branch claims. The executable-code diff does not change: the only source edits in this plan are comment-block rewrites inside two files already in the diff. Do not attempt to "fix" findings A, B, or C by changing code, and do not re-open the retained-versus-deleted decision on the defensive handle read — orchestrator Decision 2 retains it. + +**Prohibitions specific to this cycle (binding on every task):** + +1. No artifact produced by this plan may claim this branch repairs issue #511 or issue #571. Both are already CLOSED as NOT_PLANNED, superseded by #592. No GitHub closing keyword (any inflection of the stems fix / close / resolve) may appear immediately before either issue reference in any commit message, spec edit, or evidence artifact this plan produces. Carve-out, binding on any re-audit of this prohibition: the requirements input `docs/features/active/winformspumphost-suite-determinism-511/remediation-inputs.2026-08-23T20-57.md` contains three matches of the case-insensitive regex `(fix|clos|resolv)[a-z]* #(511|571)` at its lines 227, 248, and 264, all inside negations that deny the repair claim. That file is exempt by design: it is the input this plan consumes, not an artifact this plan produces; the P4-T8 file scan deliberately excludes it; and GitHub parses closing keywords only in commit messages and pull-request bodies, never in file contents, so its committed text cannot auto-close either issue. A literal re-audit of "no closing keyword anywhere in the branch" must apply this carve-out rather than raise the requirements input as a finding. +2. Do not re-run the Phase 4 ten-run determinism pass. The post-remediation source differs from the source that produced that evidence by comments only; P2-T4 records that rationale as evidence. +3. Do not create any GitHub issue. Decision D4 verified #592, #594, and #597 already exist; original-plan tasks P6-T1 and P6-T20 are discharged by them. +4. Do not weaken any test to obtain a pass. +5. Introduce no `Thread.Sleep`, `Task.Delay`, `SpinWait`, retry loop, or raised timeout constant. +6. The diff against the merge base must remain exactly three code files, all under `QuickFiler.Test/`: `Controllers/QfcItemController.InitializationTests.Part2.cs`, `Controllers/QfcItemController.ViewerSetupTests.cs`, `Controllers/QfcItemController.InitializationTests.Part3.cs`. Do not edit anything under `QuickFiler/`, any `*.csproj`, or any `.claude/` path other than `.claude/agent-memory/`. + +## Toolchain Commands — Use Verbatim + +Run in this order; restart from the first step if any step fails or changes files. + +1. `dotnet tool restore` +2. `dotnet tool run csharpier format ` then verify with `dotnet tool run csharpier check .` +3. `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true` +4. `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true` +5. `vstest.console.exe /EnableCodeCoverage /InIsolation /TestCaseFilter:"TestCategory!=LiveOutlook"` + +Non-negotiable command facts, carried forward from the approved plan: + +- **Always `/t:Rebuild`, never `/t:Build`.** MSBuild's up-to-date check does not invalidate on a command-line `/p:` change, so a warm `/t:Build` returns exit 0 with `CoreCompile` skipped on every project and runs no analyzers. Every msbuild task below asserts a zero count of the log line `Skipping target "CoreCompile"`. +- **Never add `/p:Nullable=enable`.** No project carries a `` element and there is no `Directory.Build.props`; the property conscripts files that never opted in and diverges from `.github/workflows/ci.yml`. +- **`/InIsolation` is mandatory.** Without it roughly 1,695 phantom failures appear with empty messages and sub-millisecond durations. That mass-failure signature means the flag is missing; it is a fabricated regression and must NOT be "fixed". +- **Use `pwsh -NoProfile -Command '...'` with absolute paths** for every msbuild and vstest invocation. The Bash tool mangles MSBuild switches such as `/m` into `M:/`, producing MSB1008. Single-quote the outer payload and double any inner single quotes. Bare `msbuild` does not resolve in this environment — `command -v msbuild` returns nothing and `pwsh -NoProfile` carries no Visual Studio developer environment — so every msbuild invocation uses the verified absolute path `C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe` via the call operator `&`, with the path's single quotes doubled to `''` when it sits inside a single-quoted `-Command` payload. +- **`/Logger:trx` is always paired with an explicit `/ResultsDirectory:`** naming a subdirectory private to the invoking task (prefix `r1-`), so TRX-count acceptance conditions are unambiguous against any other TRX in the evidence tree. (The 56 pre-existing raw TRX and 42 `.coverage` files — 1,180.6 MB — were deleted at maintainer instruction on 2026-08-23, and 188 empty scratch directories were pruned; the recorded disposition is `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`. The directories `evidence/regression-testing/p4-t2/`, `p1-t3/`, `p1-t4/`, `p2-t6/`, `p3-t4/` through `p3-t7/`, `supplementary-node-contention/`, `supplementary-node-contention-b/`, and `evidence/baseline/p0-t15/` no longer exist; no task below may assert their existence.) +- **Known pre-existing flakes:** the nine-assembly suite carries three known pre-existing flakes in `UtilitiesCS.Test`, tracked as issue #594. Every suite-run pass condition in this plan is scoped to the `QuickFiler.Test` assembly (the assembly containing every class this child touches); a failure in a sibling assembly is recorded with its fully qualified name and attributed to issue #594 in the task's artifact, and does not fail the task. + +### Canonical assembly list + +``` + QuickFiler.Test\bin\Debug\QuickFiler.Test.dll + SVGControl.Test\bin\Debug\SVGControl.Test.dll + Tags.Test\bin\Debug\Tags.Test.dll + TaskMaster.Test\bin\Debug\TaskMaster.Test.dll + TaskTree.Test\bin\Debug\TaskTree.Test.dll + TaskVisualization.Test\bin\Debug\TaskVisualization.Test.dll + ToDoModel.Test\bin\Debug\ToDoModel.Test.dll + UtilitiesCS.Test\bin\Debug\UtilitiesCS.Test.dll + VBFunctions.Test\bin\Debug\VBFunctions.Test.dll +``` + +### Resolving `vstest.console.exe` + +```powershell + $vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe' + $vstest = & $vswhere -latest -products * -find 'Common7\IDE\Extensions\TestPlatform\vstest.console.exe' | + Select-Object -First 1 +``` + +### Coverage numbers + +Numeric coverage is produced by `pwsh -NoProfile -File .\scripts\vscode\Invoke-MSTestWithCoverage.ps1 -SearchRoot . -CoverageOutput coverage\remediation.cobertura.xml`, which wraps the same nine assemblies with `dotnet-coverage` and emits Cobertura XML into the gitignored `coverage\` directory. The headline figure is the root `line-rate` attribute; the `QuickFiler` figure is that package's `line-rate`; the changed-module figure is the `line-rate` of the Cobertura classes whose `filename` begins `QuickFiler\Controllers\QfcItemController`. Every coverage task records real numbers; the token `UNVERIFIED` is not an acceptable value in any coverage field. The baseline of comparison is `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md`. The lines this cycle changes are comment lines only, so the changed-line coverage row legitimately records zero executable lines changed. + +--- + +### Phase 0 — Policy Reads and Remediation Baseline + +- [x] [P0-T1] Read `CLAUDE.md` in full and record the four numbered policy sections it embeds (General Code Change, General Unit Test, C# Code Change, C# Unit Test). Acceptance: the file has been read end to end and its Policy Compliance Order list is quoted in the P0-T5 artifact. +- [x] [P0-T2] Read `.claude/rules/general-code-change.md` in full. Acceptance: the 500-line file-size limit and the mandatory toolchain loop are quoted in the P0-T5 artifact. +- [x] [P0-T3] Read `.claude/rules/general-unit-test.md` in full. Acceptance: the coverage thresholds and the Determinism Infrastructure banned-API list are quoted in the P0-T5 artifact. +- [x] [P0-T4] Read `.claude/rules/csharp.md` in full, then read `docs/features/active/winformspumphost-suite-determinism-511/remediation-inputs.2026-08-23T20-57.md` in full as the sole requirements source for this cycle. Acceptance: the four toolchain commands, the six "Prohibited Behaviors" bullets, and the seven remediation exit criteria (remediation-inputs Part 5, including exit criterion 7 added by the Part 6 addendum) are quoted in the P0-T5 artifact. +- [x] [P0-T5] Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/phase0-instructions-read.md` carrying `Timestamp:`, `Policy Order:` (the files in the order read), and an explicit list of the files read with the quoted content required by P0-T1 through P0-T4. Acceptance: the file exists and all three required fields are present and non-empty. +- [x] [P0-T6] Record the remediation git baseline: current branch name, `git rev-parse HEAD`, `git merge-base origin/main HEAD`, and `git status --porcelain` line count. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/git-identity.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` carrying the branch, the HEAD sha, the merge-base sha, and the porcelain line count. Acceptance: the artifact exists with all four fields, the recorded branch is `bug/winformspumphost-suite-determinism-511-exec`, and the recorded merge-base sha is a 40-character hex string. The HEAD sha is provenance only; later scope-lock tasks gate on tree invariants against the recorded merge base (referred to below as `$MergeBase`), never on a pinned HEAD. +- [x] [P0-T7] Record the current state of the three touched files. Count the lines returned by `Get-Content -LiteralPath` for each of `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`, `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`, and `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, and count the matches of `Select-String -SimpleMatch 'viewer.Handle'` in the first two files. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/touched-files-state.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing all five counts. Acceptance: the recorded line counts are 416, 470, and 398 respectively and the recorded `viewer.Handle` match count is exactly 1 in each of the two files; a different count is recorded verbatim and flagged as drift rather than silently adjusted. The literal `viewer.Handle` is quoted here verbatim and is present in the tracked tree. +- [x] [P0-T8] Re-verify the toolchain prerequisites the original Phase 0 provisioned: `dotnet --version` run from the worktree root, existence of the `packages` directory at the worktree root, and existence of the two back-filled analyzer files `packages/Meziantou.Analyzer.3.0.156/analyzers/dotnet/roslyn5.0/cs/Meziantou.Analyzer.dll` and `packages/Roslynator.Analyzers.4.16.0/analyzers/dotnet/roslyn4.7/cs/Roslynator.CSharp.Analyzers.dll`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/toolchain-precheck.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:`. Acceptance: `dotnet --version` prints `8.0.205` and all three existence checks report true. If any check fails, re-run the corresponding original-plan Phase 0 task (P0-T8, P0-T9, or P0-T10 of `plan.2026-08-21T18-10.md`) rather than editing any tracked file. +- [x] [P0-T9] Verify `docs/features/active/winformspumphost-suite-determinism-511/evidence/.gitignore` (orchestrator Decision 3, step 1 — already satisfied: the file exists at 929 bytes, created alongside the raw-artifact disposition recorded in `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`). Never rewrite the file. It carries a rationale header plus a superset of the originally dictated lines, including `*.coveragexml` and `Deploy_*/`, and `Deploy_*` is the vstest deployment scratch directory whose default name embeds the account and host — deleting that line would reintroduce a host-identifier leak. Verify the file contains, each as its own non-comment line, all five of `*.trx`, `*.coverage`, `*.coveragexml`, `Deploy_*/`, and the date-stamped scratch pattern `20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]_*/`. Then APPEND the single line `r1-p*-t*/` at the end of the file if and only if that line is not already present, covering the Phase 3 per-run scratch directory; the append is the only permitted modification — no existing line may be removed, reordered, or altered. This closes the `git add -A` hazard for the new TRX the Phase 3 loop will produce; `*.trx` is not excluded by the repository-root `.gitignore`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/remediation-baseline/evidence-gitignore.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the five verified lines and whether the `r1-p*-t*/` append was performed. Acceptance: the `.gitignore` file exists and contains, as non-comment lines, all five verified lines plus `r1-p*-t*/`; no pre-existing line was removed or altered; `git check-ignore -q docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/r1-p3-t6/probe.trx` exits 0; and `git check-ignore -q docs/features/active/winformspumphost-suite-determinism-511/evidence/.gitignore` exits 1, confirming the `.gitignore` itself remains committable. + +### Phase 1 — Comment Corrections (Finding D) + +Finding D: two inserted comment blocks assert the opposite of what was measured (`docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md`). Both `viewer.Handle` read statements are retained per orchestrator Decision 2; only the comments change. A comment that merely stops asserting the falsehood but leaves the read looking load-bearing does not discharge the finding — each corrected comment must state both the measured truth and the read's present redundancy. + +- [x] [P1-T1] Edit `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`: replace the five comment lines currently at lines 87-91 (the block beginning with the words quoted verbatim as `no window handle` and `not dragged into handle creation`), immediately above the `viewer.Handle` read inside `BuildPumpHarnessCoreAsync`, with exactly these seven lines: + + ``` + // #571 (measured 2026-08-22): both WebView2 children — and therefore the parent + // ItemViewer — are already handle-created when construction returns, because + // InitializeComponent runs the Designer-emitted ISupportInitialize.EndInit() calls on + // both children and WinForms creates a parent's handle when a child's is created. This + // read is therefore redundant today; it is retained deliberately as a defensive + // measure so the fixture does not silently depend on a third-party side effect this + // repository neither controls nor observes. + ``` + + Do not delete or move the statement below the comment; no other line of the file changes. Acceptance, each condition measured with `Select-String -SimpleMatch` against this file only: the literal `already handle-created when construction returns` matches exactly 1 line; the literal `retained deliberately` matches exactly 1 line; the literal `no window handle` matches 0 lines; the literal `not dragged into handle creation` matches 0 lines; the literal `viewer.Handle` still matches exactly 1 line; and the file's line count is exactly 418. +- [x] [P1-T2] Edit `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`: replace the two comment lines currently at lines 436-437 (the block ending with the words quoted verbatim as `stay handle-less`), immediately above the `viewer.Handle` read in the arrange block of `ResolveControlGroupsAsync_ThroughThePumpHost_PopulatesTipsAndControlGroups`, with exactly these six lines: + + ``` + // #571 (measured 2026-08-22): both WebView2 children, and therefore the parent + // ItemViewer, are already handle-created when construction returns, via the + // Designer-emitted ISupportInitialize.EndInit() calls. This read is redundant + // today and is retained deliberately as a defensive measure, so the fixture does + // not silently depend on a third-party side effect this repository does not + // control. + ``` + + Do not delete or move the statement below the comment; no other line of the file changes. Acceptance, each condition measured with `Select-String -SimpleMatch` against this file only: the literal `already handle-created when construction returns` matches exactly 1 line; the literal `retained deliberately` matches exactly 1 line; the literal `stay handle-less` matches 0 lines; the literal `viewer.Handle` still matches exactly 1 line; and the file's line count is exactly 474. +- [x] [P1-T3] Re-audit the 500-line cap on the three touched files by counting the lines returned by `Get-Content -LiteralPath` for each. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/file-size-after-comment-fix.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` listing each file with its P0-T7 count and its post-edit count. Acceptance: the recorded post-edit counts are 418, 474, and 398 respectively, each less than 500, and the `QfcItemController.InitializationTests.Part3.cs` count is unchanged from P0-T7, confirming this phase touched only the two comment sites. +- [x] [P1-T4] Confirm the scope lock holds after the comment corrections: run `git diff --name-only $MergeBase` using the merge-base sha recorded in P0-T6, filter the result to paths ending `.cs`, `.csproj`, `.props`, `.targets`, or `.config`, and confirm the filtered set is exactly the three paths `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`, `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`, and `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`; then confirm zero paths in the unfiltered list begin `QuickFiler/`, zero end `.csproj`, and zero begin `.claude/` other than paths beginning `.claude/agent-memory/`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/scope-lock-after-comment-fix.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the filtered set and the three prohibited counts. Acceptance: the filtered set has exactly 3 members matching those three paths and the three prohibited counts are each exactly 0. + +### Phase 2 — Spec and Plan Reconciliation (Findings E and F) + +The AC revisions below change wording only; the checkboxes stay `[ ]` here and are flipped in Phase 4 with cited evidence. Each revised criterion must be false against a tree that lacks the cited evidence and true against this branch's measured evidence — a criterion that cannot fail gates nothing. + +P2-T7 and P2-T8 implement the remediation-inputs Part 6 addendum as part of Finding E: the spec's `## Scope & Non-Goals` section asserts the same falsified premise as the original AC 6, and a cycle that corrected the Acceptance Criteria alone would leave the specification internally contradictory. The two bullets Part 6 records as accurate — the `QfcItemController.InitializationTests.Part3.cs` regression-tests bullet and the empirical determinism-record bullet — are retained unchanged and their retention is asserted. + +- [x] [P2-T1] Revise spec acceptance criterion 6 in `docs/features/active/winformspumphost-suite-determinism-511/spec.md` (Finding E). Keep the item's existing unchecked checkbox marker and replace the item's body text (the wording requiring that both WebView2 children remain handle-less, which measurement falsified) with exactly this body text: + + ``` + `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` exists in + `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, asserts the + measured inherited state — both WebView2 children are already handle-created by + `ItemViewer` construction via the Designer-emitted `ISupportInitialize.EndInit()` calls, so + the harness inherits the handles rather than creating them — and passes. (Revised + 2026-08-23 per remediation Finding E: the original wording asserted an unmeasured + world-state that the measurement in + `evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md` + proved false.) + ``` + + The block is rendered with the spec's Acceptance Criteria layout: the first line follows the retained `- [ ] ` marker on the marker line itself, and every continuation line carries the section's 6-space continuation indent exactly as shown. Insert it byte-for-byte; do not flatten the indent. Acceptance, measured with `Select-String -SimpleMatch` against `spec.md` only: the literal `measured inherited state` matches exactly 1 line; the literal `Revised` matches at least 1 line inside the `## Acceptance Criteria` section; and the spec's AC checkbox count remains exactly 14 with exactly 9 checked and 5 unchecked. +- [x] [P2-T2] Revise spec acceptance criterion 3 in `docs/features/active/winformspumphost-suite-determinism-511/spec.md` (Findings E and F). Keep the item's existing unchecked checkbox marker and replace the item's body text (the wording requiring the ten runs to be suite-wide all green) with exactly this body text: + + ``` + The ten consecutive full nine-assembly runs are executed under induced CPU load using + `vstest.console.exe` with `/EnableCodeCoverage /InIsolation + /TestCaseFilter:"TestCategory!=LiveOutlook"`, with the evidence stored under + `evidence/regression-testing/`, and record zero failures in the `QuickFiler.Test` assembly + — the assembly containing every class this child owns — with both named end-to-end tests + and both named regression tests recorded as passed in all ten runs. Suite-wide, nine of the + ten runs are green; run 5 records a single failure in the sibling-owned `UtilitiesCS.Test` + assembly (`GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform`), which + this child's three-file `QuickFiler.Test/` diff cannot reach and which is + tracked as issue #594. (Revised 2026-08-23 per remediation Finding F and the ratified + owned-class scoping precedent.) + ``` + + The block is rendered with the spec's Acceptance Criteria layout: the first line follows the retained `- [ ] ` marker on the marker line itself, and every continuation line carries the section's 6-space continuation indent exactly as shown. Insert it byte-for-byte; do not flatten the indent. Acceptance, measured with `Select-String -SimpleMatch` against `spec.md` only: the literal `tracked as issue #594` matches exactly 1 line; the literal `owned-class scoping precedent` matches exactly 1 line; and the spec's AC checkbox count remains exactly 14 with exactly 9 checked and 5 unchecked. +- [x] [P2-T3] Narrow original-plan task P4-T2 in `docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md` (Finding F). In the P4-T2 task body, replace the acceptance clause requiring each of the ten TRX to record `a failed count of exactly 0` with an acceptance clause requiring each of the ten TRX to record zero failed tests within the `QuickFiler.Test` assembly and both named end-to-end tests plus both named regression tests recorded as passed in every TRX, with any sibling-assembly failure recorded by fully qualified name and attributed to issue #594; append the sentence fragment quoted verbatim as `narrowed 2026-08-23 per remediation Finding F` inside the task body; and change the P4-T2 checkbox from `[ ]` to `[x]`, because the narrowed condition is satisfied by the existing measured evidence (remediation-inputs Part 1 rows 5-7: ten TRX — since deleted at maintainer instruction on 2026-08-23, with `determinism-ten-runs.2026-08-21T18-10.md` as the distilled record of record — nine suite-wide green, run 5's single failure in `UtilitiesCS.Test`, all four owned named tests passed in 10 of 10). Acceptance, measured with `Select-String -SimpleMatch` against `plan.2026-08-21T18-10.md` only: the literal `narrowed 2026-08-23 per remediation Finding F` matches exactly 1 line; the literal `a failed count of exactly 0` matches 0 lines; and the count of unchecked task lines between that plan's Phase 4 heading and its Phase 5 heading is exactly 0 (that plan's Phase 4 held exactly one unchecked task before this edit). +- [x] [P2-T4] Write the no-re-run rationale artifact `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2-narrowing-rationale.2026-08-23T20-57.md` carrying `Timestamp:` and, in prose: (a) the narrowed P4-T2 condition and the measured evidence of record satisfying it — the three distilled records `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md`, `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md`, and `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md` — recording nine of ten suite-wide `failed=0`, run 5's single failure being `UtilitiesCS.Test.Extensions.DfDeedle_COM_Tests.GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform`, tracked as issue #594, and all four of this child's named tests passing in 10 of 10 runs; (b) the explicit statement that the post-remediation source differs from the source that produced that evidence by comment lines only, verified by `git diff --numstat` of the Phase 1 edits against the commit that produced the Phase 4 evidence, restricted to the three touched files, so no re-run of the ten-run determinism pass is required or performed; and (c) the statement that the committed distilled record `determinism-ten-runs.2026-08-21T18-10.md` was verified faithful to the raw TRX before their deletion (remediation-inputs Part 1 row 8), which licensed the raw-artifact deletion already carried out: the raw ten-TRX directory `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/p4-t2/` no longer exists, its contents having been deleted at maintainer instruction on 2026-08-23 as recorded in `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`. Acceptance: the artifact exists, names the deleted ten-TRX subdirectory path in the past tense, names the disposition record `raw-vstest-artifact-disposition.2026-08-23T21-40.md`, contains the literal `by comment lines only` on a single line, and contains the literal `#594`. +- [x] [P2-T5] Record original-plan tasks P6-T1 and P6-T20 as discharged in `docs/features/active/winformspumphost-suite-determinism-511/plan.2026-08-21T18-10.md` (orchestrator Decision 4). Change the P6-T1 checkbox to `[x]` and prepend to its task body the sentence quoted verbatim as `Discharged 2026-08-23: issue #592 already exists and carries this follow-up; no new issue is created.` Change the P6-T20 checkbox to `[x]` and prepend to its task body the sentence quoted verbatim as `Discharged 2026-08-23: issue #597 already exists and carries this follow-up; no new issue is created.` Immediately below the `### Phase 5 — Final QC Loop` heading and below the `### Phase 6 — Acceptance Criteria and Audit Handoff` heading, insert one note line each stating that the remaining unchecked tasks of that phase are executed under `remediation-plan.2026-08-23T20-57.md` per `remediation-inputs.2026-08-23T20-57.md`. Acceptance, measured with `Select-String -SimpleMatch` against `plan.2026-08-21T18-10.md` only: the literal `Discharged 2026-08-23: issue #592 already exists` matches exactly 1 line; the literal `Discharged 2026-08-23: issue #597 already exists` matches exactly 1 line; the literal `remediation-plan.2026-08-23T20-57.md` matches at least 2 lines; and the total count of unchecked task lines in that plan is exactly 29 (32 before this cycle, minus the three tasks reconciled by P2-T3 and this task). +- [x] [P2-T6] Write the discharge evidence artifact `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/discharged-issue-tasks.2026-08-23T20-57.md` carrying `Timestamp:` and a three-row table mapping each residual to its verified existing issue exactly as remediation-inputs Decision 4 records: the load-induced 60,000 ms `PumpTimeoutMs` cascade (the genuine defect behind the #511 report) to #592 OPEN, the three pre-existing `UtilitiesCS.Test` flakes to #594 OPEN, and the repository-wide analyzer version skew to #597 OPEN; plus one line recording that #511 and #571 are both CLOSED as NOT_PLANNED (2026-08-23T19:07), superseded by #592, and that no `gh issue create` is executed anywhere in this cycle. Acceptance: the artifact exists, the table has exactly 3 rows, and the literals `#592`, `#594`, and `#597` each appear at least once. +- [x] [P2-T7] Revise the three falsified "In scope" bullets in the `## Scope & Non-Goals` section of `docs/features/active/winformspumphost-suite-determinism-511/spec.md` (remediation-inputs Part 6, part of Finding E). Replace the five contiguous lines carrying the first three "In scope" bullets — the bullet beginning with the words quoted verbatim as `Deterministic creation of the`, the single-line bullet beginning with the words quoted verbatim as `#571 in full`, and the bullet containing the words quoted verbatim as `removing the handle race removes` — with exactly these thirteen lines: + + ``` + - Making the `ItemViewer` window handle state explicit on the pump thread inside the shared pump + harness. The handle already exists when construction returns (measured 2026-08-22, remediation + Finding A); the harness read makes that inherited state explicit and independent of a + third-party side effect, rather than creating a handle that would otherwise be absent. (Revised + 2026-08-23 per remediation-inputs Part 6.) + - #571 is not delivered by this feature. #571 is CLOSED as NOT_PLANNED, superseded by #592; the + real cause of both named intermittent failures is the load-induced 60,000 ms `PumpTimeoutMs` + expiry cascade, tracked as #592, which this feature does not address. (Revised 2026-08-23 per + remediation-inputs Part 6.) + - #511's load-flakiness half is not addressed here. There is no handle race (remediation Findings + A and B falsified that premise); the load-induced failures reported in #511 are the same + 60,000 ms `PumpTimeoutMs` expiry tracked as issue #592. (Revised 2026-08-23 per + remediation-inputs Part 6.) + ``` + + The block is rendered with the Scope section's own layout — bullet markers at column 0 and a 2-space continuation indent — and must be inserted byte-for-byte as shown; do not flatten the indent. Do not change the two retained "In scope" bullets below them (the `QfcItemController.InitializationTests.Part3.cs` regression-tests bullet and the empirical determinism-record bullet), and change nothing else in the file. Acceptance, each condition measured with `Select-String -SimpleMatch` against `spec.md` only: the literal `inherited state explicit` matches exactly 1 line; the literal `otherwise be absent` matches exactly 1 line; the literal `#571 is not delivered by this feature` matches exactly 1 line; the literal `expiry tracked as issue #592` matches exactly 1 line; the literal `Deterministic creation of the` matches 0 lines; the literal `#571 in full` matches 0 lines; the literal `removing the handle race removes` matches 0 lines; the retained-bullet literal `Regression tests for the new fixture invariant` still matches exactly 1 line; and the retained-bullet literal `An empirical pre-fix and post-fix determinism record captured as evidence.` still matches exactly 1 line. +- [x] [P2-T8] Revise the `## Out of scope / non-goals` bullet in `docs/features/active/winformspumphost-suite-determinism-511/spec.md` that describes #511's visible-window half as requiring its own issue (remediation-inputs Part 6, final paragraph). Replace the six contiguous lines of the bullet beginning with the words quoted verbatim as `**#511's visible-window half is out of scope and is re-attributed.**` with exactly these eight lines: + + ``` + - **#511's visible-window half is out of scope and is re-attributed.** The evidence does not + support the causal claim in #511's Actual Behavior bullet that the visible window is produced by + `WinFormsPumpHost`. See `## Root Cause Analysis`. This half is recorded under + `## Rollout & Follow-up` and is tracked as issue #592, which now exists and supersedes #511 and + #571 (both CLOSED as NOT_PLANNED); no new issue remains to be filed for it, including against + `UtilitiesCS.Test/Threading/ProgressViewer_Tests.cs`. It is deliberately **not** an acceptance + criterion of this feature, so that the feature audit does not score it as unmet. (Revised + 2026-08-23 per remediation-inputs Part 6.) + ``` + + The block is rendered with the Out-of-scope section's own layout — the bullet marker at column 0 and a 2-space continuation indent — and must be inserted byte-for-byte as shown; do not flatten the indent. Change nothing else in the file. Acceptance, each condition measured with `Select-String -SimpleMatch` against `spec.md` only: the literal `as requiring its own issue against` matches 0 lines; the literal `no new issue remains to be filed for it` matches exactly 1 line; and the literal `so that the feature audit does not score it as unmet` still matches exactly 1 line, confirming the bullet's closing sentence is preserved. + +### Phase 3 — Final QC Loop + +This loop is unconditional (original-plan Phase 5, executed here with remediation timestamps). Every command-bearing task below must execute its stated command and record `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:`; `SKIPPED` is not a valid completion state for any of them. If any step fails or changes files, restart from P3-T1 and record the restart in P3-T11 — except where a task's own text authorizes a narrower, bounded retry (the P3-T7 load-induced-timeout re-run). + +**Long-running command mechanic (mandatory for every msbuild, vstest, and coverage command in this phase).** The nine-assembly `/InIsolation` suite run and the `dotnet-coverage` run each take roughly 20 minutes over 6,437 tests, and a 16-project `/t:Rebuild` is multi-minute, against a 600,000 ms tool ceiling, so a plain foreground invocation is killed mid-run. Launch every msbuild, vstest, and coverage command via `pwsh -NoProfile -Command` using `Start-Process -PassThru` with `-RedirectStandardOutput` and `-RedirectStandardError` pointed at a log file; record the returned PID in the task's artifact; poll the log with short foreground waits until the process has exited; and take the artifact's `EXIT_CODE:` from the returned process object's `ExitCode` property, never from `$LASTEXITCODE` of the polling shell. On any abort or retry, kill the whole process tree first — the `pwsh` runner and every `testhost`, `vstest.console`, and `dotnet-coverage` child — before launching again; an orphaned child otherwise corrupts the next run's counts and holds file locks on the build outputs. + +- [x] [P3-T1] Run `dotnet tool restore` from the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-tool-restore.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` naming the restored CSharpier version. Acceptance: `EXIT_CODE: 0` and the recorded CSharpier version is 1.2.6. +- [x] [P3-T2] Apply formatting scoped to the three touched files with `dotnet tool run csharpier format QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`. The mutating pass is deliberately scoped: a repo-wide `format .` would rewrite unrelated files and break the three-file scope lock. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-csharpier-format.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the rewritten-file count, defined as the number of the three files whose SHA-256 hash (`Get-FileHash -Algorithm SHA256`) differs between a capture taken immediately before and a capture taken immediately after the `format` invocation. CSharpier 1.x prints `Formatted N files` as a processed-file count, not a rewrite count — a naive reading of that console line is always 3, and a restart rule keyed on it never terminates — so the `Formatted N files` line must not be used as the rewritten-file count. Acceptance: `EXIT_CODE: 0` and the artifact records all six hashes (three before, three after) and the hash-derived rewritten-file count. If that count is greater than 0, restart the loop from P3-T1 after this task completes. +- [x] [P3-T3] Verify formatting read-only with `dotnet tool run csharpier check .` from the worktree root. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-csharpier-check.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the unformatted-file count and, if non-zero, whether every reported file is a pre-existing condition outside the three touched files. Acceptance: no file among the three touched files is reported as unformatted. +- [x] [P3-T4] Run the analyzer gate from the worktree root with the verified absolute msbuild path, launched per the Phase 3 long-running command mechanic: the command is `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true` (bare `msbuild` does not resolve: `command -v msbuild` returns nothing and `pwsh -NoProfile` carries no Visual Studio developer environment), with stdout and stderr redirected to `coverage\analyzer-remediation.log`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-analyzer-gate.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the resolved msbuild path used, the launched PID, the warning count, the error count, and the count of log lines matching `Skipping target "CoreCompile"`. Acceptance: `EXIT_CODE: 0` (taken from the process object's `ExitCode`), the artifact records the resolved msbuild path, the recorded error count is 0, and the recorded `Skipping target "CoreCompile"` count is exactly 0, proving the analyzers actually ran. +- [x] [P3-T5] Run the nullable gate from the worktree root with the verified absolute msbuild path, launched per the Phase 3 long-running command mechanic: the command is `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true` (bare `msbuild` does not resolve, as in P3-T4), with stdout and stderr redirected to `coverage\nullable-remediation.log`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-nullable-gate.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the resolved msbuild path used, the launched PID, the error count, and the count of log lines matching `Skipping target "CoreCompile"`. Acceptance: `EXIT_CODE: 0` (taken from the process object's `ExitCode`), the artifact records the resolved msbuild path, the recorded error count is 0, the recorded `Skipping target "CoreCompile"` count is exactly 0, and the artifact confirms the command carried no `/p:Nullable=enable`. +- [x] [P3-T6] Run the full nine-assembly suite once with the resolved `vstest.console.exe`, the nine assembly paths from the canonical assembly list, `/EnableCodeCoverage`, `/InIsolation`, `/Logger:trx`, `/ResultsDirectory:docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/r1-p3-t6`, and `/TestCaseFilter:"TestCategory!=LiveOutlook"`, invoked through `pwsh -NoProfile -Command '...'` and launched per the Phase 3 long-running command mechanic, with stdout and stderr redirected to `coverage\suite-remediation.log`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-suite-run.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording total, passed, failed, and skipped counts, the launched PID, the TRX path, the per-assembly failed count for `QuickFiler.Test`, and the outcome of each of the four owned named tests (`InitializeBool_ThroughThePumpHost_CompletesAndInitializesState`, `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates`, `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread`, `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles`). Acceptance: `EXIT_CODE:` is taken from the process object's `ExitCode`; the subdirectory holds exactly one TRX file; the recorded total is at least 6,000, confirming all nine assemblies loaded (roughly 1,695 empty-message failures means `/InIsolation` was omitted — re-run with the flag and record the correction); the recorded `QuickFiler.Test` failed count is exactly 0; all four owned named tests are recorded as passed; and every failure outside `QuickFiler.Test`, if any, is listed by fully qualified name and attributed to issue #594 in the artifact rather than treated as a gate failure. A failure inside `QuickFiler.Test` fails this task and restarts the loop. +- [x] [P3-T7] Capture post-change numeric coverage with `pwsh -NoProfile -File .\scripts\vscode\Invoke-MSTestWithCoverage.ps1 -SearchRoot . -CoverageOutput coverage\remediation.cobertura.xml` from the worktree root, launched per the Phase 3 long-running command mechanic (the run takes roughly 20 minutes), then read the root `line-rate` and `branch-rate` attributes, the `QuickFiler` package `line-rate`, and the `line-rate` of every Cobertura class whose `filename` begins `QuickFiler\Controllers\QfcItemController`. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording all four figures as numeric percentages to two decimal places. The raw Cobertura XML stays in the gitignored `coverage\` directory and is not copied into the evidence tree (P3-T9 copies it to the gitignored `artifacts/csharp/` producer path). Bounded re-run authorization: `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md` records this exact script failing once under machine load with seven 60,000 ms `PumpTimeoutMs` expiries — the out-of-scope #592 defect — and the script throws before post-processing, so that failure mode produces no comparable XML at all. If the coverage run fails on a load-induced `PumpTimeoutMs` expiry in `QuickFiler.Test`, re-run this task alone, up to two re-runs, recording every attempt in the artifact with its timestamp, its failure signature, and the machine-load state at launch, without restarting the loop from P3-T1. Any failure that is not a load-induced `PumpTimeoutMs` expiry still restarts the loop from P3-T1. Acceptance: the script reported exactly 9 discovered test assemblies and no coverage field is empty or contains the token `UNVERIFIED`; the vstest exit code is recorded verbatim; every attempt (first run plus any authorized re-runs, maximum three attempts total) is recorded in the artifact; and a sibling-assembly test failure during the coverage run is listed by fully qualified name and attributed to issue #594 rather than failing this task, provided the four coverage figures were produced. +- [x] [P3-T8] Verify the coverage delta against the baseline. Write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage-delta.2026-08-23T20-57.md` with `Timestamp:` and a table carrying, for each of the four measured figures, the baseline value from `docs/features/active/winformspumphost-suite-determinism-511/evidence/baseline/coverage.2026-08-21T18-10.md`, the post-change value from P3-T7, and the signed delta; plus a changed-line coverage row recording that this cycle's diff against the evidence-producing source consists of comment lines only, so zero executable lines changed and changed-line coverage is vacuously non-regressed. Acceptance: the `QuickFiler` package `line-rate` delta is greater than or equal to 0 (strict, no tolerance); every `QfcItemController` class `line-rate` delta is greater than or equal to -0.50 percentage points — `dotnet-coverage` denominators are not bit-stable between runs and this cycle's diff is test-file comments only, so a small negative per-class delta is measurement noise and is recorded as such in the row with both raw rates cited — and every cell in the table holds a numeric value rather than a placeholder. +- [x] [P3-T9] Produce the downstream review-gate coverage artifact: copy the post-processed Cobertura XML `coverage\remediation.cobertura.xml` from P3-T7 to `artifacts/csharp/coverage.xml` at the worktree root, creating the `artifacts/csharp/` directory if absent, then read the copied file's root `line-rate` and `branch-rate` attributes and write `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-coverage-artifact.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording both figures as numeric percentages to two decimal places. `artifacts/csharp/` is a tool-output producer path read by the downstream feature-review coverage hook, not an evidence location, so the evidence-location invariant is unaffected; the numeric record lives under `evidence/qa-gates/`, and `artifacts/` is excluded by the repository-root `.gitignore`, so the copied XML does not disturb the P4-T9 clean-tree gate. Acceptance: `artifacts/csharp/coverage.xml` exists and is byte-identical to `coverage\remediation.cobertura.xml` (same SHA-256); its root `line-rate` expressed as a percentage is greater than or equal to 85 and its root `branch-rate` expressed as a percentage is greater than or equal to 75 (baseline 85.55% line, 79.03% branch); and the evidence artifact records both figures numerically. +- [x] [P3-T10] Re-audit the 500-line cap after the final formatting pass, because CSharpier can add lines. Count the lines returned by `Get-Content -LiteralPath` for each of `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part2.cs`, `QuickFiler.Test/Controllers/QfcItemController.ViewerSetupTests.cs`, and `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, and record all three in `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-file-size-audit.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:`. Acceptance: each of the three recorded counts is less than 500. +- [x] [P3-T11] Record the clean-pass attestation in `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/remediation-clean-pass.2026-08-23T20-57.md` with `Timestamp:` and, for each of P3-T1 through P3-T10, the command run and its exit code, plus the number of loop restarts performed and the reason for each, and any authorized P3-T7 re-run attempts with their reasons. Acceptance: the artifact records that P3-T1 through P3-T10 all completed without failure and without changing files in a single consecutive pass; if any earlier step changed a file or failed, the loop was restarted from P3-T1 and only the final consecutive pass is recorded as the clean one (an authorized P3-T7 re-run is recorded as an attempt within the pass, not as a loop restart). + +### Phase 4 — Acceptance Criteria Check-Off, Handoff, and Evidence Hygiene + +One AC checkbox changes state per task, each with its own evidence pointer, per the acceptance-criteria-tracking skill. + +- [x] [P4-T1] Check off revised spec AC 3 in `docs/features/active/winformspumphost-suite-determinism-511/spec.md`, citing the three distilled records `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/determinism-ten-runs.2026-08-21T18-10.md`, `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-tests-ten-runs.2026-08-21T18-10.md`, and `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/regression-tests-ten-runs.2026-08-21T18-10.md`, the raw-artifact disposition record `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md`, the load bracket artifacts `load-generator-start.2026-08-21T18-10.md` and `load-generator-stop.2026-08-21T18-10.md` in `evidence/regression-testing/`, and the narrowing rationale from P2-T4. The raw ten-TRX directory `evidence/regression-testing/p4-t2/` is named in prose only: it no longer exists — its contents were deleted at maintainer instruction on 2026-08-23 per the disposition record — and it must not be cited as, or asserted to be, an existing path. Acceptance: exactly one AC checkbox changes state, every cited artifact path resolves to an existing file, and the criterion checked is the P2-T2 revised text (its line contains the literal `tracked as issue #594` elsewhere in the item). +- [x] [P4-T2] Check off revised spec AC 6, citing `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/named-regression-tests.2026-08-21T18-10.md` (the test passes) and `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md` (the measured inherited state the revised criterion asserts). Acceptance: exactly one AC checkbox changes state and both cited artifact paths resolve to existing files. +- [x] [P4-T3] Check off spec AC 8 (all 21 pump-host call sites pass in the final run: 13 self-tests plus 8 consumer tests), citing `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/pumphost-selftests.2026-08-21T18-10.md`, `docs/features/active/winformspumphost-suite-determinism-511/evidence/regression-testing/consumer-tests.2026-08-21T18-10.md`, and the P3-T6 remediation suite run. Acceptance: exactly one AC checkbox changes state, the cited artifacts record 13 passed self-tests and at least 8 passed consumer tests with zero failures, and the P3-T6 artifact records a `QuickFiler.Test` failed count of exactly 0. +- [x] [P4-T4] Check off spec AC 13 (the five-step toolchain completes green in a single final pass with coverage captured and no `QuickFiler` regression), citing the P3-T11 clean-pass attestation, the P3-T7 coverage figures, and the P3-T8 delta table. Acceptance: exactly one AC checkbox changes state and the cited delta artifact records a `QuickFiler` package `line-rate` delta greater than or equal to 0. +- [x] [P4-T5] Update `docs/features/active/winformspumphost-suite-determinism-511/spec.md`, section `## Rollout & Follow-up`: record that the genuine defect behind the #511 report — the load-induced 60,000 ms `PumpTimeoutMs` expiry cascade under machine load — is out of scope for this branch and is tracked as issue #592, which supersedes #511 and #571 (both CLOSED as NOT_PLANNED); record that the three pre-existing `UtilitiesCS.Test` flakes blocking any suite-wide zero gate are tracked as issue #594; and update required follow-up item 1 to name issue #592 as the filed follow-up number in place of the unfilled instruction to record one. No sentence added may state that this branch repairs either superseded issue. Acceptance, measured with `Select-String -SimpleMatch` against `spec.md` only: within the `## Rollout & Follow-up` section the literal `#592` appears at least 2 times and the literal `#594` appears at least 1 time, and the single-line literal `File this as its own issue and record the` matches exactly 0 lines. (That literal matches exactly 1 line today, at the head of the wrapped instruction sentence at spec.md line 723; the full sentence is wrapped across lines 723-724 — `...record the` / `number here.` — so a full-sentence `Select-String -SimpleMatch` returns 0 lines both before and after the edit and could not fail. The shorter single-line literal is asserted instead precisely because it can fail.) +- [x] [P4-T6] Check off spec AC 14 (`## Rollout & Follow-up` records the out-of-scope half with its re-attribution and names the filed follow-up issue number), citing the P4-T5 spec edit and the P2-T6 discharge artifact, with #592 as the named follow-up issue per remediation-inputs Finding E. Acceptance: exactly one AC checkbox changes state, the spec's `## Rollout & Follow-up` section names #592, and the P2-T6 artifact exists. +- [x] [P4-T7] Write the acceptance-criteria status summary to `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/ac-status-summary.2026-08-23T20-57.md` with `Timestamp:` and one row per criterion carrying the criterion number, its verbatim first line, its state, its evidence artifact path, and — for AC 3 and AC 6 — a note that the criterion text was revised this cycle per Findings E and F with the falsified original wording summarized. Acceptance: the summary has exactly 14 rows, every row names an artifact path that resolves to an existing file, every row's state reads satisfied, and the row states agree with the checkbox states in `spec.md` (14 of 14 checked). +- [x] [P4-T8] Write the remediation review-handoff index to `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/remediation-review-handoff.2026-08-23T20-57.md` with `Timestamp:`, listing: every Markdown evidence artifact path produced by this plan's Phases 0 through 4 — the index lists Markdown evidence only; the raw P3-T6 TRX under `docs/features/active/winformspumphost-suite-determinism-511/evidence/qa-gates/r1-p3-t6/` is named on its own separate line marked `deleted by P4-T10` and that line is exempt from the resolves-to-existing condition below; the branch name and the merge-base sha from P0-T6; the seven remediation exit criteria from remediation-inputs Part 5 with the task that discharged each (exit criterion 7 — the `## Scope & Non-Goals` correction — is discharged by P2-T7 and P2-T8); the residual conditions recorded rather than repaired (the #592 pump-timeout cascade, the #594 sibling flakes, the #597 analyzer skew, residual CPU-contention sensitivity, and the `InvokeBeginInvoke` production asymmetry); the exit-criterion-7 spec-scope re-check — run `Select-String -SimpleMatch` against `spec.md` for each of the four falsified-premise literals `Deterministic creation of the`, `#571 in full`, `removing the handle race removes`, and `as requiring its own issue against`, and record the four counts in the index; the requirements-input carve-out record — `remediation-inputs.2026-08-23T20-57.md` carries three matches of the scan regex at its lines 227, 248, and 264, all inside negations that deny the repair claim; it is exempt by design from the file scan per the plan preamble, and GitHub parses closing keywords only in commit messages and pull-request bodies, never in file contents; and the result of the closing-keyword file scan. The file scan: run `Select-String` with the case-insensitive regex `(fix|clos|resolv)[a-z]* #(511|571)` against (a) `docs/features/active/winformspumphost-suite-determinism-511/spec.md`, (b) this plan file `docs/features/active/winformspumphost-suite-determinism-511/remediation-plan.2026-08-23T20-57.md`, and (c) each of the three touched `.cs` files — five files in total. The git-log leg is deliberately not run here: this task runs before the P4-T9 and P4-T10 commits, so `git log --format=%B $MergeBase..HEAD` could not yet see the messages this plan produces and the leg could not fail; it runs post-commit in P4-T9 and is repeated in P4-T10. Acceptance: the index exists, every listed Markdown artifact path resolves to an existing file, the P3-T6 TRX line is present and marked `deleted by P4-T10`, all five residual conditions are named, the carve-out record is present, the exit-criterion-7 re-check records exactly 0 matching lines in `spec.md` for each of the four falsified-premise literals, and the file scan records exactly 0 matches in each of the five scanned files. No pull-request creation and no CI monitoring is performed by this plan; both are handled outside it, with the pull request targeting `main` per orchestrator Decision 1. +- [x] [P4-T9] Commit every change produced by this cycle on the current branch — the two comment-corrected `.cs` files, `spec.md`, `plan.2026-08-21T18-10.md`, this remediation plan, `docs/features/active/winformspumphost-suite-determinism-511/evidence/.gitignore` if the P0-T9 append modified it, `remediation-inputs.2026-08-23T20-57.md`, `decision-record.2026-08-23T20-40.md` if not yet committed, every Markdown evidence artifact this plan wrote, and any modified or untracked file under `.claude/agent-memory/` (permitted by prohibition 6 and excluded from the scope-lock filter, which admits only `.cs`, `.csproj`, `.props`, `.targets`, and `.config` paths) — in a single commit whose message names issues #511 and #571 as context, names #592 as the superseding issue, and contains no GitHub closing keyword immediately before any issue reference. Then confirm the tree state and run the post-commit closing-keyword git-log scan (the leg deliberately moved out of P4-T8, which runs pre-commit). Acceptance: `git status --porcelain` produces zero output lines; `git diff --name-only $MergeBase` still satisfies the P1-T4 scope-lock conditions (exactly three code files, three prohibited counts each 0); and `Select-String` with the case-insensitive regex `(fix|clos|resolv)[a-z]* #(511|571)` against the full output of `git log --format=%B $MergeBase..HEAD` — every commit message on the branch, now including this task's commit; the pre-existing messages were verified to carry 0 matches — returns exactly 0 matches. +- [x] [P4-T10] Final task (orchestrator Decision 3, step 3): delete every raw vstest artifact under the evidence tree, then commit the deletion record. The 2026-08-23 maintainer deletion recorded in `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-vstest-artifact-disposition.2026-08-23T21-40.md` already removed the 56 pre-existing TRX and 42 `.coverage` files and pruned 188 empty scratch directories; the raw artifacts this task deletes are those newly produced by the Phase 3 loop, principally the P3-T6 TRX under `evidence/qa-gates/r1-p3-t6/`. Enumerate and delete every file matching `*.trx` and every file matching `*.coverage` under `docs/features/active/winformspumphost-suite-determinism-511/evidence/` recursively (all are untracked or ignored; the distilled Markdown records are the evidence of record per remediation-inputs Part 1 row 8), remove the now-empty per-run scratch directories, write `docs/features/active/winformspumphost-suite-determinism-511/evidence/other/raw-artifact-deletion.2026-08-23T20-57.md` with `Timestamp:`, `Command:`, `EXIT_CODE:`, and `Output Summary:` recording the deleted-file counts by extension, and commit that single artifact by explicit pathspec with a message that names no issue with a closing keyword. Then repeat the closing-keyword git-log scan after this commit. Acceptance: a recursive count of files matching `*.trx` under `docs/features/active/winformspumphost-suite-determinism-511/evidence/` is exactly 0; a recursive count of files matching `*.coverage` under the same tree is exactly 0; the deletion-record artifact exists with all four fields; `git status --porcelain` produces zero output lines after the commit; if agent-memory files were written after the P4-T9 commit, include them in this commit by explicit pathspec; and `Select-String` with the case-insensitive regex `(fix|clos|resolv)[a-z]* #(511|571)` against the full output of `git log --format=%B $MergeBase..HEAD`, now including this task's commit, returns exactly 0 matches. + +--- + +## Residual Conditions Recorded, Not Claimed Repaired + +1. **The genuine defect behind the #511 report** — the load-induced 60,000 ms `PumpTimeoutMs` expiry cascade — is tracked as issue #592 and is out of scope for this branch. Findings A, B, and C are accepted: the fixture-hardening statement forces a handle that construction already created, and this branch's value is the hardening, the regression tests pinning the inherited state, and the mechanism finding. +2. **The three pre-existing `UtilitiesCS.Test` flakes** blocking any suite-wide zero gate are tracked as issue #594; every suite gate in this plan is scoped to the `QuickFiler.Test` assembly accordingly. +3. **The repository-wide analyzer version skew** is tracked as issue #597; this plan back-fills nothing new and edits no project file. +4. **Residual CPU-contention sensitivity** of the pump-hosted suite is a stated trade, unchanged by this cycle. +5. **The `InvokeBeginInvoke` production asymmetry** remains a follow-up recorded in the spec's `## Rollout & Follow-up`, not addressed here. diff --git a/docs/features/active/winformspumphost-suite-determinism-511/research/winformspumphost-suite-determinism.2026-08-21T18-20.md b/docs/features/active/winformspumphost-suite-determinism-511/research/winformspumphost-suite-determinism.2026-08-21T18-20.md index 3025977fe..282063b60 100644 --- a/docs/features/active/winformspumphost-suite-determinism-511/research/winformspumphost-suite-determinism.2026-08-21T18-20.md +++ b/docs/features/active/winformspumphost-suite-determinism-511/research/winformspumphost-suite-determinism.2026-08-21T18-20.md @@ -8,7 +8,7 @@ Feature: `winformspumphost-suite-determinism-511` (epic child 1 of 4, Scope of this document: research only. No source file, project file, configuration file, or `.claude/**` file was modified. No build and no test run was executed. Every claim below is grounded in a file read or a grep against the worktree at -`C:\Users\DanMoisan\repos\TaskMaster\.claude\worktrees\agent-a5bd77000d205e542`, or is explicitly +`\.claude\worktrees\agent-a5bd77000d205e542`, or is explicitly labelled as documented framework behaviour or as an open question. Paths in this document are repository-relative for readability. The absolute root for every one of diff --git a/docs/features/active/winformspumphost-suite-determinism-511/spec.md b/docs/features/active/winformspumphost-suite-determinism-511/spec.md index 031e6389d..bf8e727cf 100644 --- a/docs/features/active/winformspumphost-suite-determinism-511/spec.md +++ b/docs/features/active/winformspumphost-suite-determinism-511/spec.md @@ -91,11 +91,19 @@ ### In scope -- Deterministic creation of the `ItemViewer` window handle on the pump thread inside the shared - pump harness, so that `Control.Invoke` has an existing handle before any act. -- #571 in full: both named intermittent failures. -- #511's **load-flakiness half**: removing the handle race removes one whole class of the load- - induced failures reported in #511. +- Making the `ItemViewer` window handle state explicit on the pump thread inside the shared pump + harness. The handle already exists when construction returns (measured 2026-08-22, remediation + Finding A); the harness read makes that inherited state explicit and independent of a + third-party side effect, rather than creating a handle that would otherwise be absent. (Revised + 2026-08-23 per remediation-inputs Part 6.) +- #571 is not delivered by this feature. #571 is CLOSED as NOT_PLANNED, superseded by #592; the + real cause of both named intermittent failures is the load-induced 60,000 ms `PumpTimeoutMs` + expiry cascade, tracked as #592, which this feature does not address. (Revised 2026-08-23 per + remediation-inputs Part 6.) +- #511's load-flakiness half is not addressed here. There is no handle race (remediation Findings + A and B falsified that premise); the load-induced failures reported in #511 are the same + 60,000 ms `PumpTimeoutMs` expiry tracked as issue #592. (Revised 2026-08-23 per + remediation-inputs Part 6.) - Regression tests for the new fixture invariant, placed in `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`. - An empirical pre-fix and post-fix determinism record captured as evidence. @@ -105,9 +113,11 @@ - **#511's visible-window half is out of scope and is re-attributed.** The evidence does not support the causal claim in #511's Actual Behavior bullet that the visible window is produced by `WinFormsPumpHost`. See `## Root Cause Analysis`. This half is recorded under - `## Rollout & Follow-up` as requiring its own issue against + `## Rollout & Follow-up` and is tracked as issue #592, which now exists and supersedes #511 and + #571 (both CLOSED as NOT_PLANNED); no new issue remains to be filed for it, including against `UtilitiesCS.Test/Threading/ProgressViewer_Tests.cs`. It is deliberately **not** an acceptance - criterion of this feature, so that the feature audit does not score it as unmet. + criterion of this feature, so that the feature audit does not score it as unmet. (Revised + 2026-08-23 per remediation-inputs Part 6.) - **#511's literal proposed remedy is rejected**: replacing the real message pump with an injectable synchronization-context or dispatcher seam. Rationale in `## Root Cause Analysis` and `## Proposed Fix`. @@ -595,61 +605,72 @@ this feature's acceptance. ## Acceptance Criteria -- [ ] `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` +- [x] `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` (`QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs:175`) passes in every one of ten consecutive full nine-assembly runs, with the ten TRX results stored under `evidence/regression-testing/`. -- [ ] `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` +- [x] `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` (`QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs:131`) passes in every one of those same ten consecutive full nine-assembly runs. -- [ ] The ten consecutive full nine-assembly runs are executed under induced CPU load and are all - green, using `vstest.console.exe /EnableCodeCoverage /InIsolation +- [x] The ten consecutive full nine-assembly runs are executed under induced CPU load using + `vstest.console.exe` with `/EnableCodeCoverage /InIsolation /TestCaseFilter:"TestCategory!=LiveOutlook"`, with the evidence stored under - `evidence/regression-testing/`. (Ten under induced load is chosen over #571's "at least 5" - because it is the epic's stated leading indicator, it targets #511's load-induced cascade - directly, and it satisfies #571's threshold a fortiori.) -- [ ] An empirical pre-fix baseline artifact exists under `evidence/regression-testing/` recording, + `evidence/regression-testing/`, and record zero failures in the `QuickFiler.Test` assembly + — the assembly containing every class this child owns — with both named end-to-end tests + and both named regression tests recorded as passed in all ten runs. Suite-wide, nine of the + ten runs are green; run 5 records a single failure in the sibling-owned `UtilitiesCS.Test` + assembly (`GetEmailDataInViewAsync_SeparatesTableSnapshotFromDataFrameTransform`), which + this child's three-file `QuickFiler.Test/` diff cannot reach and which is + tracked as issue #594. (Revised 2026-08-23 per remediation Finding F and the ratified + owned-class scoping precedent.) +- [x] An empirical pre-fix baseline artifact exists under `evidence/regression-testing/` recording, per run across ten runs, the pass/fail outcome of both named tests and the observed harness viewer `IsHandleCreated` value, establishing the pre-fix failure behaviour by execution rather than by static reading. -- [ ] `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` exists in +- [x] `BuildPumpHarness_ForcesTheViewerWindowHandleOnThePumpThread` exists in `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, asserts the harness viewer's `IsHandleCreated` is `true` before the act, and passes. -- [ ] `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` exists in - `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, asserts both - WebView2 children remain handle-less, and passes. -- [ ] `git diff` reports zero hunks in both +- [x] `BuildPumpHarness_DoesNotCreateTheWebViewChildHandles` exists in + `QuickFiler.Test/Controllers/QfcItemController.InitializationTests.Part3.cs`, asserts the + measured inherited state — both WebView2 children are already handle-created by + `ItemViewer` construction via the Designer-emitted `ISupportInitialize.EndInit()` calls, so + the harness inherits the handles rather than creating them — and passes. (Revised + 2026-08-23 per remediation Finding E: the original wording asserted an unmeasured + world-state that the measurement in + `evidence/regression-testing/webview-child-handle-measurement.2026-08-21T18-10.md` + proved false.) +- [x] `git diff` reports zero hunks in both `QuickFiler/Controllers/QfcItemController.Initialization.cs` and `QuickFiler/Controllers/QfcItemController.ViewerSetup.cs`, and file inspection confirms all seven `#230` de-exemption comment blocks in `Initialization.cs` (lines 135, 164, 196, 259, 291, 403, 447), the `#230` de-exemption block at `ViewerSetup.cs:254`, and the retained `[ExcludeFromCodeCoverage]` block at `ViewerSetup.cs:30-41` are present and unmodified. -- [ ] All 21 pump-host call sites pass in the final run: the 13 self-tests in +- [x] All 21 pump-host call sites pass in the final run: the 13 self-tests in `QuickFiler.Test/TestSupport/WinFormsPumpHostTests.cs` and the 8 consumer tests (5 in `QfcItemController.InitializationTests.Part3.cs`, 2 in `QfcItemController.SeamFactoryTests.cs`, 1 in `QfcItemController.ViewerSetupTests.cs`). -- [ ] `git diff --name-only` against the merge base lists exactly three code files, all under +- [x] `git diff --name-only` against the merge base lists exactly three code files, all under `QuickFiler.Test/` (`Controllers/QfcItemController.InitializationTests.Part2.cs`, `Controllers/QfcItemController.ViewerSetupTests.cs`, `Controllers/QfcItemController.InitializationTests.Part3.cs`), and lists no file under `QuickFiler/`, no `*.csproj`, and no path under `.claude/` other than `.claude/agent-memory/`, which epic hard constraint 1 lists as safe to edit and which is agent bookkeeping rather than part of the fix. -- [ ] `QfcItemController_SeamFactoryTests` and `QfcItemController_InitializationTests` both pass in +- [x] `QfcItemController_SeamFactoryTests` and `QfcItemController_InitializationTests` both pass in the same run, and file inspection confirms `UiThreadDispatcherGate` (`QfcItemController.InitializationTests.Part2.cs:51`) and `SwapUiThreadDispatcher` (`:139`) retain their acquire-and-release structure. -- [ ] Every changed file is under 500 lines after the change: +- [x] Every changed file is under 500 lines after the change: `QfcItemController.InitializationTests.Part2.cs` (was 409), `QfcItemController.ViewerSetupTests.cs` (was 467), and `QfcItemController.InitializationTests.Part3.cs` (was 290). -- [ ] `git diff` introduces no occurrence of `Thread.Sleep`, `Task.Delay`, `SpinWait`, a retry loop, +- [x] `git diff` introduces no occurrence of `Thread.Sleep`, `Task.Delay`, `SpinWait`, a retry loop, or a raised timeout constant, and every existing timeout constant retains its current value (`PumpTimeoutMs = 60000`, `TimeoutMs = 30000`). -- [ ] The five-step toolchain in `## Test Strategy` completes green in a single final pass, coverage +- [x] The five-step toolchain in `## Test Strategy` completes green in a single final pass, coverage is captured under `evidence/qa-gates/`, and measured `QuickFiler` line coverage is greater than or equal to the pre-fix baseline recorded under `evidence/baseline/`. -- [ ] `## Rollout & Follow-up` records #511's visible-window half as out of scope with its +- [x] `## Rollout & Follow-up` records #511's visible-window half as out of scope with its re-attribution to `UtilitiesCS.Test/Threading/ProgressViewer_Tests.cs`, and names the filed follow-up issue number for it, so the feature audit does not score that half as an unmet criterion of this feature. @@ -720,8 +741,10 @@ regress runtime behaviour. There is no feature flag and none is warranted. on a `ProgressViewer : Form` (`UtilitiesCS/Threading/ProgressViewer.cs:16`) inside an `[STATestClass]`. A one-line remedy exists — the file already has a headless construction helper `CreateHeadlessViewer` at `ProgressViewer_Tests.cs:33-34` — but it is in `UtilitiesCS.Test`, - outside this child's file set and outside this epic. **File this as its own issue and record the - number here.** Note two constraints on how it is filed: the re-attribution is a code reading, not + outside this child's file set and outside this epic. **The follow-up issue is filed as issue + #592**, which supersedes #511 and #571 (both CLOSED as NOT_PLANNED); no new issue remains to be + filed for this half. Note two constraints on how it was filed: the re-attribution is a code + reading, not a reproduced observation, so someone should watch a full-suite run and confirm the window is the `ProgressViewer` before the issue asserts causation; and `epic.md` forbids any child of this epic from writing under `docs/features/potential/**`, so the follow-up is filed directly as a GitHub @@ -740,6 +763,22 @@ regress runtime behaviour. There is no feature flag and none is warranted. MSTest version and its interaction with the gate were not verified. File as its own issue if the ten-run determinism requirement exposes it. +### Out-of-scope residuals, re-attributed (recorded 2026-08-23) + +- **The genuine defect behind the #511 report is out of scope for this branch.** The load-induced + 60,000 ms `PumpTimeoutMs` expiry cascade under machine load is the mechanism actually observed; + there is no handle race, because remediation Findings A and B falsified that premise. It is + tracked as issue **#592**, which supersedes both #511 and #571 (both CLOSED as NOT_PLANNED). + This branch makes no repair claim for either superseded issue. Its contribution is the fixture + hardening, the regression tests pinning the measured inherited handle state, and the mechanism + finding. +- **The three pre-existing `UtilitiesCS.Test` flakes** that block any suite-wide absolute-zero + gate are tracked as issue **#594**. Every suite gate in this feature is scoped to the + `QuickFiler.Test` assembly accordingly, and a sibling-assembly failure is recorded by fully + qualified name and attributed to #594 rather than treated as a gate failure. +- **The repository-wide analyzer version skew** is tracked as issue **#597**. This branch + back-fills nothing new and edits no project file. + ### Links - Primary issue #511: https://github.com/drmoisan/TaskMaster/issues/511