diff --git a/docs/features/potential/promoted/2026-08-15-ci-nuget-cache-fallback-masks-stale-package-refs.md b/docs/features/potential/promoted/2026-08-15-ci-nuget-cache-fallback-masks-stale-package-refs.md new file mode 100644 index 00000000..eccd0aef --- /dev/null +++ b/docs/features/potential/promoted/2026-08-15-ci-nuget-cache-fallback-masks-stale-package-refs.md @@ -0,0 +1,125 @@ +# ci-nuget-cache-fallback-masks-stale-package-refs (Issue #569) + +- Date captured: 2026-08-15 +- Author: Dan Moisan +- Status: Promoted -> docs/features/active/ci-nuget-cache-fallback-masks-stale-package-refs/ (Issue #569) + +> Automation note: Keep the section headings below unchanged; the promotion tooling maps each of them into the GitHub bug issue template. + +- Issue: #569 +- Issue URL: https://github.com/drmoisan/TaskMaster/issues/569 +- Last Updated: 2026-08-15 +## Summary + +The three build and test workflows restore the `packages` directory from an +`actions/cache` entry whose `restore-keys` fallback is a bare +`nuget-${{ runner.os }}-` prefix. On a cache miss the fallback supplies package +folders from an unrelated earlier commit, so a project referencing a package +version that `packages.config` no longer declares still compiles. Two real +defects on PR #568 were invisible to CI for exactly this reason and only +appeared on a local cold build. + +## Environment + +- OS/version: `windows-latest` GitHub-hosted runner +- Python version: n/a (GitHub Actions YAML) +- Command/flags used: `nuget restore TaskMaster.sln`, then the workflow's msbuild or vstest step +- Data source or fixture: `actions/cache@v4` entry keyed on `**/packages.config` + +## Steps to Reproduce + +1. On a branch, change a package version in every `packages.config` but leave a + stale `..\packages\.\` path in a `.csproj` or in test code. +2. Push. The cache key `nuget-${{ runner.os }}-${{ hashFiles('**/packages.config') }}` + misses because the config files changed. +3. The `restore-keys: nuget-${{ runner.os }}-` fallback restores a prior cache + that still contains `.`. +4. `nuget restore` installs the new versions alongside the stale restored ones. +5. The build and the tests pass, despite referencing a version no longer + declared anywhere in the repository. + +## Expected Behavior + +CI reflects what a clean checkout produces. A project or test that references a +package version absent from `packages.config` fails the build, because that is +what any developer with a cold `packages` directory experiences. + +## Actual Behavior + +CI run 31890892701 on `chore/update-nuget` head `8f30fd53` reported +`build-analyzers`, `build-nullable`, and `mstest-coverage` as **success**. The +same commit built locally against a correctly-restored `packages` directory +produced: + +- 10 `CSC : error CS0006: Metadata file '..\packages\Meziantou.Analyzer.3.0.138\...' + could not be found` errors (and the matching `Roslynator.Analyzers.4.15.0` + errors) across 16 projects, because the upgrade advanced `packages.config` and + the analyzer ``/`` lines to 3.0.156 / 4.16.0 but left the + `` item paths behind. +- 3 test failures in `UtilitiesCS.Test.Extensions.AsyncSerialization_Tests` + (`InvalidOperationException: The Microsoft.Graph.xml fixture could not be + located from the test assembly path`), because the fixture hard-coded + `packages\Microsoft.Graph.6.2.0` while the upgrade moved to 6.5.0. + +Only the `format-check` job failed, and it is the one job with no `packages` +cache dependency. + +## Logs / Screenshots + +- [x] Attached minimal logs or screenshot +- Snippet: CI run 31890892701 job list showing three green build/test jobs on the + commit that fails a cold local build; local msbuild CS0006 output and the TRX + failure messages quoted above. Both defects were fixed in commit `46ca9210`. + +## Impact / Severity + +- [ ] Blocker +- [x] High +- [ ] Medium +- [ ] Low + +High because it is a gate-fidelity defect, not an ordinary bug: it caused three +protected checks to report green on a commit that does not build from a clean +checkout. Any future package-path drift is silently admitted to `main` the same +way. It also affects the correctness signal of every prior green run whose cache +was populated from an older commit. + +## Suspected Cause / Notes + +- Affected workflows, all with the same cache block: + - `.github/workflows/_build-analyzers.yml` (lines 35-45) + - `.github/workflows/_build-nullable.yml` + - `.github/workflows/_mstest-coverage.yml` +- The exact-match key is correct; the `restore-keys` prefix fallback is what + admits foreign content. For a `packages.config` restore the cache is only + sound as an exact match, because `nuget restore` adds missing packages but + never removes packages the current configuration does not declare. +- Two independent remedies exist and are complementary: + 1. Drop the `restore-keys` fallback so a `packages.config` change forces a + cold restore. Costs restore time on dependency changes only. + 2. Add a validation step asserting that every `..\packages\.\` + path referenced by a `.csproj` resolves to a version declared in that + project's `packages.config`. This catches drift regardless of cache state + and is the stronger of the two. +- Note that remedy 2 must tolerate genuinely conditional imports: for example + `QuickFiler.Test.csproj` imports `..\packages\altcover.8.6.45\...` guarded by + `Condition="Exists(...)"` and is a pre-existing no-op, not a defect. +- Related repository rule: `.claude/rules/ci-workflows.md` already governs + workflow-authoring hazards that local toolchain stages cannot see. This finding + is the same class of problem and likely belongs alongside it once fixed. + +## Proposed Fix / Validation Ideas + +- [ ] Unit coverage areas: if remedy 2 is implemented as a script, it needs + Pester coverage per `.claude/rules/general-unit-test.md`, including a + positive case, a stale-reference case, and a conditional-import case. +- [ ] Integration scenario to retest: reproduce the original failure by pushing + a branch with a deliberately stale `` path and confirming + CI now fails. +- [ ] Manual verification notes: confirm a clean-cache run still completes within + the workflows' 30-minute timeouts. + +## Next Step + +- [x] Promote to GitHub issue (bug-report template) +- [ ] Move to active fix folder / branch diff --git a/docs/features/potential/promoted/2026-08-15-qfc-item-controller-init-tests-flaky-window-handle.md b/docs/features/potential/promoted/2026-08-15-qfc-item-controller-init-tests-flaky-window-handle.md new file mode 100644 index 00000000..1d7c5cde --- /dev/null +++ b/docs/features/potential/promoted/2026-08-15-qfc-item-controller-init-tests-flaky-window-handle.md @@ -0,0 +1,117 @@ +# qfc-item-controller-init-tests-flaky-window-handle (Issue #571) + +- Date captured: 2026-08-15 +- Author: Dan Moisan +- Status: Promoted -> docs/features/active/qfc-item-controller-init-tests-flaky-window-handle/ (Issue #571) + +> Automation note: Keep the section headings below unchanged; the promotion tooling maps each of them into the GitHub bug issue template. + +- Issue: #571 +- Issue URL: https://github.com/drmoisan/TaskMaster/issues/571 +- Last Updated: 2026-08-15 +## Summary + +Two tests in `QuickFiler.Controllers.Tests.QfcItemController_InitializationTests` +fail intermittently during a full-suite run with +`InvalidOperationException: Invoke or BeginInvoke cannot be called on a control +until the window handle has been created`, but pass every time when the class is +run in isolation. The tests exercise a real WinForms `Control.Invoke` path with +no seam, so they depend on whether the control's window handle happens to exist +when the test reaches it. + +## Environment + +- OS/version: Windows 11 Pro 10.0.26200 +- Python version: n/a (C# / .NET Framework 4.8.1, MSTest) +- Command/flags used: `vstest.console.exe <9 test assemblies> /EnableCodeCoverage /InIsolation /Logger:trx /TestCaseFilter:"TestCategory!=LiveOutlook"` +- Data source or fixture: none; the failure is in test-host state, not data + +## Steps to Reproduce + +1. Build the solution in Debug. +2. Run the full suite across all nine `*.Test.dll` assemblies with the command + above. +3. Repeat. The two tests below fail on some runs and pass on others. + +Observed on 2026-08-15: run 1 passed both tests, run 2 failed both, run 3 (full +suite) passed both. Running only +`/TestCaseFilter:"FullyQualifiedName~QfcItemController_InitializationTests"` +passed 9 of 9 on every attempt. + +## Expected Behavior + +Per `.claude/rules/general-unit-test.md`, tests are deterministic: identical +inputs and environment produce identical results, and the suite does not depend +on ordering or on ambient UI state. + +## Actual Behavior + +Both of the following fail non-deterministically: + +- `InitializeNineArgOverload_ThroughThePumpHost_SavesParametersAndDelegates` +- `InitializeBool_ThroughThePumpHost_CompletesAndInitializesState` + +``` +System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a +control until the window handle has been created. + at System.Windows.Forms.Control.MarshaledInvoke(...) + at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args) + at QuickFiler.ItemViewer.QuickFiler.IItemViewer.Invoke(Delegate method) + at QuickFiler.Controllers.QfcItemController.InvokeBeginInvoke(Boolean async, Action action) + in QuickFiler\Controllers\QfcItemController.FocusAndTheme.cs:line 256 + at QuickFiler.Controllers.QfcItemController.ToggleTips(Boolean async, ToggleState desiredState) + in QuickFiler\Controllers\QfcItemController.FocusAndTheme.cs:line 204 +``` + +## Logs / Screenshots + +- [x] Attached minimal logs or screenshot +- Snippet: stack trace above, extracted from the TRX of the failing run on + 2026-08-15. + +## Impact / Severity + +- [ ] Blocker +- [ ] High +- [x] Medium +- [ ] Low + +The failure is intermittent and does not indicate a production defect, but a +flaky test in a protected gate is corrosive: it trains reviewers to re-run +rather than investigate, and it can fail an otherwise-green CI run at random. + +## Suspected Cause / Notes + +- `QfcItemController.InvokeBeginInvoke` at + `QuickFiler/Controllers/QfcItemController.FocusAndTheme.cs:256` calls + `IItemViewer.Invoke` directly. `Control.Invoke` throws unless the control's + native window handle already exists. +- The tests reach this through `ToggleTips` at + `QuickFiler/Controllers/QfcItemController.FocusAndTheme.cs:204`. +- Handle creation depends on ambient WinForms state in the shared test host, + which differs between a full-suite run and a single-class run. This is exactly + the mutable-global-state dependency the unit-test policy prohibits. +- A sibling test in the same file already documents this hazard and works around + it with a headless `ProgressTrackerPane` built via + `FormatterServices.GetUninitializedObject` (see the comment block in + `UtilitiesCS.Test/Extensions/AsyncSerialization_Tests.cs`), which indicates the + repository already has a pattern for avoiding a live message pump in tests. +- Preferred fix per `.claude/rules/csharp.md` "DI Seams": introduce an interface + or injectable-delegate seam for the invoke path so the test supplies a + synchronous no-op marshaller and never touches a real window handle. + Adding a sleep, a retry, or a handle-forcing call would violate the + "Prohibited Behaviors" section of the same rule. + +## Proposed Fix / Validation Ideas + +- [ ] Unit coverage areas: `QfcItemController` initialization overloads and + `ToggleTips`, exercised through the new seam rather than a live control. +- [ ] Integration scenario to retest: full nine-assembly suite run repeatedly + (at least 5 consecutive runs) to demonstrate the flakiness is gone. +- [ ] Manual verification notes: confirm the seam's production default still + marshals through the real control so runtime behavior is unchanged. + +## Next Step + +- [x] Promote to GitHub issue (bug-report template) +- [ ] Move to active fix folder / branch diff --git a/docs/features/potential/promoted/2026-08-15-system-reactive-7-packages-config-unsupported.md b/docs/features/potential/promoted/2026-08-15-system-reactive-7-packages-config-unsupported.md new file mode 100644 index 00000000..2f0b7e73 --- /dev/null +++ b/docs/features/potential/promoted/2026-08-15-system-reactive-7-packages-config-unsupported.md @@ -0,0 +1,106 @@ +# system-reactive-7-packages-config-unsupported (Issue #570) + +- Date captured: 2026-08-15 +- Author: Dan Moisan +- Status: Promoted -> docs/features/active/system-reactive-7-packages-config-unsupported/ (Issue #570) + +> Automation note: Keep the section headings below unchanged; the promotion tooling maps each of them into the GitHub bug issue template. + +- Issue: #570 +- Issue URL: https://github.com/drmoisan/TaskMaster/issues/570 +- Last Updated: 2026-08-15 +## Summary + +The NuGet upgrade in PR #568 moved System.Reactive to 7.0.0, which explicitly +does not support `packages.config`. Every build of the solution now emits five +warnings from the package's own guard target stating the configuration is +unsupported. The repository's projects are legacy non-SDK `packages.config` +projects, so the package is being consumed in a scenario its authors disclaim. + +## Environment + +- OS/version: Windows 11 Pro 10.0.26200 +- Python version: n/a (C# / .NET Framework 4.8.1) +- Command/flags used: `msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true` +- Data source or fixture: `packages/System.Reactive.7.0.0` + +## Steps to Reproduce + +1. Check out `main` at or after merge commit `97065e55`. +2. Run `nuget restore TaskMaster.sln`. +3. Run the analyzer or nullable toolchain stage, for example + `msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true`. +4. Observe the warning summary at the end of the build. + +## Expected Behavior + +The solution builds with zero warnings from its dependency set, and the reactive +dependency is consumed in a configuration its maintainers support. + +## Actual Behavior + +The build succeeds with 5 warnings, all of the following form: + +``` +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.) +``` + +Affected projects: `ToDoModel`, `QuickFiler`, `TaskMaster`, `UtilitiesCS.Test`, +and one further project in the same build. + +## Logs / Screenshots + +- [x] Attached minimal logs or screenshot +- Snippet: see the warning text quoted above; reproduced verbatim from the + local analyzer and nullable toolchain stages on 2026-08-15. + +## Impact / Severity + +- [ ] Blocker +- [ ] High +- [x] Medium +- [ ] Low + +The build is not broken today and both protected gates pass. The severity is +Medium rather than Low because the package guard is not cosmetic: the vendor +states the scenario is unsupported, so assembly-binding or runtime-loading +behavior for Rx may diverge from a supported configuration without further +warning, and the warning count masks any new warning that appears later. + +## Suspected Cause / Notes + +- The upgrade advanced System.Reactive across a major version boundary (6.x to + 7.0.0) where the package added `System.Reactive.PackagesConfigCheck.targets` + as a deliberate guard against `packages.config` consumption. +- The repository is intentionally on `packages.config` (see + `.claude/rules/csharp.md`, "Mechanism"): the projects are legacy non-SDK + VSTO / .NET Framework projects, and PackageReference / Central Package + Management were explicitly not introduced. +- Three responses exist and should be weighed rather than assumed: + 1. Pin System.Reactive back to the last 6.x release that supports + `packages.config`. + 2. Set `RxUseUnsupportedPackagesConfig=true` to silence the guard, accepting + the vendor-disclaimed configuration. + 3. Migrate the affected projects to PackageReference, which conflicts with + the documented repository decision and is a much larger change. +- Option 1 is the most likely correct answer given the repository's documented + stance, but it needs verification that nothing added in Rx 7.0 is required. + +## Proposed Fix / Validation Ideas + +- [ ] Unit coverage areas: existing reactive-dependent tests in `UtilitiesCS.Test` + and `QuickFiler.Test` must continue to pass under whichever option is taken. +- [ ] Integration scenario to retest: full `vstest.console.exe` run with + `/EnableCodeCoverage` across all nine test assemblies. +- [ ] Manual verification notes: confirm the build warning count returns to zero + and that assembly binding redirects for `System.Reactive` in each + `app.config` still resolve at runtime. + +## Next Step + +- [x] Promote to GitHub issue (bug-report template) +- [ ] Move to active fix folder / branch