diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 8daec7969..0a4347b07 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -113,7 +113,7 @@ and GitHub restricts it by default from 2026-11-02. | Secret | Holds | | --- | --- | -| `DEPENDABOT_REPAIR_APP_ID` | the numeric App identifier | +| `DEPENDABOT_REPAIR_APP_ID` | the App's Client ID, passed to the token action's `client-id` input (the numeric App ID is not stored) | | `DEPENDABOT_REPAIR_APP_PRIVATE_KEY` | the App's PEM private key | A repository admin provisions both by hand. The procedure — creating the App, granting it contents diff --git a/.github/workflows/dependabot-repair.yml b/.github/workflows/dependabot-repair.yml index fa7eac91f..b9c2f4785 100644 --- a/.github/workflows/dependabot-repair.yml +++ b/.github/workflows/dependabot-repair.yml @@ -10,8 +10,8 @@ name: dependabot-repair # name appears nowhere in this file: it is a security regression for a convenience gain, and GitHub # restricts it by default from 2026-11-02. # -# Credential: a GitHub App installation token minted from DEPENDABOT_REPAIR_APP_ID and -# DEPENDABOT_REPAIR_APP_PRIVATE_KEY. When those secrets are absent the token step fails, the job +# Credential: a GitHub App installation token minted from the App's Client ID, stored in +# DEPENDABOT_REPAIR_APP_ID, and the private key in DEPENDABOT_REPAIR_APP_PRIVATE_KEY. When those secrets are absent the token step fails, the job # stops before it can push, and the pull request keeps the behaviour it has today. See # .github/workflows/README.md for the degraded mode and the installation runbook. @@ -48,7 +48,7 @@ jobs: id: app-token uses: actions/create-github-app-token@v3 with: - app-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }} + client-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }} private-key: ${{ secrets.DEPENDABOT_REPAIR_APP_PRIVATE_KEY }} - name: Checkout the Dependabot branch diff --git a/QuickFiler.Test/QuickFiler.Test.csproj b/QuickFiler.Test/QuickFiler.Test.csproj index ad3ddafda..9fd57ab0b 100644 --- a/QuickFiler.Test/QuickFiler.Test.csproj +++ b/QuickFiler.Test/QuickFiler.Test.csproj @@ -5,7 +5,6 @@ - Debug @@ -534,7 +533,6 @@ - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. diff --git a/SVGControl/app.config b/SVGControl/app.config index 57e0ab003..05b1ceb18 100644 --- a/SVGControl/app.config +++ b/SVGControl/app.config @@ -12,11 +12,11 @@ - + - + diff --git a/docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md b/docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md index f64e14259..b2d7b0e17 100644 --- a/docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md +++ b/docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md @@ -96,13 +96,13 @@ permissions listed in step 6 below and skip to step 10. 8. Under **Where can this GitHub App be installed?**, select **Only on this account**. 9. Click **Create GitHub App**. -### Part B — Record the App ID and generate a private key +### Part B — Record the Client ID and generate a private key -10. On the App's settings page that appears after creation, locate the **App ID** in the "About" - section near the top of the page and record it. The adjacent **Client ID** is also shown; record - it as well, because the `actions/create-github-app-token` action now documents `client-id` as - the recommended input and continues to accept the legacy `app-id` input. Neither value is a - secret in the cryptographic sense, but this runbook stores the App ID as a repository secret to +10. On the App's settings page that appears after creation, locate the **Client ID** in the "About" + section near the top of the page and record it. The numeric **App ID** shown beside it is not + needed: the repair workflow passes the Client ID to the `actions/create-github-app-token` action + as its `client-id` input, which the action documents as the recommended input. The Client ID is + not a secret in the cryptographic sense, but this runbook stores it as a repository secret to keep the workflow configuration uniform. 11. On the same page, scroll to the **Private keys** section and click **Generate a private key**. A `.pem` file downloads automatically. GitHub issues the key in PKCS#1 `RSAPrivateKey` PEM @@ -126,9 +126,9 @@ permissions listed in step 6 below and skip to step 10. 19. Click **Settings** on the repository navigation bar. 20. In the sidebar's "Security" section, select **Secrets and variables**, then **Actions**. 21. Select the **Secrets** tab, then click **New repository secret**. -22. Create the App ID secret: +22. Create the Client ID secret: - **Name** — `DEPENDABOT_REPAIR_APP_ID` - - **Secret** — the App ID value recorded in step 10 + - **Secret** — the Client ID value recorded in step 10 - Click **Add secret**. 23. Click **New repository secret** again and create the private key secret: - **Name** — `DEPENDABOT_REPAIR_APP_PRIVATE_KEY` @@ -151,7 +151,7 @@ permissions listed in step 6 below and skip to step 10. id: app-token uses: actions/create-github-app-token@v3 with: - app-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }} + client-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }} private-key: ${{ secrets.DEPENDABOT_REPAIR_APP_PRIVATE_KEY }} - name: Check out the Dependabot branch diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/code-review.2026-09-30T10-30.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/code-review.2026-09-30T10-30.md new file mode 100644 index 000000000..e06f8579a --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/code-review.2026-09-30T10-30.md @@ -0,0 +1,91 @@ +# Code Review — package-manifest-consistency-residuals (Issue #929) + +- Artifact timestamp label: 2026-09-30T10-30 (caller-assigned) +- Branch: `bug/package-manifest-consistency-residuals-929`; head `5ce3c8c3b`; source diff base `231e1c0b5` +- Review method: Read, Grep and Glob over the item worktree (Bash forbidden by the caller); no command executed +- Companion artifacts: `policy-audit.2026-09-30T10-30.md`, `feature-audit.2026-09-30T10-30.md` +- Total blocking findings: **0** +- Total non-blocking findings: **7** (code-level; the policy audit carries five further procedural or evidence-hygiene items) + +## Executive Summary + +The change is small, targeted and matches the bugfix workflow: a tree-reading regression test file was authored and observed red before the fixes and green after, the fixes are the minimal edits the issue names (two deleted `` lines, two corrected `bindingRedirect` lines, one workflow input rename with its documentation), and the only production PowerShell edit is a three-line comment refresh. The two added in-memory detector tests and the four tree tests follow the conventions of the sibling suites (`$PSScriptRoot`-resolved reads, Arrange/Act/Assert comments, `-Because` on every assertion, no mocks, no files written). All toolchain gates passed on the final iteration. + +No blocking defect was found. Seven non-blocking observations are recorded below; none changes behaviour and none is required before merge. Five are cosmetic or style; two are pre-existing conditions outside the diff that the review surfaces for follow-up (a wall-clock wait in a QuickFiler.Test timing test, and tracked `.csproj.bak` copies still carrying the removed token). + +## Findings Table + +| Severity | File | Location | Finding | Recommendation | Rationale | Evidence | +|---|---|---|---|---|---|---| +| Minor (non-blocking) | `QuickFiler.Test/Controllers/QfcDatamodelLivenessTests.cs` (outside the diff) | line 189 (`RemainingLoadActive_AcrossAsyncVoidFirstAwait_StaysTrueWhileLoaderProduces`), wait at line 172/192 | Test relies on a real five-second `Task.Wait(TimeSpan.FromSeconds(5))`; it failed once in local iteration 1 under the full parallel run and passed in the baseline and iteration 2 on the same tree. A second, different timing test (`QfcItemController.UiThreadDispatcherFixtureTests.cs` line 206) failed once on CI run 36722780748. | List for follow-up: replace the wall-clock wait with the deterministic completion signal the determinism rule requires, and examine the dispatcher-fixture test for the same class. Not a change for this branch. | `.claude/rules/general-unit-test.md` bans real wall-clock waits in test code; both tests are pre-existing and no `.cs` file changed here. | `evidence/qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md`; `evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md` (run-level conclusion) | +| Minor (non-blocking) | `QuickFiler.Test/QuickFiler.Test.csproj.bak`, `QuickFiler/QuickFiler.csproj.bak` (outside the diff) | whole files | Two of eight tracked `*.csproj.bak` copies still carry the `altcover` token after the live imports were removed. MSBuild does not read `.bak`, so AC1's project-file scope is satisfied. | List for follow-up: delete the eight tracked `.bak` copies (plan decision D12 deliberately left them). | Tracked backup copies of project files are stale duplicates that future censuses have to exclude by pathspec. | Grep `altcover` (case-insensitive) over the worktree excluding `docs/`; `evidence/baseline/p0-t1-worktree-anchor.2026-09-28T20-01.md` BAK-TRACKED list | +| Minor (non-blocking) | `docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md` | line 301 | Sources entry still reads "Private key generation and App ID location (steps 10-12)" although step 10 now records the Client ID and states the App ID is not needed. | Reword to "Client ID location" when the runbook is next touched. | Comment/citation text drifted from the instruction it cites; the instruction itself (steps 10, 22, YAML sample) is correct. | Read of lines 99-106, 129-132, 154, 298-321 | +| Minor (non-blocking) | `.github/workflows/dependabot-repair.yml` | line 14 | Header comment line is roughly 150 characters; the surrounding block wraps near 100. | Re-wrap the two-line credential sentence when the file is next edited. | Readability only; actionlint does not police comment width. | Read of lines 13-16 | +| Minor (non-blocking) | `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | lines 92-110 | Test 2 asserts two assemblies (`Fizzler`, `System.Runtime.CompilerServices.Unsafe`) inside one `It` via `foreach`; a Fizzler failure stops the block before the Unsafe assertions run. | Optional: split into two `It` blocks or use a `-ForEach` data-driven `It`, so each assembly reports independently. | `.claude/rules/powershell.md`: one behaviour per `It`. The census in test 1 is a deliberate single assertion over a set and is acceptable as written. | Read of the file | +| Info (non-blocking) | `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | lines 65-90 | Test 1 enumerates every top-level directory that holds a `packages.config` and exactly one `.csproj`; directories with zero or several project files are silently skipped. On this tree every manifest directory has exactly one project file, so nothing is skipped today. | Optional hardening: assert the skipped-directory count is zero, or assert the pair count equals the number of `packages.config` files found, so a future multi-project directory cannot drop out of the census unnoticed. | The `Should -BeGreaterThan 9` floor guards against an empty census but not against partial coverage of the tree. | Read of lines 67-74 | +| Info (non-blocking) | feature folder evidence (`Timestamp:` fields) | all executor artifacts | Labels lead the embedded UTC clock readings by 38 to 72 minutes (for example P2-T3 iter2 labelled `10-58` with RUN-START `13:46:37Z`, i.e. 09:46 local), so they are sequence labels rather than clock readings. | None for this branch; future executors should stamp from the clock. | Evidence hygiene; the gates demonstrably ran (JUNIT-WRITTEN follows RUN-START in every artifact; CI run ids are third-party facts). | `evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md`, `p1-t11-...`, `evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md`; worktree `artifacts/pester/powershell-coverage.xml` report name `Pester (09/30/2026 09:47:03)` | + +## Scope Reviewed + +| Path | Lines / shape | Reviewed how | +|---|---|---| +| `QuickFiler.Test/QuickFiler.Test.csproj` | 2 deletions (570 to 568) | Grep confirms no `altcover` token remains in any `*.csproj`, `*.config`, `*.props`, `*.targets`; P1-T4 quotes the two deleted lines | +| `SVGControl/app.config` | 2 changed lines (15, 19) | Read in full; compared with `SVGControl.csproj` lines 58 and 82 and `packages.config` lines 4 and 10 | +| `.github/workflows/dependabot-repair.yml` | lines 13-14, 51 | Read in full (173 lines) | +| `.github/workflows/README.md` | line 116 | Grep | +| 911 runbook | Part B heading, steps 10 and 22, YAML sample line 154 | Read lines 96-159 and 296-321 | +| `scripts/dependencies/ConsistencyVerifier.psm1` | comment lines 221-223 | Read lines 180-320 and 424-480 | +| `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1` | comments at 57-59 and 300; `It` blocks at 240-263; 337 lines | Read lines 1-30, 50-79, 210-329; Grep of every `Describe`/`Context`/`It` line | +| `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | new, 152 lines | Read in full | +| `docs/features/potential/promoted/2026-09-28-package-manifest-consistency-residuals.md` | promoted record | present on disk; content is the issue body | +| Feature folder | issue.md, plan (56 of 56), 61 evidence `.md`, 2 JaCoCo projections, 2 trx summaries | Glob (69 files); 30 artifacts read in full | + +## File-by-File Review + +### `QuickFiler.Test/QuickFiler.Test.csproj` + +The two removed elements were `Exists()`-guarded imports of `..\packages\altcover.8.6.45\build\netstandard2.0\AltCover.{props,targets}`. No manifest declares altcover, the restore never creates that folder (P0-T5 `ALTCOVER-RESTORED: False`), and CI has no cache fallback that could supply it, so the imports were inert and their removal cannot alter the build graph. The project has no `` guard to remove alongside (P0-T17 census; plan tree facts). Correct and minimal. + +### `SVGControl/app.config` + +Both `bindingRedirect` elements now name the assembly version the `` declares (`Fizzler, Version=1.3.1.0`; `System.Runtime.CompilerServices.Unsafe, Version=6.0.3.0`) and the `oldVersion` upper bound moves with it. The executor additionally verified the restored DLLs' `AssemblyName.Version` (P0-T18: `FIZZLER_ASM=1.3.1.0`, `UNSAFE_ASM=6.0.3.0`) and that `Invoke-BindingRedirectReconciliation` reports zero repairs after the edit (P1-T5). Hand-editing was the right call: the repair script only reconciles redirects for packages it upgraded (plan decision D2). + +### `.github/workflows/dependabot-repair.yml` + +`client-id` is the input `actions/create-github-app-token` documents as recommended; the runbook's Sources entry (line 318) records that `app-id` remains accepted as legacy, so the rename is behaviour-preserving for the action while removing the deprecation warning that the issue's linked run shows. The secret name is deliberately unchanged (decision D3), so no maintainer action is required for the merge and the workflow's degraded mode (token step fails, job stops before pushing) is unchanged. The header comment was updated to describe the Client ID semantics. Nothing in the `run:` blocks changed, so the `ci-workflows.md` exit-code rule is not engaged. + +### `.github/workflows/README.md` and the 911 runbook + +README line 116 and runbook steps 10 and 22 now say the secret holds the App's Client ID and that the numeric App ID is not stored. The runbook's YAML sample matches the workflow line for line. One stale citation phrase remains (Findings Table, row 3). + +### `scripts/dependencies/ConsistencyVerifier.psm1` + +Three comment lines inside the `.DESCRIPTION` of `Find-PackageAbsentFromManifest` now state that issue 929 removed the last live instance and that the shape survives as an in-memory fixture. Line count held at 499 (P2-T1 iter2). No executable line changed; the function body (lines 236-249) is byte-identical to the base per the caller's diff, and the CI JaCoCo documents show the same 158/160 covered lines before and after with the same two uncovered lines (430, 475), which is consistent with an unchanged body. + +### `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1` + +The two added `It` blocks sit in the existing `Context 'Package absent from the manifest'` and reuse the existing `$script:GuardedUnmanifestedProject` (two guarded altcover imports plus a declared `Contoso.Widgets` reference) and `$script:AgreeingProject` fixtures against `$script:Manifest`. The positive test pins three facts: FindingCount 2, every finding Kind `Import`, every PackageFolder `altcover.8.6.45`. The negative test filters to the Import kind and guards the empty subset with `ExaminedCount -gt 0`, the same guard pattern the sibling tests use. Comments at lines 57-59 and 300 no longer describe the fixture as live. Fixtures are here-strings; no file is written. + +### `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` + +- Header (lines 1-12): `Set-StrictMode -Version Latest`; module import by `$PSScriptRoot`; the two document paths and the `client-id` pattern are script-scoped constants; the header comment states the no-disk-write and no-`AC` rules. +- `Get-TokenStepBlock` (14-43): re-implements the step-block slicing of `DependabotConfig.Tests.ps1` (a step runs from its `- name:` line to the next), returns the first step whose `uses:` line contains the token, and returns an empty `string[]` otherwise; the comma-return preserves array shape under StrictMode. +- `Get-DependentAssemblyBlock` (45-60): single-line regex over the config text with `[regex]::Escape` on the assembly name; returns the first matching `` block. +- Test 1 (65-90): census over top-level directories; `ExaminedCount` summed and asserted greater than zero before the zero-findings assertion, so a detector that never fired cannot pass vacuously; the failure message lists each offending Import as `: line ` (the P1-T2 message shows exactly that shape). +- Test 2 (92-110): for each of the two assemblies, extracts the `Version=` from the `` and asserts `newVersion` equality and `oldVersion` suffix. See Findings Table row 5 for the granularity note. +- Test 3 (112-125): exactly one `client-id:` line reading a secret and zero `app-id:` lines inside the token step. +- Test 4 (127-151): extracts the secret name from the workflow, asserts the runbook's YAML sample passes `client-id` from that exact secret and no `app-id`, and asserts Part D (the secret-creation section) mentions `Client ID` and the secret name. The coupling to the workflow's own text is what makes AC6's "names that secret exactly as the workflow names it" a checked property rather than a duplicated literal. + +Residual risk recorded by the plan (A2): test 4 reads the runbook at its active-folder path; the eventual feature-promotion move of the 911 folder must update `$script:RunbookPath` in the same change. + +## Positive Observations + +- Fail-before / pass-after evidence is complete and specific: four red tests with messages quoting the exact defect values, then three green and one red at the intermediate step, then four green. +- Decision D1 avoided adding a production rule the detector already had, keeping the production diff to comments. +- Every gate substitution mandated by the coordinator's PowerShell ruling is recorded in the artifact it affects with a `GATE-SUBSTITUTION:` line. +- Committed coverage evidence is in the permitted projection form; the raw documents were left gitignored under `coverage/` and `artifacts/`, which let this review read the per-line JaCoCo data directly. +- The two P2 loop iterations are both recorded, including the failed one, with an attribution paragraph rather than a silent retry. + +## Blocking Count + +Blocking: 0. Non-blocking: 7 in this artifact. No remediation inputs are produced. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t1-worktree-anchor.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t1-worktree-anchor.2026-09-28T20-01.md new file mode 100644 index 000000000..a367f6d37 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t1-worktree-anchor.2026-09-28T20-01.md @@ -0,0 +1,40 @@ +# P0-T1 — Worktree anchor + +Timestamp: 2026-09-30T09-09 +Command: git rev-parse --show-toplevel; git rev-parse --abbrev-ref HEAD; git fetch origin main; git rev-parse origin/main; git merge-base origin/main HEAD; git rev-parse HEAD; git cat-file -t ; git cat-file -t ; git rev-list --count ..HEAD; git merge-base --is-ancestor 231e1c0b55105aeb626bf5a6e8d0266a567cacad HEAD; git status --porcelain --untracked-files=all; git ls-files -- "*.csproj.bak"; git diff --name-only HEAD -- (all run from ) +EXIT_CODE: 0 +Output Summary: +- show-toplevel: +- Branch: bug/package-manifest-consistency-residuals-929 +- origin/main (after fetch): b305903e275b8abf58e8e65831c189f517568fe4 +- BASE-SHA (merge-base origin/main HEAD): 231e1c0b55105aeb626bf5a6e8d0266a567cacad (git cat-file -t: commit) +- P0-START (HEAD): 481b33c594d8412cb64e604ff53295db215ac2f1 (git cat-file -t: commit) +- git rev-list --count ..HEAD: 8 (recorded as measured) +- MERGED-MAIN-ANCESTOR: 0 (git merge-base --is-ancestor 231e1c0b55105aeb626bf5a6e8d0266a567cacad HEAD exited 0; the worktree carries the 2026-09-30 merge of origin/main) +- Seven-path diff against HEAD: empty (no Write Set source file is already modified) +- Note: origin/main has advanced to b305903e2 since the branch merged 231e1c0b5; the merge-base remains 231e1c0b5, so is the merged tip as the plan states. + +BASE-UNTRACKED: +``` + M .claude/agent-memory/atomic-executor/MEMORY.md + M .claude/agent-memory/atomic-planner/MEMORY.md +?? .claude/agent-memory/atomic-executor/index_csharp_nullable_and_component_gotchas.md +?? .claude/agent-memory/atomic-executor/index_pwsh_git_and_gate_mechanics_misc.md +?? .claude/agent-memory/atomic-executor/index_test_isolation_and_coverage.md +?? .claude/agent-memory/atomic-executor/project_hygiene_pattern_array_comma_precedence_and_regex_token_hits.md +?? .claude/agent-memory/atomic-planner/project_929_manifest_residuals_plan_seams.md +``` +No entry matches *.cs, *.csproj, packages.config or app.config. + +BAK-TRACKED: +``` +QuickFiler.Test/QuickFiler.Test.csproj.bak +QuickFiler/QuickFiler.csproj.bak +Tags/Tags.csproj.bak +TaskTree/TaskTree.csproj.bak +TaskVisualization.Test/TaskVisualization.Test.csproj.bak +TaskVisualization/TaskVisualization.csproj.bak +ToDoModel.Test/ToDoModel.Test.csproj.bak +ToDoModel/ToDoModel.csproj.bak +``` +Eight tracked .csproj.bak copies (the plan names two carrying altcover tokens; all eight are recorded). They are not project files and are not edited (decision D12). diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t10-msbuild-analyzers.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t10-msbuild-analyzers.2026-09-28T20-01.md new file mode 100644 index 000000000..827eb2a1b --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t10-msbuild-analyzers.2026-09-28T20-01.md @@ -0,0 +1,13 @@ +# P0-T10 — Analyzer rebuild baseline (CMD-MSBUILD-ANALYZERS) + +Timestamp: 2026-09-30T09-21 +Command: pwsh -NoProfile -Command 'Set-Location ""; msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true "/flp:LogFile=coverage\analyzers.msbuild.log;Verbosity=normal"; "MSBUILD_EXIT=$LASTEXITCODE"; $l = "coverage\analyzers.msbuild.log"; "OUT_LINES=" + @(Select-String -LiteralPath $l -SimpleMatch -Pattern ("/out:obj" + [char]92 + "Debug" + [char]92)).Count; "CS0006_LINES=" + @(Select-String -LiteralPath $l -SimpleMatch -Pattern "CS0006").Count' +EXIT_CODE: 0 +OUTLOOK-CLOSED: true +Output Summary: +- CMD-OUTLOOK: Get-Process outlook count printed 0 (Outlook not running; nothing terminated). +- msbuild summary: "Build succeeded." / "0 Warning(s)" / "0 Error(s)" / "Time Elapsed 00:00:16.19" +- MSBUILD_EXIT=0 +- OUT_LINES=36 (at least 18) +- CS0006_LINES=0 +- The file log stays under the ignored coverage directory and is not committed. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t11-msbuild-nullable.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t11-msbuild-nullable.2026-09-28T20-01.md new file mode 100644 index 000000000..d0c3489b1 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t11-msbuild-nullable.2026-09-28T20-01.md @@ -0,0 +1,13 @@ +# P0-T11 — Nullable rebuild baseline (CMD-MSBUILD-NULLABLE) + +Timestamp: 2026-09-30T09-22 +Command: pwsh -NoProfile -Command 'Set-Location ""; msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true "/flp:LogFile=coverage\nullable.msbuild.log;Verbosity=normal" | Out-Null; "MSBUILD_EXIT=$LASTEXITCODE"; $l = "coverage\nullable.msbuild.log"; "OUT_LINES=" + @(Select-String -LiteralPath $l -SimpleMatch -Pattern ("/out:obj" + [char]92 + "Debug" + [char]92)).Count; Get-Content -LiteralPath $l -Tail 8' +EXIT_CODE: 0 +OUTLOOK-CLOSED: true +Output Summary: +- CMD-OUTLOOK: @(Get-Process outlook -ErrorAction SilentlyContinue).Count printed 0 (nothing terminated). +- Console output was discarded with Out-Null to keep the capture readable; the msbuild arguments are exactly CMD-MSBUILD-NULLABLE and the summary is read from the file log tail. +- File log tail: "Build succeeded." / "0 Warning(s)" / "0 Error(s)" / "Time Elapsed 00:00:14.18" +- MSBUILD_EXIT=0 +- OUT_LINES=36 (at least 18) +- No Nullable property was added and the Rebuild target was used (CLAUDE.md C#1.3). diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-coverage-projection.2026-09-28T20-01.jacoco.xml b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-coverage-projection.2026-09-28T20-01.jacoco.xml new file mode 100644 index 000000000..0c933d212 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-coverage-projection.2026-09-28T20-01.jacoco.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-mstest-coverage.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-mstest-coverage.2026-09-28T20-01.md new file mode 100644 index 000000000..db3b33fa9 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-mstest-coverage.2026-09-28T20-01.md @@ -0,0 +1,28 @@ +# P0-T12 — C# test and coverage baseline (CMD-MSTEST-COVERAGE) + +Timestamp: 2026-09-30T09-40 +Command: pwsh -NoProfile -Command 'Set-Location ""; & "\scripts\vscode\Invoke-MSTestWithCoverage.ps1" -SearchRoot .' (run detached with its combined output redirected to a session scratch log outside the repository, because the run exceeds a single tool-call window; the script and its arguments are unchanged) +EXIT_CODE: 0 +Output Summary: +- "Test Run Successful." +- "Total tests: 7346" / "Passed: 7346" +- First-party coverage: lines 56475/65736 (85.91%), branches 13656/17054 (80.08%) +- Baseline line percentage L = 85.91; baseline branch percentage R = 80.08 (L at least 80 and R at least 75; the runner enforces both floors before printing the line) +- MEETS-85: true (observation only, convention 10) +- Test-result summary (copied): total 7346, executed 7346, passed 7346, failed 0; skipped 0 (derived); error 0, timeout 0, aborted 0, notExecuted 0, inconclusive 0; failed tests: none +- Path-printing lines, with host prefixes replaced (convention 4): + - "Using vstest.console: \Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe" + - "Coverage output: \coverage\coverage.cobertura.xml" + - "Coverage projection: \coverage\coverage.cobertura.jacoco.xml" + - "Test-result summary: \coverage\test-results\mstest-coverage-run.summary.txt" + - "Done. Coverage artifact: \coverage\coverage.cobertura.xml" + +Copies: +- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-coverage-projection.2026-09-28T20-01.jacoco.xml — 1467 bytes; root element report; 9 package elements +- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-test-results.2026-09-28T20-01.summary.txt — 298 bytes + +Reconciliation: the sum of the projection's package LINE covered counters is 56475, equal to the line numerator A = 56475 on the printed line, so the copy describes this run. + +PROJECTION-RAW-ELEMENTS: 0 (Select-String over the copy for ", scan_folders ["scripts/dependencies","tests/scripts/dependencies"]); re-hash; git status --porcelain --untracked-files=all -- scripts/dependencies tests/scripts/dependencies; @(Get-Content -LiteralPath "scripts/dependencies/ConsistencyVerifier.psm1").Count +EXIT_CODE: 0 +Output Summary: +- MCP payload: {"ok":true,"tool":"run_poshqc_format","workspace_root":"","summary":"Ran bundled PoshQC format against '' with 2 selected scan folder(s)."} (ok recorded, not asserted) +- scan_folders: ["scripts/dependencies","tests/scripts/dependencies"] +- Hash sets: 13 entries before, 13 after (6 production, 7 test files); every hash identical +- Rewrite count (hash difference): 0 +- REVERT-SET: empty +- FORMAT-REWROTE-WRITE-SET: none +- Post-run porcelain over the two folders: empty +- VERIFIER-LINES: 499 + +Hash set (identical before and after): +``` +scripts\dependencies\AnalyzerItemRepair.psm1 102E3EBCF014F8365C3C65A834EDEC5FC9DAC9B1FFD6477E68D813335DB48F68 +scripts\dependencies\ConsistencyVerifier.psm1 2F37D7CBE2EC9739B4E7E1E08B76C653ACFA083F7AD73D008B616F9024E2EBFA +scripts\dependencies\PackageCompatibility.psm1 89B31603872ED09C8E2DF2E94A597D42BF3A2019D4F49298D6859CEF7CBF41CD +scripts\dependencies\PackageGraph.psm1 1CE9EABA3A43FF2446C3B63FFA53CE501537362C8E6EED6BB9DB4774F15C9BC6 +scripts\dependencies\ProjectConsistency.psm1 0E7B005A65B5614A0099F7A7286FE6692F87CC49FF09D749877F832C37D69EFE +scripts\dependencies\Repair-PackageManifestConsistency.ps1 E69F61364EB1640C0FADFBBAE1F418250D2F508E8F26A048BE43F70DD659078A +tests\scripts\dependencies\AnalyzerItemRepair.Tests.ps1 7C4CBC097681F98A629F94AD12D800A7E87652CA773825FA26F621969671D011 +tests\scripts\dependencies\ConsistencyVerifier.Tests.ps1 72928DAEE535364B263945689AE46BE024D8D08FF129381094A7D213B1D0E317 +tests\scripts\dependencies\DependabotConfig.Tests.ps1 3F738E78A77F028BBB97D86BD2B9A33DC8CB94F1ABB31F1DC306413CDE3B3C48 +tests\scripts\dependencies\PackageCompatibility.Tests.ps1 0EF34C85EBA0B70C24CC4EA662472FA97F33D20B527120278606B12F6D7010DC +tests\scripts\dependencies\PackageGraph.Tests.ps1 910DD957F6377DD60A9F2EFC26E7597421E2C69505DE21E78E4B087729305EBE +tests\scripts\dependencies\ProjectConsistency.Tests.ps1 BCB15A04404BD3792A1DCB65315DE2B4CD822087B9D3EB3006E8BE9EB81CA761 +tests\scripts\dependencies\Repair-PackageManifestConsistency.Tests.ps1 3348C5D17773A9DCC6EEFD3A85EF6874BB96CA9BE8B1F2A85C1EA9CB96756942 +``` diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t14-poshqc-analyze.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t14-poshqc-analyze.2026-09-28T20-01.md new file mode 100644 index 000000000..4629e5402 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t14-poshqc-analyze.2026-09-28T20-01.md @@ -0,0 +1,13 @@ +# P0-T14 — PowerShell analyzer baseline (CMD-POSHQC-ANALYZE) + +Timestamp: 2026-09-30T09-43 +Command: MCP mcp__drm-copilot__run_poshqc_analyze (workspace_root , scan_folders ["scripts/dependencies","tests/scripts/dependencies"]); pwsh -NoProfile -Command 'Set-Location ""; "FILES=" + @(Get-ChildItem -Recurse -File -Path "scripts/dependencies","tests/scripts/dependencies" -Include *.ps1,*.psm1).Count' +EXIT_CODE: 0 +Output Summary: +- MCP payload (verbatim, host prefix replaced): {"ok":true,"tool":"run_poshqc_analyze","workspace_root":"","summary":"Ran bundled PoshQC analyze against '' with 2 selected scan folder(s)."} +- No stderr excerpt was returned. +- scan_folders: ["scripts/dependencies","tests/scripts/dependencies"] +- PoshQC analyze: pass (0 findings); tool reports no count +- FILES=13 (6 production, 7 test files) + +GATE-SUBSTITUTION: PoshQC analyze ok flag stands in for a diagnostic count diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t15-poshqc-test-mcp.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t15-poshqc-test-mcp.2026-09-28T20-01.md new file mode 100644 index 000000000..88fb7651a --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t15-poshqc-test-mcp.2026-09-28T20-01.md @@ -0,0 +1,23 @@ +# P0-T15 — PowerShell test baseline through the MCP route (CMD-POSHQC-TEST, CMD-JUNIT-READ) + +Timestamp: 2026-09-30T09-45 +Command: pwsh -NoProfile -Command '[DateTime]::UtcNow.ToString("o")' (RUN-START); MCP mcp__drm-copilot__run_poshqc_test (workspace_root , scan_folders ["tests/scripts/dependencies"]); CMD-JUNIT-READ; the PESTER-VERSION read command, appended to the same pwsh invocation as CMD-JUNIT-READ +EXIT_CODE: 0 +Output Summary: +- RUN-START: 2026-09-30T13:17:15.3091663Z +- MCP payload (host prefix replaced): {"ok":true,"tool":"run_poshqc_test","workspace_root":"","summary":"Ran bundled PoshQC test against '' with 1 selected scan folder(s)."} +- JUNIT-WRITTEN=2026-09-30T13:17:45.2888350Z (later than RUN-START; the document was written by this run) +- JUNIT-ROOT tests=131 failures=0 errors=0 disabled=0 +- JUNIT-SUITE AnalyzerItemRepair.Tests.ps1 tests=13 failures=0 skipped=0 +- JUNIT-SUITE ConsistencyVerifier.Tests.ps1 tests=12 failures=0 skipped=0 +- JUNIT-SUITE DependabotConfig.Tests.ps1 tests=17 failures=0 skipped=0 +- JUNIT-SUITE PackageCompatibility.Tests.ps1 tests=8 failures=0 skipped=0 +- JUNIT-SUITE PackageGraph.Tests.ps1 tests=32 failures=0 skipped=0 +- JUNIT-SUITE ProjectConsistency.Tests.ps1 tests=18 failures=0 skipped=0 +- JUNIT-SUITE Repair-PackageManifestConsistency.Tests.ps1 tests=31 failures=0 skipped=0 +- Exactly 7 JUNIT-SUITE lines; no JUNIT-NOTPASSED line. +- PESTER-VERSION: 5.6.1 + +This route reports no coverage figure; P0-T16 reads the coverage baseline from CI. + +GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t16-pester.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t16-pester.2026-09-28T20-01.md new file mode 100644 index 000000000..e73335543 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t16-pester.2026-09-28T20-01.md @@ -0,0 +1,33 @@ +# P0-T16 — Pester coverage baseline from CI (CMD-CI-PESTER) + +Timestamp: 2026-09-30T09-47 +Command: CMD-CI-PESTER with RUN-ID 36666302259 and DIR coverage/ci-main-pester-36666302259-1 (pwsh -NoProfile -Command 'Set-Location ""; gh run view 36666302259 --repo drmoisan/TaskMaster --json databaseId,headSha,headBranch,event,status,conclusion,workflowName ...; gh run view --repo drmoisan/TaskMaster --job --log ...; gh run download 36666302259 --repo drmoisan/TaskMaster --name pester-coverage --dir "coverage/ci-main-pester-36666302259-1"; ...'), then git merge-base --is-ancestor 231e1c0b55105aeb626bf5a6e8d0266a567cacad HEAD +EXIT_CODE: 0 +Output Summary: +- RUN id=36666302259 head=231e1c0b55105aeb626bf5a6e8d0266a567cacad branch=main event=push status=completed conclusion=success workflow=CI +- git merge-base --is-ancestor 231e1c0b55105aeb626bf5a6e8d0266a567cacad HEAD exited 0 (the run's head is an ancestor of the executor's HEAD) +- PESTER-JOBS=1 +- JOB id=109731601928 name=pester / Run Pester suite with coverage status=completed conclusion=success +- LOG-LINES=1085 +- Log lines (verbatim after SGR stripping; run 36666302259, head 231e1c0b5): + - "Tests Passed: 373, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0" + - "PESTER Passed=373 Failed=0 Skipped=0 Total=373" + - "COVERAGE LinePercent=94.51 Covered=1721 Total=1821" +- BASELINE-TOTAL: 373 (Passed 373 + Failed 0 + Skipped 0, equal to the Total field 373) +- DIR-PREEXISTS=False; DOWNLOAD-EXIT=0; ARTIFACT-FILES=1; DIR used: coverage/ci-main-pester-36666302259-1 +- REPORT-LINE covered=1721 missed=100; computed percent 1721 / 1821 * 100 = 94.51, equal to the log's LinePercent 94.51 and at least 80 +- MEETS-85: true (observation only, convention 10) +- SOURCEFILE lines (run 36666302259, head 231e1c0b5): + - AnalyzerItemRepair.psm1 covered=106 missed=0 + - ConsistencyVerifier.psm1 covered=158 missed=2 + - PackageCompatibility.psm1 covered=33 missed=0 + - PackageGraph.psm1 covered=164 missed=0 + - ProjectConsistency.psm1 covered=103 missed=0 + - Repair-PackageManifestConsistency.ps1 covered=213 missed=14 +- VERIFIER-COVERED: 158 +- VERIFIER-MISSED: 2 +- No TRANSCRIPTION-MISMATCH: the run's figures equal the coordinator's (Tests Passed 373, LinePercent 94.51, Covered 1721, Total 1821). + +Pester emits no branch counter, so no PowerShell branch figure is claimed. These figures stand in for a permitted evidence form that the committed-evidence section of CLAUDE.md does not define for the Pester route. The downloaded JaCoCo document stays under the ignored coverage directory and is not committed. + +GATE-SUBSTITUTION: CI Pester job 109731601928 stands in for a local coverage run diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t17-altcover-and-verifier-prefix.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t17-altcover-and-verifier-prefix.2026-09-28T20-01.md new file mode 100644 index 000000000..ac65003ca --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t17-altcover-and-verifier-prefix.2026-09-28T20-01.md @@ -0,0 +1,31 @@ +# P0-T17 — Pre-fix altcover state and read-only verifier baseline + +Timestamp: 2026-09-30T09-49 +Command: pwsh -NoProfile -Command 'Set-Location ""; $m = @(git grep -i -n altcover -- "*.csproj" "*/packages.config"); "ALTCOVER_LINES=$($m.Count)"; $m' then CMD-VERIFIER-WHATIF +EXIT_CODE: 0 +Output Summary: +- ALTCOVER_LINES=2 + - QuickFiler.Test/QuickFiler.Test.csproj:8: + - QuickFiler.Test/QuickFiler.Test.csproj:537: +- CMD-VERIFIER-WHATIF result line: ABSENT=2 DISAGREE=0 WRITTEN=0 SUCCESS=True PROJECTS=18 FILES=53 HASHES_EQUAL=True +- DISAGREE (0) and SUCCESS (True) recorded as measured with no expectation: DISAGREE is computed over the in-memory repaired project text (Repair-PackageManifestConsistency.ps1 lines 411 to 422). +- Information line (printed five times): "Manifest discovery: enumerated directories 35, returned files 53" +- -WhatIf messages (operation "Rewrite in canonical inline form"), target paths with prefix replaced: + - \QuickFiler.Test\packages.config + - \QuickFiler\packages.config + - \SVGControl.Test\packages.config + - \Tags.Test\packages.config + - \Tags\packages.config + - \TaskMaster.Test\packages.config + - \TaskMaster\packages.config + - \TaskTree.Test\packages.config + - \TaskTree\packages.config + - \TaskVisualization.Test\packages.config + - \TaskVisualization\packages.config + - \ToDoModel.Test\packages.config + - \ToDoModel\packages.config + - \UtilitiesCS.Test\packages.config + - \UtilitiesCS\packages.config + - \VBFunctions.Test\packages.config + - \VBFunctions\packages.config +- HASHES_EQUAL=True: the what-if run wrote nothing (FILES=53, at least 50). diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t18-redirect-prefix.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t18-redirect-prefix.2026-09-28T20-01.md new file mode 100644 index 000000000..42826eb22 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t18-redirect-prefix.2026-09-28T20-01.md @@ -0,0 +1,30 @@ +# P0-T18 — Pre-fix binding redirect state + +Timestamp: 2026-09-30T09-50 +Command: pwsh -NoProfile -Command 'Set-Location ""; (quote SVGControl/app.config lines 15 and 19 and SVGControl/SVGControl.csproj lines 58 and 82); "FIZZLER_ASM=" + [System.Reflection.AssemblyName]::GetAssemblyName((Resolve-Path "packages/Fizzler.1.3.1/lib/netstandard2.0/Fizzler.dll").Path).Version; "UNSAFE_ASM=" + [System.Reflection.AssemblyName]::GetAssemblyName((Resolve-Path "packages/System.Runtime.CompilerServices.Unsafe.6.1.2/lib/net462/System.Runtime.CompilerServices.Unsafe.dll").Path).Version; (CMD-REDIRECT-OBSERVE); (tree-wide Fizzler newVersion listing over */app.config)' — the plan's three commands run in one pwsh invocation +EXIT_CODE: 0 +Output Summary: +- SVGControl/app.config line 15: ` ` +- SVGControl/app.config line 19: ` ` +- SVGControl/SVGControl.csproj line 58: ` ` +- SVGControl/SVGControl.csproj line 82: ` ` +- FIZZLER_ASM=1.3.1.0 +- UNSAFE_ASM=6.0.3.0 +- FIZZLER_REPAIRS=1 UNSAFE_REPAIRS=1 EXAMINED=4 (the pre-fix drift as Invoke-BindingRedirectReconciliation sees it) + +Tree-wide Fizzler redirect listing (13 configs: 12 at 1.3.0.0, UtilitiesCS at 1.3.1.0): +- SVGControl Fizzler 1.3.0.0 (in-scope AC2 target) +- UtilitiesCS Fizzler 1.3.1.0 (already names 1.3.1.0) +- OUT-OF-SCOPE-RESIDUAL: QuickFiler Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: QuickFiler.Test Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: SVGControl.Test Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: Tags Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: TaskMaster Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: TaskTree Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: TaskVisualization Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: TaskVisualization.Test Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: ToDoModel Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: ToDoModel.Test Fizzler 1.3.0.0 +- OUT-OF-SCOPE-RESIDUAL: UtilitiesCS.Test Fizzler 1.3.0.0 + +The 11 out-of-scope residuals are already recorded in docs/features/potential/2026-08-04-stale-fizzler-and-unsafe-binding-redirects.md (decision D5). The tree-wide count matches the plan's expectation of 13. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t19-workflow-prefix-and-actionlint.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t19-workflow-prefix-and-actionlint.2026-09-28T20-01.md new file mode 100644 index 000000000..d21b28396 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t19-workflow-prefix-and-actionlint.2026-09-28T20-01.md @@ -0,0 +1,17 @@ +# P0-T19 — Pre-fix workflow, runbook and README state; actionlint baseline + +Timestamp: 2026-09-30T09-51 +Command: pwsh -NoProfile -Command 'Set-Location ""; $w = Get-Content ".github/workflows/dependabot-repair.yml"; "WF_APPID=" + ...; "WF_CLIENTID=" + ...; $rb = Get-Content "docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md"; "RB_APPID=" + ...; "RB_CLIENTID=" + ...; "RB_PARTB=" + ...; "README_NUMERIC=" + ...' (the plan's P0-T19 command verbatim) then CMD-ACTIONLINT +EXIT_CODE: 0 +Output Summary: +- WF_APPID=1 +- WF_CLIENTID=0 +- RB_APPID=1 +- RB_CLIENTID=0 +- RB_PARTB=1 (the Part B heading at line 99) +- README_NUMERIC=1 +- actionlint version line: "1.7.7" (followed by "installed by downloading from release page" and "built with go1.23.4 compiler for windows/amd64") +- Scoped lint of .github/workflows/dependabot-repair.yml: no output; SCOPED_EXIT=0 +- Repository-wide run-actionlint.ps1: no output; REPO_EXIT=0 +- Lint output recorded as empty: the baseline tree lints clean; the app-id deprecation is a runtime warning of the action, not a lint finding. +- CI actionlint version: 1.7.7 (.github/workflows/_actionlint.yml line 26); local version 1.7.7. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t20-hygiene.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t20-hygiene.2026-09-28T20-01.md new file mode 100644 index 000000000..c54250e3f --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t20-hygiene.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P0-T20 — Hygiene scan of the feature folder (CMD-HYGIENE) + +Timestamp: 2026-09-30T09-52 +Command: CMD-HYGIENE with FOLDER-LIST "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929" (pwsh -NoProfile -Command 'Set-Location ""; $acct = Split-Path -Leaf $env:USERPROFILE; $machine = [System.Environment]::MachineName; ...; "PATTERNS=" ...; "SELFTEST=" ...; "SELFTEST_NEG=" ...; "SCANNED=... HITS=..."; ...'; the account and machine values are derived at run time and not recorded) +EXIT_CODE: 0 +Output Summary: +- PATTERNS=3 +- SELFTEST=1 +- SELFTEST_NEG=0 +- SCANNED=23 HITS=0 (at least 20: 19 Phase 0 .md artifacts, the projection and summary copies, issue.md and the plan) +- Hit listing: empty +- PRE-FIX-HITS: 0 diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t21-commit.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t21-commit.2026-09-28T20-01.md new file mode 100644 index 000000000..9cb9a4f71 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t21-commit.2026-09-28T20-01.md @@ -0,0 +1,23 @@ +# P0-T21 — Phase 0 evidence commit + +Timestamp: 2026-09-30T09-54 +Command: git add -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929; git commit -m "docs(929): phase 0 baseline evidence" -m "Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com" -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929; git rev-parse HEAD; git show --name-only --format= HEAD; git status --porcelain --untracked-files=all; git push origin bug/package-manifest-consistency-residuals-929 +EXIT_CODE: 0 +Output Summary: +- P0-HEAD: 488492f135c17c1ca4c8e6224bf7663a58c5e7b1 (differs from P0-START 481b33c594d8412cb64e604ff53295db215ac2f1) +- Commit: "[bug/package-manifest-consistency-residuals-929 488492f13] docs(929): phase 0 baseline evidence" — 23 files changed +- git show --name-only --format= HEAD: 23 paths, all under the feature folder (20 Phase 0 .md artifacts, the projection copy, the summary copy and the plan file with its check-offs); 0 paths outside it +- FORMAT-REWROTE-WRITE-SET at P0-T13 was none, so no Write Set member was committed and the plain message applies. +- Porcelain after the commit (only agent-memory entries, none of them staged or committed by this task): +``` + M .claude/agent-memory/atomic-executor/MEMORY.md + M .claude/agent-memory/atomic-planner/MEMORY.md +?? .claude/agent-memory/atomic-executor/index_csharp_nullable_and_component_gotchas.md +?? .claude/agent-memory/atomic-executor/index_pwsh_git_and_gate_mechanics_misc.md +?? .claude/agent-memory/atomic-executor/index_test_isolation_and_coverage.md +?? .claude/agent-memory/atomic-executor/project_hygiene_pattern_array_comma_precedence_and_regex_token_hits.md +?? .claude/agent-memory/atomic-planner/project_929_manifest_residuals_plan_seams.md +``` +- Push (per the caller's phase-boundary instruction): "481b33c59..488492f13 bug/package-manifest-consistency-residuals-929 -> bug/package-manifest-consistency-residuals-929" + +This artifact is written after the commit and is swept by the P1-T14 commit. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t3-sdk-bootstrap.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t3-sdk-bootstrap.2026-09-28T20-01.md new file mode 100644 index 000000000..a21cd3bc2 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t3-sdk-bootstrap.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P0-T3 — Repository-pinned .NET SDK bootstrap + +Timestamp: 2026-09-30T09-14 +Command: pwsh -NoProfile -Command 'Set-Location ""; if (-not (Test-Path ".dotnet-sdk\sdk")) { & ".\scripts\vscode\Install-RepoDotNetSdk.ps1" }; dotnet --version; dotnet --list-sdks' +EXIT_CODE: 0 +Output Summary: +- .dotnet-sdk\sdk was absent before the run (fresh worktree), so Install-RepoDotNetSdk.ps1 ran and printed "Installed repo-local .NET SDK 8.0.205 to \.dotnet-sdk." +- dotnet --version: 8.0.205 +- dotnet --list-sdks: + - 8.0.205 [\.dotnet-sdk\sdk] + - 10.0.401 [\dotnet\sdk] (machine-wide install) +- The 8.0.205 line names the sdk folder under the repository-root .dotnet-sdk folder (Install-RepoDotNetSdk.ps1 line 36, global.json line 7). diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t4-tool-restore.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t4-tool-restore.2026-09-28T20-01.md new file mode 100644 index 000000000..06104483e --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t4-tool-restore.2026-09-28T20-01.md @@ -0,0 +1,10 @@ +# P0-T4 — dotnet tool restore + +Timestamp: 2026-09-30T09-15 +Command: pwsh -NoProfile -Command 'Set-Location ""; dotnet tool restore; "TOOL_RESTORE_EXIT=$LASTEXITCODE"' +EXIT_CODE: 0 +Output Summary: +- "Tool 'csharpier' (version '1.2.6') was restored. Available commands: csharpier" +- "Restore was successful." +- TOOL_RESTORE_EXIT=0 +- csharpier 1.2.6 is the version the repository-root dotnet-tools.json pins. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t5-package-restore.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t5-package-restore.2026-09-28T20-01.md new file mode 100644 index 000000000..5865eec48 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t5-package-restore.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P0-T5 — Cold NuGet package restore + +Timestamp: 2026-09-30T09-16 +Command: pwsh -NoProfile -Command 'Set-Location ""; $before = @(Get-ChildItem -Path ".\packages" -Directory -ErrorAction SilentlyContinue).Count; "PACKAGE_DIRS_BEFORE=$before"; & ".\scripts\vscode\Invoke-Restore.ps1"; "RESTORE_EXIT=$LASTEXITCODE"; $after = @(Get-ChildItem -Path ".\packages" -Directory).Count; "PACKAGE_DIRS_AFTER=$after"; "ALTCOVER_RESTORED=" + (Test-Path "packages\altcover.8.6.45")' +EXIT_CODE: 0 +Output Summary: +- PACKAGE_DIRS_BEFORE=0 (fresh worktree; the cold state AC7 names) +- "Using MSBuild: \Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe" +- Restore target over TaskMaster.sln; output ends "Build succeeded." / "0 Warning(s)" / "0 Error(s)" / "Time Elapsed 00:00:02.75" +- RESTORE_EXIT=0 +- PACKAGE_DIRS_AFTER=172 (greater than 100 and not lower than PACKAGE_DIRS_BEFORE) +- ALTCOVER-RESTORED: False (no manifest declares altcover, so the restore did not produce packages\altcover.8.6.45) diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t6-analyzer-item-census.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t6-analyzer-item-census.2026-09-28T20-01.md new file mode 100644 index 000000000..1304e0025 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t6-analyzer-item-census.2026-09-28T20-01.md @@ -0,0 +1,15 @@ +# P0-T6 — Analyzer Include item census + +Timestamp: 2026-09-30T09-17 +Command: pwsh -NoProfile -Command 'Set-Location ""; $items = @(); foreach ($p in @(git ls-files -- "*.csproj")) { $dir = Split-Path -Parent $p; foreach ($line in (Get-Content -LiteralPath $p)) { if ($line -match "Analyzer Include=""([^""]+)""") { $rel = $Matches[1]; $items += [pscustomobject]@{ Project = $p; Item = $rel; Resolves = (Test-Path -LiteralPath (Join-Path $dir $rel)) } } } }; "ANALYZER_ITEMS=$($items.Count) FILES=$(@($items | Select-Object -ExpandProperty Project -Unique).Count) UNRESOLVED=$(@($items | Where-Object { -not $_.Resolves }).Count)"; "SKEW_235=" + @(git grep -n "Meziantou.Analyzer.3.0.235" -- "*.csproj").Count; $items | Where-Object { -not $_.Resolves } | ForEach-Object { $_.Project + " " + $_.Item }' +EXIT_CODE: 0 +Output Summary: +- ANALYZER_ITEMS=162 FILES=17 UNRESOLVED=0 +- SKEW_235=0 +- Unresolved (project, item) listing: empty + +ANALYZER-ITEM-STATE: aligned + +No back-fill was performed and none is permitted by this plan; the AC7 back-fill clause is not exercised. + +The packages tree is ignored at .gitignore line 197 (`**/[Pp]ackages/*`), and the restore of P0-T5 is the only step that populated it (PACKAGE_DIRS_BEFORE=0, PACKAGE_DIRS_AFTER=172). Decision D8 governs. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t7-dotnet-coverage.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t7-dotnet-coverage.2026-09-28T20-01.md new file mode 100644 index 000000000..96b1ae53c --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t7-dotnet-coverage.2026-09-28T20-01.md @@ -0,0 +1,8 @@ +# P0-T7 — dotnet-coverage global tool + +Timestamp: 2026-09-30T09-18 +Command: pwsh -NoProfile -Command 'Set-Location ""; if (-not (Get-Command dotnet-coverage -ErrorAction SilentlyContinue)) { dotnet tool install --global dotnet-coverage }; (Get-Command dotnet-coverage).Source' +EXIT_CODE: 0 +Output Summary: +- Get-Command resolved dotnet-coverage to \.dotnet\tools\dotnet-coverage.exe (already installed; no install was run). +- The coverage runner's absent-tool guard (Invoke-MSTestWithCoverage.ps1 lines 344 to 346) will not throw. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t8-pester-provision.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t8-pester-provision.2026-09-28T20-01.md new file mode 100644 index 000000000..085289778 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t8-pester-provision.2026-09-28T20-01.md @@ -0,0 +1,17 @@ +# P0-T8 — Pester provisioning (N/A, read-only listing) + +Timestamp: 2026-09-30T09-18 +Command: pwsh -NoProfile -Command 'Set-Location ""; Get-Module Pester -ListAvailable | Select-Object Name,Version | Format-Table -AutoSize | Out-String' +EXIT_CODE: 0 +Output Summary: +``` +Name Version +---- ------- +Pester 5.6.1 +Pester 3.4.0 +``` +N/A: no raw Pester invocation in this plan; the MCP test route supplies its own Pester + +GATE-SUBSTITUTION: Pester provisioning replaced by the PoshQC MCP test route + +No Install-Module was run. The listing carries no expectation and is recorded as measured. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t9-csharpier-check.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t9-csharpier-check.2026-09-28T20-01.md new file mode 100644 index 000000000..2b4d4a77d --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t9-csharpier-check.2026-09-28T20-01.md @@ -0,0 +1,18 @@ +# P0-T9 — C# formatter baseline (CMD-CSHARPIER-CHECK) + +Timestamp: 2026-09-30T09-19 +Command: pwsh -NoProfile -Command 'Set-Location ""; dotnet tool run csharpier check .; "CSHARPIER_EXIT=$LASTEXITCODE"' followed by the CMD-CSHARPIER-CHECK XML-candidate companion command +EXIT_CODE: 0 +Output Summary: +- "Checked 1625 files in 7451ms." +- CSHARPIER_EXIT=0 +- N = 1625 (greater than 900) + +CSHARPIER-FINDINGS: none + +XML-CANDIDATES: 3 +``` +artifacts\pester\pester-junit.xml +artifacts\pester\powershell-coverage.koverage.xml +artifacts\pester\powershell-coverage.xml +``` diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/phase0-instructions-read.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/phase0-instructions-read.2026-09-28T20-01.md new file mode 100644 index 000000000..92d66cff6 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/phase0-instructions-read.2026-09-28T20-01.md @@ -0,0 +1,28 @@ +# P0-T2 — Phase 0 instructions read + +Timestamp: 2026-09-30T09-12 +Command: Read each file below in order from ; line counts by pwsh -NoProfile -Command '@(Get-Content -LiteralPath ).Count' +EXIT_CODE: 0 +Policy Order: CLAUDE.md, then .claude/rules/general-code-change.md, then .claude/rules/general-unit-test.md, then the language- and domain-specific rules (powershell, csharp, quality-tiers, tonality, ci-workflows, plan-acceptance-gates), then the three skills, as fixed by the policy-compliance-order skill. + +Files read (in order, with line counts): + +1. CLAUDE.md — 463 lines +2. .claude/rules/general-code-change.md — 80 lines +3. .claude/rules/general-unit-test.md — 105 lines +4. .claude/rules/powershell.md — 97 lines +5. .claude/rules/csharp.md — 96 lines +6. .claude/rules/quality-tiers.md — 51 lines +7. .claude/rules/tonality.md — 80 lines +8. .claude/rules/ci-workflows.md — 42 lines +9. .claude/rules/plan-acceptance-gates.md — 257 lines +10. .claude/skills/atomic-plan-contract/SKILL.md — 245 lines +11. .claude/skills/evidence-and-timestamp-conventions/SKILL.md — 176 lines +12. .claude/skills/acceptance-criteria-tracking/SKILL.md — 104 lines + +Output Summary: +- Twelve files read in the order above, each with a non-zero line count. +- issue.md line 12 reads `- Work Mode: minor-audit`. +- issue.md carries the heading `## Acceptance Criteria` (line 40) with exactly 7 lines matching `^- \[ \] AC\d+:` beneath it (AC1 to AC7, lines 44 to 50). +- No spec.md, user-story.md or research.md exists in the feature folder (Test-Path False for each). +- Coverage-floor conflict (convention 10): CLAUDE.md states an 80 percent PowerShell and C# line floor and a four-step toolchain loop; .claude/rules/general-unit-test.md, .claude/rules/quality-tiers.md and .claude/rules/powershell.md state 85 percent and a seven-stage loop. This plan gates on CLAUDE.md and records MEETS-85 as an observation only. The conflict is tracked as open GitHub issue 668. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/other/p2-t19-maintainer-followup.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/other/p2-t19-maintainer-followup.2026-09-28T20-01.md new file mode 100644 index 000000000..9f107d665 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/other/p2-t19-maintainer-followup.2026-09-28T20-01.md @@ -0,0 +1,15 @@ +# P2-T19 — Maintainer follow-up record (issue 929 Summary item 4) + +Timestamp: 2026-09-30T11-18 +Command: pwsh -NoProfile -Command 'Set-Location ""; "DEFERRED_UNCHECKED=" + @(Select-String -Path "docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/spec.md" -Pattern "^- \[ \] \*\*AC(18|19|20) ").Count' +EXIT_CODE: 0 +Output Summary: +- DEFERRED_UNCHECKED=3 (AC18, AC19 and AC20 remain unchecked in the 911 spec; this plan changed nothing there) + +This item is not an acceptance criterion and not a merge gate. + +- Acceptance criteria AC18, AC19 and AC20 of issue 911 remain deferred to the maintainer until a GitHub App credential is provisioned. Nothing in this change marks them passed. +- The secret store remains unconfirmed: whether the Dependabot-triggered workflow_run that runs .github/workflows/dependabot-repair.yml reads repository Actions secrets or only Dependabot secrets is for the maintainer to confirm. +- After this change merges, the secret named DEPENDABOT_REPAIR_APP_ID must hold the App's Client ID, not the numeric App ID: the workflow now passes that secret as the client-id input of actions/create-github-app-token. The private key stays in DEPENDABOT_REPAIR_APP_PRIVATE_KEY. +- Runbook: docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md (Part B step 10 and Part D step 22 now instruct storing the Client ID). +- Spec: docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/spec.md (AC18 to AC20). diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/other/p2-t21-reduced-audit-handoff.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/other/p2-t21-reduced-audit-handoff.2026-09-28T20-01.md new file mode 100644 index 000000000..eac7c9e04 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/other/p2-t21-reduced-audit-handoff.2026-09-28T20-01.md @@ -0,0 +1,153 @@ +# P2-T21 — Reduced-audit handoff index (issue 929) + +Timestamp: 2026-09-30T11-22 +Command: Enumerate the evidence tree with each artifact's first EXIT_CODE line; CMD-HYGIENE over the feature folder; pwsh -NoProfile -Command 'Set-Location ""; & ".\scripts\hygiene\Test-RepositoryHygiene.ps1"; "GUARD_EXIT=$LASTEXITCODE"' +EXIT_CODE: 0 +Output Summary: index of the 61 evidence .md artifacts produced before this one, the committed coverage copies, the commits, the CI runs, the observations the plan requires to be carried forward, and the pre-commit hygiene and CI hygiene-guard results (appended below). + +## Anchors (P0-T1) + +- BASE-SHA: 231e1c0b55105aeb626bf5a6e8d0266a567cacad +- P0-START: 481b33c594d8412cb64e604ff53295db215ac2f1 +- MERGED-MAIN-ANCESTOR: 0 + +## Commits + +| Task | SHA | Message | Pushed | +|---|---|---|---| +| P0-T21 | 488492f135c17c1ca4c8e6224bf7663a58c5e7b1 | docs(929): phase 0 baseline evidence | yes | +| P1-T14 | b96926588d562f994430e7ba7301de5de86f206c | fix(929): remove altcover imports, correct SVGControl redirects, pass client-id to the token action | yes | +| P2-T20 | 9e41ffbcf069b1b4f0aa7fe8e5eab2483c561530 | docs(929): final QC evidence, coverage projection and acceptance check-off | yes | + +No P2-T1 formatter commit and no P2-T2 repair commit was made in either iteration (the formatter rewrote nothing and the analyzer reported ok true). + +P2-T20 commit transcription (the P2-T20 artifact is inside that commit): +- Head: 9e41ffbcf069b1b4f0aa7fe8e5eab2483c561530 +- git show --name-only --format= HEAD: 32 paths, all under the feature folder, including evidence/qa-gates/p2-t20-ac-status-summary.2026-09-28T20-01.md, evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml, evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt, issue.md and the plan +- Porcelain after the commit: only agent-memory entries (the two modified MEMORY.md files and five untracked agent-memory notes) + +## Fail-before / pass-after pair + +- Fail-before: evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md (RepositoryTreeConsistency.Tests.ps1 tests=4 failures=4; EXIT_CODE 1, ExpectedExitCode 1) +- Pass-after: evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md (tests=4 failures=0; root 137 failures 0) + +## Committed coverage evidence copies + +- Baseline: evidence/baseline/p0-t12-coverage-projection.2026-09-28T20-01.jacoco.xml and evidence/baseline/p0-t12-test-results.2026-09-28T20-01.summary.txt +- Final: evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml and evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt +- All four are package-level projections or trx-derived summaries; no raw document is committed. + +## CI runs + +| Purpose | Run id | Head SHA | Pester job | Pester conclusion | Run conclusion | +|---|---|---|---|---|---| +| Baseline (P0-T16) | 36666302259 | 231e1c0b55105aeb626bf5a6e8d0266a567cacad (main) | 109731601928 | success | success | +| Branch (P2-T3) | 36722780748 | b96926588d562f994430e7ba7301de5de86f206c | 109911885533 | success | failure (mstest-coverage job only: 1 of 7346 failed, Transaction_SecondCallerCannotInstallUntilTheFirstRestores) | + +## Carried-forward observations + +- ANALYZER-ITEM-STATE: aligned (P0-T6) +- MEETS-85 observations: P0-T12 true (C# line 85.91); P0-T16 true (PowerShell 94.51); P2-T3 true (PowerShell 94.51, both iterations); P2-T7 true (C# line 85.92, iteration 2). Convention 10 conflict (CLAUDE.md 80 percent versus the rules' 85 percent) is tracked as open issue 668. +- OUT-OF-SCOPE-RESIDUAL (P0-T18): eleven app.config files other than SVGControl and UtilitiesCS redirect Fizzler to 1.3.0.0 (QuickFiler, QuickFiler.Test, SVGControl.Test, Tags, TaskMaster, TaskTree, TaskVisualization, TaskVisualization.Test, ToDoModel, ToDoModel.Test, UtilitiesCS.Test); recorded in docs/features/potential/2026-08-04-stale-fizzler-and-unsafe-binding-redirects.md. +- CSHARPIER-COUNTS-IGNORED-XML: false (P2-T4, both iterations) +- P1-T13: no potential entry authored; coordinator ruling 2026-09-30 +- Maintainer follow-up (P2-T19): AC18 to AC20 of issue 911 remain deferred; the secret store is unconfirmed; DEPENDABOT_REPAIR_APP_ID must now hold the App's Client ID. Not an acceptance criterion and not a merge gate. + +## GATE-SUBSTITUTION lines carried by the artifacts + +- P0-T8: Pester provisioning replaced by the PoshQC MCP test route +- P0-T14, P2-T2 (iter1, iter2): PoshQC analyze ok flag stands in for a diagnostic count +- P0-T15, P1-T2, P1-T3, P1-T7, P1-T11: JUnit per-file counts stand in for a direct Pester run +- P0-T16: CI Pester job 109731601928 stands in for a local coverage run +- P2-T3 (iter1, iter2): CI Pester job on the pushed head stands in for a local coverage run + +## Final QC loop iterations + +- Iteration 1: P2-T1 to P2-T6 passed; P2-T7 failed (1 of 7346, RemainingLoadActive_AcrossAsyncVoidFirstAwait_StaysTrueWhileLoaderProduces in QuickFiler.Test/Controllers/QfcDatamodelLivenessTests.cs, a five-second wait that did not complete). +- Iteration 2: P2-T1 to P2-T7 passed on the unchanged tree; P2-T8 attests iteration 2. + +## AC status summary + +- Source: issue.md `## Acceptance Criteria`; Total 7; Checked off 7; Remaining 0. + +## Evidence artifacts (path relative to the feature folder | task | EXIT_CODE) + +| Path | Task | EXIT_CODE | +|---|---|---| +| evidence/baseline/p0-t1-worktree-anchor.2026-09-28T20-01.md | P0-T1 | 0 | +| evidence/baseline/phase0-instructions-read.2026-09-28T20-01.md | P0-T2 | 0 | +| evidence/baseline/p0-t3-sdk-bootstrap.2026-09-28T20-01.md | P0-T3 | 0 | +| evidence/baseline/p0-t4-tool-restore.2026-09-28T20-01.md | P0-T4 | 0 | +| evidence/baseline/p0-t5-package-restore.2026-09-28T20-01.md | P0-T5 | 0 | +| evidence/baseline/p0-t6-analyzer-item-census.2026-09-28T20-01.md | P0-T6 | 0 | +| evidence/baseline/p0-t7-dotnet-coverage.2026-09-28T20-01.md | P0-T7 | 0 | +| evidence/baseline/p0-t8-pester-provision.2026-09-28T20-01.md | P0-T8 | 0 | +| evidence/baseline/p0-t9-csharpier-check.2026-09-28T20-01.md | P0-T9 | 0 | +| evidence/baseline/p0-t10-msbuild-analyzers.2026-09-28T20-01.md | P0-T10 | 0 | +| evidence/baseline/p0-t11-msbuild-nullable.2026-09-28T20-01.md | P0-T11 | 0 | +| evidence/baseline/p0-t12-mstest-coverage.2026-09-28T20-01.md | P0-T12 | 0 | +| evidence/baseline/p0-t13-poshqc-format.2026-09-28T20-01.md | P0-T13 | 0 | +| evidence/baseline/p0-t14-poshqc-analyze.2026-09-28T20-01.md | P0-T14 | 0 | +| evidence/baseline/p0-t15-poshqc-test-mcp.2026-09-28T20-01.md | P0-T15 | 0 | +| evidence/baseline/p0-t16-pester.2026-09-28T20-01.md | P0-T16 | 0 | +| evidence/baseline/p0-t17-altcover-and-verifier-prefix.2026-09-28T20-01.md | P0-T17 | 0 | +| evidence/baseline/p0-t18-redirect-prefix.2026-09-28T20-01.md | P0-T18 | 0 | +| evidence/baseline/p0-t19-workflow-prefix-and-actionlint.2026-09-28T20-01.md | P0-T19 | 0 | +| evidence/baseline/p0-t20-hygiene.2026-09-28T20-01.md | P0-T20 | 0 | +| evidence/baseline/p0-t21-commit.2026-09-28T20-01.md | P0-T21 | 0 | +| evidence/regression-testing/p1-t1-tree-test-authored.2026-09-28T20-01.md | P1-T1 | 0 | +| evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md | P1-T2 | 1 (expected 1) | +| evidence/regression-testing/p1-t3-verifier-import-tests.2026-09-28T20-01.md | P1-T3 | 1 (expected 1) | +| evidence/qa-gates/p1-t4-altcover-imports-removed.2026-09-28T20-01.md | P1-T4 | 0 | +| evidence/qa-gates/p1-t5-redirects-fixed.2026-09-28T20-01.md | P1-T5 | 0 | +| evidence/qa-gates/p1-t6-workflow-client-id.2026-09-28T20-01.md | P1-T6 | 0 | +| evidence/qa-gates/p1-t7-actionlint.2026-09-28T20-01.md | P1-T7 | 1 (expected 1) | +| evidence/qa-gates/p1-t8-runbook-client-id.2026-09-28T20-01.md | P1-T8 | 0 | +| evidence/qa-gates/p1-t9-readme-client-id.2026-09-28T20-01.md | P1-T9 | 0 | +| evidence/qa-gates/p1-t10-verifier-comment.2026-09-28T20-01.md | P1-T10 | 0 | +| evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md | P1-T11 | 0 | +| evidence/qa-gates/p1-t12-verifier-postfix.2026-09-28T20-01.md | P1-T12 | 0 | +| evidence/qa-gates/p1-t14-commit.2026-09-28T20-01.md | P1-T14 | 0 | +| evidence/qa-gates/p2-t1-poshqc-format.iter1.2026-09-28T20-01.md | P2-T1 iter1 | 0 | +| evidence/qa-gates/p2-t2-poshqc-analyze.iter1.2026-09-28T20-01.md | P2-T2 iter1 | 0 | +| evidence/qa-gates/p2-t3-pester.iter1.2026-09-28T20-01.md | P2-T3 iter1 | 0 | +| evidence/qa-gates/p2-t4-csharpier-check.iter1.2026-09-28T20-01.md | P2-T4 iter1 | 0 | +| evidence/qa-gates/p2-t5-msbuild-analyzers.iter1.2026-09-28T20-01.md | P2-T5 iter1 | 0 | +| evidence/qa-gates/p2-t6-msbuild-nullable.iter1.2026-09-28T20-01.md | P2-T6 iter1 | 0 | +| evidence/qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md | P2-T7 iter1 | 1 (failed; loop restarted) | +| evidence/qa-gates/p2-t1-poshqc-format.iter2.2026-09-28T20-01.md | P2-T1 iter2 | 0 | +| evidence/qa-gates/p2-t2-poshqc-analyze.iter2.2026-09-28T20-01.md | P2-T2 iter2 | 0 | +| evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md | P2-T3 iter2 | 0 | +| evidence/qa-gates/p2-t4-csharpier-check.iter2.2026-09-28T20-01.md | P2-T4 iter2 | 0 | +| evidence/qa-gates/p2-t5-msbuild-analyzers.iter2.2026-09-28T20-01.md | P2-T5 iter2 | 0 | +| evidence/qa-gates/p2-t6-msbuild-nullable.iter2.2026-09-28T20-01.md | P2-T6 iter2 | 0 | +| evidence/qa-gates/p2-t7-mstest-coverage.iter2.2026-09-28T20-01.md | P2-T7 iter2 | 0 | +| evidence/qa-gates/p2-t8-attestation-and-coverage-delta.2026-09-28T20-01.md | P2-T8 | 0 | +| evidence/qa-gates/p2-t9-file-size-audit.2026-09-28T20-01.md | P2-T9 | 0 | +| evidence/qa-gates/p2-t10-change-footprint.2026-09-28T20-01.md | P2-T10 | 0 | +| evidence/qa-gates/p2-t11-hygiene.2026-09-28T20-01.md | P2-T11 | 0 | +| evidence/qa-gates/p2-t12-ac1-checkoff.2026-09-28T20-01.md | P2-T12 | 0 | +| evidence/qa-gates/p2-t13-ac2-checkoff.2026-09-28T20-01.md | P2-T13 | 0 | +| evidence/qa-gates/p2-t14-ac3-checkoff.2026-09-28T20-01.md | P2-T14 | 0 | +| evidence/qa-gates/p2-t15-ac4-checkoff.2026-09-28T20-01.md | P2-T15 | 0 | +| evidence/qa-gates/p2-t16-ac5-checkoff.2026-09-28T20-01.md | P2-T16 | 0 | +| evidence/qa-gates/p2-t17-ac6-checkoff.2026-09-28T20-01.md | P2-T17 | 0 | +| evidence/qa-gates/p2-t18-ac7-checkoff.2026-09-28T20-01.md | P2-T18 | 0 | +| evidence/other/p2-t19-maintainer-followup.2026-09-28T20-01.md | P2-T19 | 0 | +| evidence/qa-gates/p2-t20-ac-status-summary.2026-09-28T20-01.md | P2-T20 | 0 | + +Artifact count listed: 61 evidence .md files (at least 54), each present on disk at the time of this index. + +## Pre-commit checks + +CMD-HYGIENE over the feature folder: +- PATTERNS=3 +- SELFTEST=1 +- SELFTEST_NEG=0 +- SCANNED=68 +- HITS=0 +- PRE-FIX-HITS: 0 + +CI hygiene guard run locally (scripts/hygiene/Test-RepositoryHygiene.ps1 over every tracked file): +- HYGIENE Findings=0 +- GUARD_EXIT=0 diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t10-verifier-comment.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t10-verifier-comment.2026-09-28T20-01.md new file mode 100644 index 000000000..8d4f15e73 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t10-verifier-comment.2026-09-28T20-01.md @@ -0,0 +1,14 @@ +# P1-T10 — Verifier comment updated, line count held + +Timestamp: 2026-09-30T10-15 +Command: Edit scripts/dependencies/ConsistencyVerifier.psm1 lines 221 to 223; pwsh -NoProfile -Command 'Set-Location ""; "LINES=" + @(Get-Content -LiteralPath "scripts/dependencies/ConsistencyVerifier.psm1").Count; "LIVE=" + ...; "I929=" + ...; "NUMSTAT=" + (git diff --numstat 488492f135c17c1ca4c8e6224bf7663a58c5e7b1 -- scripts/dependencies/ConsistencyVerifier.psm1)' +EXIT_CODE: 0 +Output Summary: +- Replacement (three lines for three lines, same indentation): + - ` Issue 929 removed the last live instance, two Exists() guarded elements in` + - ` QuickFiler.Test naming an altcover package no manifest declared; the shape survives as` + - ` an in-memory test fixture. No exception is hard-coded for any package identifier.` +- LINES=499 (equals VERIFIER-LINES 499 from P0-T13; at most 500) +- LIVE=0 +- I929=1 +- NUMSTAT=3 3 scripts/dependencies/ConsistencyVerifier.psm1 (against P0-HEAD 488492f13) diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t12-verifier-postfix.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t12-verifier-postfix.2026-09-28T20-01.md new file mode 100644 index 000000000..de034b384 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t12-verifier-postfix.2026-09-28T20-01.md @@ -0,0 +1,13 @@ +# P1-T12 — Read-only verifier run on the fixed tree (CMD-VERIFIER-WHATIF) + +Timestamp: 2026-09-30T10-18 +Command: CMD-VERIFIER-WHATIF (pwsh -NoProfile -Command 'Set-Location ""; $files = @(Get-ChildItem -Path "*/packages.config","*/app.config","*/*.csproj" -File); ...; $r = & ".\scripts\dependencies\Repair-PackageManifestConsistency.ps1" -WhatIf; ...') +EXIT_CODE: 0 +Output Summary: +- Result line: ABSENT=0 DISAGREE=0 WRITTEN=0 SUCCESS=True PROJECTS=18 FILES=53 HASHES_EQUAL=True +- ABSENT=0 (P0-T17 measured 2) +- WRITTEN=0; HASHES_EQUAL=True (nothing written) +- PROJECTS=18; FILES=53 (equal to the P0-T17 value) +- DISAGREE=0 (equal to the P0-T17 value; this change moves no version); SUCCESS=True (recorded as measured) +- Information line (printed five times): "Manifest discovery: enumerated directories 35, returned files 53" +- -WhatIf messages: the same 17 "Rewrite in canonical inline form" targets P0-T17 recorded, each \\packages.config for QuickFiler.Test, QuickFiler, SVGControl.Test, Tags.Test, Tags, TaskMaster.Test, TaskMaster, TaskTree.Test, TaskTree, TaskVisualization.Test, TaskVisualization, ToDoModel.Test, ToDoModel, UtilitiesCS.Test, UtilitiesCS, VBFunctions.Test and VBFunctions. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t14-commit.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t14-commit.2026-09-28T20-01.md new file mode 100644 index 000000000..36c7a2f36 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t14-commit.2026-09-28T20-01.md @@ -0,0 +1,22 @@ +# P1-T14 — Hygiene scan, implementation commit and push + +Timestamp: 2026-09-30T10-21 +Command: CMD-HYGIENE with FOLDER-LIST "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929","tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1",".github/workflows/dependabot-repair.yml",".github/workflows/README.md","docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md","scripts/dependencies/ConsistencyVerifier.psm1","tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1"; @(Get-Content).Count per non-Markdown Write Set file; git add -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929; git commit -m "fix(929): remove altcover imports, correct SVGControl redirects, pass client-id to the token action" -m "Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com"; git push origin bug/package-manifest-consistency-residuals-929; git rev-parse HEAD; git show --name-only --format= HEAD; git status --porcelain --untracked-files=all; git ls-remote --heads origin bug/package-manifest-consistency-residuals-929 +EXIT_CODE: 0 +Output Summary: +- Pre-commit hygiene: PATTERNS=3 SELFTEST=1 SELFTEST_NEG=0 SCANNED=43 HITS=0 +- PRE-FIX-HITS: 0 +- Line counts of the non-Markdown Write Set files (each at most 500): + - QuickFiler.Test/QuickFiler.Test.csproj 568 + - SVGControl/app.config 23 + - .github/workflows/dependabot-repair.yml 173 + - scripts/dependencies/ConsistencyVerifier.psm1 499 (equals VERIFIER-LINES) + - tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 337 + - tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 152 +- Commit: "[bug/package-manifest-consistency-residuals-929 b96926588] fix(929): remove altcover imports, correct SVGControl redirects, pass client-id to the token action" — 22 files changed +- Recorded head: b96926588d562f994430e7ba7301de5de86f206c (differs from P0-HEAD 488492f13) +- git show --name-only --format= HEAD: 22 paths — the eight non-feature-folder Write Set paths (.github/workflows/README.md, .github/workflows/dependabot-repair.yml, QuickFiler.Test/QuickFiler.Test.csproj, SVGControl/app.config, the 911 runbook, scripts/dependencies/ConsistencyVerifier.psm1, tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1, tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1) plus 14 paths under the feature folder (the P0-T21 artifact, twelve Phase 1 artifacts P1-T1 to P1-T12 and the plan) +- Porcelain after the commit: only agent-memory entries (2 modified MEMORY.md files and 5 untracked agent-memory notes), none staged or committed +- Push: "488492f13..b96926588 bug/package-manifest-consistency-residuals-929 -> bug/package-manifest-consistency-residuals-929" (exit 0) +- PUSHED-HEAD: b96926588d562f994430e7ba7301de5de86f206c refs/heads/bug/package-manifest-consistency-residuals-929 (names the recorded head) +- The push starts no CI run by itself (ci.yml lines 3 to 8); P2-T3 dispatches one. The pre-implementation hook accepted the commit of source paths; the executor did not create or edit the orchestrator checkpoint. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t4-altcover-imports-removed.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t4-altcover-imports-removed.2026-09-28T20-01.md new file mode 100644 index 000000000..d9dc2cb7f --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t4-altcover-imports-removed.2026-09-28T20-01.md @@ -0,0 +1,13 @@ +# P1-T4 — altcover Import elements removed + +Timestamp: 2026-09-30T10-06 +Command: Edit QuickFiler.Test/QuickFiler.Test.csproj (delete the two altcover Import lines); pwsh -NoProfile -Command 'Set-Location ""; "NUMSTAT=" + (git diff --numstat 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- QuickFiler.Test/QuickFiler.Test.csproj); "LINES=" + @(Get-Content QuickFiler.Test/QuickFiler.Test.csproj).Count; "ALTCOVER_LINES=" + @(git grep -i -n altcover -- "*.csproj" "*/packages.config").Count'; git diff 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- QuickFiler.Test/QuickFiler.Test.csproj +EXIT_CODE: 0 +Output Summary: +- NUMSTAT=0 2 QuickFiler.Test/QuickFiler.Test.csproj (0 added, 2 deleted) +- LINES=568 (570 minus 2) +- ALTCOVER_LINES=0 (P0-T17 measured 2 over the same pathspec) +- Deleted lines, verbatim from git diff -- QuickFiler.Test/QuickFiler.Test.csproj: + - `- ` (hunk @@ -5,7 +5,6 @@) + - `- ` (hunk @@ -534,7 +533,6 @@) +- No other change to the file. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t5-redirects-fixed.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t5-redirects-fixed.2026-09-28T20-01.md new file mode 100644 index 000000000..3d7c74b08 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t5-redirects-fixed.2026-09-28T20-01.md @@ -0,0 +1,13 @@ +# P1-T5 — SVGControl binding redirects corrected + +Timestamp: 2026-09-30T10-07 +Command: Edit SVGControl/app.config lines 15 and 19; git diff --numstat 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- SVGControl/app.config; git diff 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- SVGControl/app.config; CMD-REDIRECT-OBSERVE (all in one pwsh invocation beginning with Set-Location "") +EXIT_CODE: 0 +Output Summary: +- NUMSTAT=2 2 SVGControl/app.config (2 added, 2 deleted) +- New lines, verbatim from git diff -- SVGControl/app.config (hunk @@ -12,11 +12,11 @@): + - line 15: `+ ` + - line 19: `+ ` +- Indentation unchanged; the edit touched only the two bindingRedirect lines. +- FIZZLER_REPAIRS=0 UNSAFE_REPAIRS=0 EXAMINED=4 (P0-T18 measured 1, 1 and 4 on the same command) +- The Fizzler value 1.3.1.0 equals FIZZLER_ASM and the Unsafe value 6.0.3.0 equals UNSAFE_ASM from P0-T18. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t6-workflow-client-id.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t6-workflow-client-id.2026-09-28T20-01.md new file mode 100644 index 000000000..8c9bcf08d --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t6-workflow-client-id.2026-09-28T20-01.md @@ -0,0 +1,22 @@ +# P1-T6 — Repair workflow passes client-id + +Timestamp: 2026-09-30T10-09 +Command: Edit .github/workflows/dependabot-repair.yml lines 13, 14 and 51; pwsh -NoProfile -Command 'Set-Location ""; $w = Get-Content ".github/workflows/dependabot-repair.yml"; "WF_APPID=" + ...; "WF_CLIENTID=" + ...; "WF_SECRET=" + ...; "NUMSTAT=" + (git diff --numstat 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- .github/workflows/dependabot-repair.yml)'; git diff 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- .github/workflows/dependabot-repair.yml +EXIT_CODE: 0 +Output Summary: +- WF_APPID=0 +- WF_CLIENTID=1 +- WF_SECRET=1 (the secret name DEPENDABOT_REPAIR_APP_ID is unchanged, decision D3) +- NUMSTAT=3 3 .github/workflows/dependabot-repair.yml (at most 3 added and 3 deleted) +- Diff hunks, verbatim (lines 13, 14 and 51 only): + +``` +@@ -10,8 +10,8 @@ name: dependabot-repair +-# Credential: a GitHub App installation token minted from DEPENDABOT_REPAIR_APP_ID and +-# DEPENDABOT_REPAIR_APP_PRIVATE_KEY. When those secrets are absent the token step fails, the job ++# Credential: a GitHub App installation token minted from the App's Client ID, stored in ++# DEPENDABOT_REPAIR_APP_ID, and the private key in DEPENDABOT_REPAIR_APP_PRIVATE_KEY. When those secrets are absent the token step fails, the job +@@ -48,7 +48,7 @@ jobs: +- app-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }} ++ client-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }} +``` diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t7-actionlint.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t7-actionlint.2026-09-28T20-01.md new file mode 100644 index 000000000..34aa2fbc7 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t7-actionlint.2026-09-28T20-01.md @@ -0,0 +1,22 @@ +# P1-T7 — actionlint after the workflow edit, and the intermediate test state + +Timestamp: 2026-09-30T10-11 +Command: CMD-ACTIONLINT; RUN-START captured in the same pwsh invocation with [DateTime]::UtcNow.ToString("o"); MCP mcp__drm-copilot__run_poshqc_test (workspace_root , scan_folders ["tests/scripts/dependencies"]); CMD-JUNIT-READ +EXIT_CODE: 1 +ExpectedExitCode: 1 +Output Summary: +- actionlint version line: "1.7.7" +- Scoped lint of .github/workflows/dependabot-repair.yml: no output; SCOPED_EXIT=0 +- Repository-wide run-actionlint.ps1: no output; REPO_EXIT=0 +- RUN-START: 2026-09-30T13:27:50.9467135Z +- MCP payload (host prefix replaced): {"ok": false, "tool": "run_poshqc_test", "workspace_root": "", "summary": "Command exited with code 1."} +- JUNIT-WRITTEN=2026-09-30T13:28:21.7740649Z (later than RUN-START) +- JUNIT-ROOT tests=137 failures=1 errors=0 disabled=0 +- JUNIT-SUITE DependabotConfig.Tests.ps1 tests=17 failures=0 skipped=0 (the existing workflow static tests still hold after the edit) +- JUNIT-SUITE RepositoryTreeConsistency.Tests.ps1 tests=4 failures=1 skipped=0 +- Other suites at failures=0: AnalyzerItemRepair 13, ConsistencyVerifier 14, PackageCompatibility 8, PackageGraph 32, ProjectConsistency 18, Repair-PackageManifestConsistency 31 +- JUNIT-NOTPASSED Repository tree consistency (issue 929).instructs the maintainer to store the Client ID in the secret the repair workflow reads by name +- JUNIT-MESSAGE Expected 1, because the runbook sample must pass client-id from secrets.DEPENDABOT_REPAIR_APP_ID, but got 0. +- Tests 1 to 3 now pass after P1-T4 to P1-T6; test 4 (the runbook secret-name test) still reproduces its defect until P1-T8 (decision D13). + +GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t8-runbook-client-id.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t8-runbook-client-id.2026-09-28T20-01.md new file mode 100644 index 000000000..2241b69ee --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t8-runbook-client-id.2026-09-28T20-01.md @@ -0,0 +1,37 @@ +# P1-T8 — Runbook instructs storing the Client ID + +Timestamp: 2026-09-30T10-13 +Command: Edit docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md (Part B heading, step 10, step 22, YAML sample line 154); the P1-T8 pwsh measurement command verbatim; git diff 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- +EXIT_CODE: 0 +Output Summary: +- RB_APPID=0 +- RB_CLIENTID=1 +- RB_SECRET=2 (step 22 and the YAML sample; at least 2) +- RB_PARTB=0 (a search for "Record the App ID" returns 0 lines; P0-T19 measured 1) +- PARTD_CLIENTID=2 (at least 1) +- The citations at lines 301 and 318 were not edited. + +Diff hunks against , verbatim: +``` +@@ -96,13 +96,13 @@ permissions listed in step 6 below and skip to step 10. +-### Part B — Record the App ID and generate a private key ++### Part B — Record the Client ID and generate a private key +-10. On the App's settings page that appears after creation, locate the **App ID** in the "About" +- section near the top of the page and record it. The adjacent **Client ID** is also shown; record +- it as well, because the `actions/create-github-app-token` action now documents `client-id` as +- the recommended input and continues to accept the legacy `app-id` input. Neither value is a +- secret in the cryptographic sense, but this runbook stores the App ID as a repository secret to ++10. On the App's settings page that appears after creation, locate the **Client ID** in the "About" ++ section near the top of the page and record it. The numeric **App ID** shown beside it is not ++ needed: the repair workflow passes the Client ID to the `actions/create-github-app-token` action ++ as its `client-id` input, which the action documents as the recommended input. The Client ID is ++ not a secret in the cryptographic sense, but this runbook stores it as a repository secret to +@@ -126,9 +126,9 @@ permissions listed in step 6 below and skip to step 10. +-22. Create the App ID secret: ++22. Create the Client ID secret: +- - **Secret** — the App ID value recorded in step 10 ++ - **Secret** — the Client ID value recorded in step 10 +@@ -151,7 +151,7 @@ permissions listed in step 6 below and skip to step 10. +- app-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }} ++ client-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }} +``` diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t9-readme-client-id.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t9-readme-client-id.2026-09-28T20-01.md new file mode 100644 index 000000000..3061b8f4b --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t9-readme-client-id.2026-09-28T20-01.md @@ -0,0 +1,13 @@ +# P1-T9 — Workflows README secret row names the Client ID + +Timestamp: 2026-09-30T10-14 +Command: Edit .github/workflows/README.md line 116; pwsh -NoProfile -Command 'Set-Location ""; $r = Get-Content ".github/workflows/README.md"; "README_NUMERIC=" + ...; "README_CLIENTID=" + ...; "NUMSTAT=" + (git diff --numstat 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- .github/workflows/README.md)'; git diff 231e1c0b55105aeb626bf5a6e8d0266a567cacad -- .github/workflows/README.md +EXIT_CODE: 0 +Output Summary: +- README_NUMERIC=0 (P0-T19 measured 1) +- README_CLIENTID=1 (at least 1) +- NUMSTAT=1 1 .github/workflows/README.md (1 added, 1 deleted) +- Diff (hunk @@ -113,7 +113,7 @@): + - `-| `DEPENDABOT_REPAIR_APP_ID` | the numeric App identifier |` + - `+| `DEPENDABOT_REPAIR_APP_ID` | the App's Client ID, passed to the token action's `client-id` input (the numeric App ID is not stored) |` +- The table shape is unchanged and the edit introduces no backticked three-part version literal (the AC26 test in DependabotConfig.Tests.ps1 reads every such literal in this file). diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter1.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter1.2026-09-28T20-01.md new file mode 100644 index 000000000..d15f2c141 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter1.2026-09-28T20-01.md @@ -0,0 +1,32 @@ +# P2-T1 — PowerShell QC step 1, format (iteration 1) + +Timestamp: 2026-09-30T10-23 +Command: Get-FileHash -Algorithm SHA256 over every .ps1, .psm1 and .psd1 file under scripts/dependencies and tests/scripts/dependencies; MCP mcp__drm-copilot__run_poshqc_format (workspace_root , scan_folders ["scripts/dependencies","tests/scripts/dependencies"]); re-hash; git status --porcelain --untracked-files=all -- scripts/dependencies tests/scripts/dependencies; @(Get-Content -LiteralPath "scripts/dependencies/ConsistencyVerifier.psm1").Count +EXIT_CODE: 0 +Output Summary: +- MCP payload (host prefix replaced): {"ok":true,"tool":"run_poshqc_format","workspace_root":"","summary":"Ran bundled PoshQC format against '' with 2 selected scan folder(s)."} +- scan_folders: ["scripts/dependencies","tests/scripts/dependencies"] +- Hash sets: 14 entries before and 14 after (6 production, 8 test files); every hash identical +- Write Set rewrite count: 0 +- REVERT-SET: empty +- Post-revert porcelain over the two folders: empty +- ConsistencyVerifier.psm1 line count: 499 (equals VERIFIER-LINES) +- No REWRITE-NUMSTAT capture was needed (no rewrite); no commit made; the loop does not restart. + +Hash set (identical before and after): +``` +scripts\dependencies\AnalyzerItemRepair.psm1 102E3EBCF014F8365C3C65A834EDEC5FC9DAC9B1FFD6477E68D813335DB48F68 +scripts\dependencies\ConsistencyVerifier.psm1 00604D4F0731A2B432797CBBF85AE5DABAE1D17190A07DCA2348D272D1FBA920 +scripts\dependencies\PackageCompatibility.psm1 89B31603872ED09C8E2DF2E94A597D42BF3A2019D4F49298D6859CEF7CBF41CD +scripts\dependencies\PackageGraph.psm1 1CE9EABA3A43FF2446C3B63FFA53CE501537362C8E6EED6BB9DB4774F15C9BC6 +scripts\dependencies\ProjectConsistency.psm1 0E7B005A65B5614A0099F7A7286FE6692F87CC49FF09D749877F832C37D69EFE +scripts\dependencies\Repair-PackageManifestConsistency.ps1 E69F61364EB1640C0FADFBBAE1F418250D2F508E8F26A048BE43F70DD659078A +tests\scripts\dependencies\AnalyzerItemRepair.Tests.ps1 7C4CBC097681F98A629F94AD12D800A7E87652CA773825FA26F621969671D011 +tests\scripts\dependencies\ConsistencyVerifier.Tests.ps1 CC9AD3DFE9799F943AE464A04C4E8AA00A389283B510DB8759A1BA474231C719 +tests\scripts\dependencies\DependabotConfig.Tests.ps1 3F738E78A77F028BBB97D86BD2B9A33DC8CB94F1ABB31F1DC306413CDE3B3C48 +tests\scripts\dependencies\PackageCompatibility.Tests.ps1 0EF34C85EBA0B70C24CC4EA662472FA97F33D20B527120278606B12F6D7010DC +tests\scripts\dependencies\PackageGraph.Tests.ps1 910DD957F6377DD60A9F2EFC26E7597421E2C69505DE21E78E4B087729305EBE +tests\scripts\dependencies\ProjectConsistency.Tests.ps1 BCB15A04404BD3792A1DCB65315DE2B4CD822087B9D3EB3006E8BE9EB81CA761 +tests\scripts\dependencies\Repair-PackageManifestConsistency.Tests.ps1 3348C5D17773A9DCC6EEFD3A85EF6874BB96CA9BE8B1F2A85C1EA9CB96756942 +tests\scripts\dependencies\RepositoryTreeConsistency.Tests.ps1 B4312DE871FCA6A2E690D9F3B6B9269F7E4631735A87719FC4BFE85919CBBD9A +``` diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter2.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter2.2026-09-28T20-01.md new file mode 100644 index 000000000..b8b1c9cf7 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter2.2026-09-28T20-01.md @@ -0,0 +1,14 @@ +# P2-T1 — PowerShell QC step 1, format (iteration 2) + +Timestamp: 2026-09-30T10-55 +Command: Get-FileHash -Algorithm SHA256 over every .ps1, .psm1 and .psd1 file under scripts/dependencies and tests/scripts/dependencies; MCP mcp__drm-copilot__run_poshqc_format (workspace_root , scan_folders ["scripts/dependencies","tests/scripts/dependencies"]); re-hash; git status --porcelain --untracked-files=all -- scripts/dependencies tests/scripts/dependencies; @(Get-Content -LiteralPath "scripts/dependencies/ConsistencyVerifier.psm1").Count +EXIT_CODE: 0 +Output Summary: +- Iteration 2 follows the iteration 1 P2-T7 failure (qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md). +- MCP payload (host prefix replaced): {"ok":true,"tool":"run_poshqc_format","workspace_root":"","summary":"Ran bundled PoshQC format against '' with 2 selected scan folder(s)."} +- scan_folders: ["scripts/dependencies","tests/scripts/dependencies"] +- Hash sets: 14 entries before and 14 after (6 production, 8 test files); every hash identical, and identical to the iteration 1 set +- Write Set rewrite count: 0 +- REVERT-SET: empty +- Post-revert porcelain over the two folders: empty +- ConsistencyVerifier.psm1 line count: 499 (equals VERIFIER-LINES) diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t10-change-footprint.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t10-change-footprint.2026-09-28T20-01.md new file mode 100644 index 000000000..5e515a837 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t10-change-footprint.2026-09-28T20-01.md @@ -0,0 +1,101 @@ +# P2-T10 — Change footprint (CMD-FOOTPRINT) + +Timestamp: 2026-09-30T11-09 +Command: git diff --name-only 481b33c594d8412cb64e604ff53295db215ac2f1 -- . together with git status --porcelain --untracked-files=all (P0-START anchor; both run in one pwsh invocation beginning with Set-Location "") +EXIT_CODE: 0 +Output Summary: +- Every path in the union of the two captures is a Write Set member, lies under the feature folder, or lies under the agent-memory tree. +- Paths outside the feature folder and the agent-memory tree: exactly the eight non-feature-folder Write Set paths named in P1-T14: + - .github/workflows/README.md + - .github/workflows/dependabot-repair.yml + - QuickFiler.Test/QuickFiler.Test.csproj + - SVGControl/app.config + - docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md + - scripts/dependencies/ConsistencyVerifier.psm1 + - tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 + - tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 +- Paths matching *.cs: 0 +- Paths under .claude/rules, .github/instructions or the config directory: 0 +- Other *.csproj, packages.config or app.config paths: 0 (the count the AC7 check-off cites as proof that no analyzer item or manifest was changed on this branch) +- Paths under docs/features/potential: 0 +- Agent-memory entries present (not this change's work, not staged): .claude/agent-memory/atomic-executor/MEMORY.md and .claude/agent-memory/atomic-planner/MEMORY.md (modified, tracked), plus five untracked agent-memory notes. + +Anchored name-only diff against P0-START, verbatim (git also printed two "LF will be replaced by CRLF" warnings, for the atomic-executor MEMORY.md and the plan file): +``` +.claude/agent-memory/atomic-executor/MEMORY.md +.claude/agent-memory/atomic-planner/MEMORY.md +.github/workflows/README.md +.github/workflows/dependabot-repair.yml +QuickFiler.Test/QuickFiler.Test.csproj +SVGControl/app.config +docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t1-worktree-anchor.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t10-msbuild-analyzers.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t11-msbuild-nullable.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-coverage-projection.2026-09-28T20-01.jacoco.xml +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-mstest-coverage.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-test-results.2026-09-28T20-01.summary.txt +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t13-poshqc-format.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t14-poshqc-analyze.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t15-poshqc-test-mcp.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t16-pester.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t17-altcover-and-verifier-prefix.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t18-redirect-prefix.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t19-workflow-prefix-and-actionlint.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t20-hygiene.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t21-commit.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t3-sdk-bootstrap.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t4-tool-restore.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t5-package-restore.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t6-analyzer-item-census.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t7-dotnet-coverage.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t8-pester-provision.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t9-csharpier-check.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/phase0-instructions-read.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t10-verifier-comment.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t12-verifier-postfix.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t4-altcover-imports-removed.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t5-redirects-fixed.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t6-workflow-client-id.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t7-actionlint.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t8-runbook-client-id.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t9-readme-client-id.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t1-tree-test-authored.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t3-verifier-import-tests.2026-09-28T20-01.md +docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/plan.2026-09-28T20-01.md +scripts/dependencies/ConsistencyVerifier.psm1 +tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 +tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 +``` + +Porcelain capture, verbatim: +``` + M .claude/agent-memory/atomic-executor/MEMORY.md + M .claude/agent-memory/atomic-planner/MEMORY.md + M docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/plan.2026-09-28T20-01.md +?? .claude/agent-memory/atomic-executor/index_csharp_nullable_and_component_gotchas.md +?? .claude/agent-memory/atomic-executor/index_pwsh_git_and_gate_mechanics_misc.md +?? .claude/agent-memory/atomic-executor/index_test_isolation_and_coverage.md +?? .claude/agent-memory/atomic-executor/project_hygiene_pattern_array_comma_precedence_and_regex_token_hits.md +?? .claude/agent-memory/atomic-planner/project_929_manifest_residuals_plan_seams.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t14-commit.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter1.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter2.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter1.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter2.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter1.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter1.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter2.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter1.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter2.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter1.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter2.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter2.2026-09-28T20-01.md +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt +?? docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t8-attestation-and-coverage-delta.2026-09-28T20-01.md +``` diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t11-hygiene.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t11-hygiene.2026-09-28T20-01.md new file mode 100644 index 000000000..66bf5748c --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t11-hygiene.2026-09-28T20-01.md @@ -0,0 +1,14 @@ +# P2-T11 — Hygiene scan of the final footprint (CMD-HYGIENE) + +Timestamp: 2026-09-30T11-10 +Command: CMD-HYGIENE with FOLDER-LIST "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929",".github/workflows/dependabot-repair.yml",".github/workflows/README.md","docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks","tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1" (account and machine values derived at run time and not recorded); plus a count of evidence .md files under the feature folder +EXIT_CODE: 0 +Output Summary: +- PATTERNS=3 +- SELFTEST=1 +- SELFTEST_NEG=0 +- SCANNED=61 HITS=0 (at least 45) +- Hit listing: empty +- PRE-FIX-HITS: 0 +- Evidence .md artifacts under the feature folder before this artifact: 51 — the 44 the plan counts for a single-iteration run plus the seven iteration 2 artifacts of P2-T1 to P2-T7 (the plan states that a further iteration only raises the count) +- The two P2-T7 copies (projection and summary) and the two P0-T12 copies are included in the scan because their extensions are in the filter list. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t12-ac1-checkoff.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t12-ac1-checkoff.2026-09-28T20-01.md new file mode 100644 index 000000000..df2214efa --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t12-ac1-checkoff.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T12 — AC1 check-off + +Timestamp: 2026-09-30T11-11 +Command: Read the cited artifacts; Edit issue.md changing `- [ ] AC1:` to `- [x] AC1:` +EXIT_CODE: 0 +Output Summary: +- Evidence read: + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t4-altcover-imports-removed.2026-09-28T20-01.md — ALTCOVER_LINES=0 over every tracked project file and packages manifest; LINES=568; NUMSTAT 0 added / 2 deleted + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter2.2026-09-28T20-01.md — post-change analyzer rebuild MSBUILD_EXIT=0, CS0006_LINES=0, "0 Error(s)" +- Quoted: ALTCOVER_LINES=0 +- Change to issue.md: only the AC1 line, `- [ ] AC1:` to `- [x] AC1:`; no other character changed. +- Checked off AC: "AC1: `QuickFiler.Test/QuickFiler.Test.csproj` contains no `Import` element that references an `altcover` package path; ..." diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t13-ac2-checkoff.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t13-ac2-checkoff.2026-09-28T20-01.md new file mode 100644 index 000000000..6ff412ae3 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t13-ac2-checkoff.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T13 — AC2 check-off + +Timestamp: 2026-09-30T11-12 +Command: Read the cited artifacts; Edit issue.md changing `- [ ] AC2:` to `- [x] AC2:` +EXIT_CODE: 0 +Output Summary: +- Evidence read: + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t18-redirect-prefix.2026-09-28T20-01.md — FIZZLER_ASM=1.3.1.0; SVGControl.csproj line 58 declares Fizzler, Version=1.3.1.0; pre-fix FIZZLER_REPAIRS=1 + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t5-redirects-fixed.2026-09-28T20-01.md — post-fix FIZZLER_REPAIRS=0; new line 15 `` + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md — the SVGControl redirect test passing (RepositoryTreeConsistency.Tests.ps1 tests=4 failures=0) +- Change to issue.md: only the AC2 checkbox. +- Checked off AC: "AC2: In `SVGControl/app.config`, the `Fizzler` binding redirect names newVersion 1.3.1.0 and an oldVersion range ending at 1.3.1.0, ..." diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t14-ac3-checkoff.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t14-ac3-checkoff.2026-09-28T20-01.md new file mode 100644 index 000000000..988340bda --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t14-ac3-checkoff.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T14 — AC3 check-off + +Timestamp: 2026-09-30T11-13 +Command: Read the cited artifacts; Edit issue.md changing `- [ ] AC3:` to `- [x] AC3:` +EXIT_CODE: 0 +Output Summary: +- Evidence read: + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t18-redirect-prefix.2026-09-28T20-01.md — UNSAFE_ASM=6.0.3.0; SVGControl.csproj line 82 declares System.Runtime.CompilerServices.Unsafe, Version=6.0.3.0; pre-fix UNSAFE_REPAIRS=1 + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t5-redirects-fixed.2026-09-28T20-01.md — post-fix UNSAFE_REPAIRS=0; new line 19 `` + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md — the SVGControl redirect test (which checks both Fizzler and System.Runtime.CompilerServices.Unsafe) passing +- Change to issue.md: only the AC3 checkbox. +- Checked off AC: "AC3: In `SVGControl/app.config`, the `System.Runtime.CompilerServices.Unsafe` binding redirect names newVersion 6.0.3.0 and an oldVersion range ending at 6.0.3.0, ..." diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t15-ac4-checkoff.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t15-ac4-checkoff.2026-09-28T20-01.md new file mode 100644 index 000000000..0bffe93cf --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t15-ac4-checkoff.2026-09-28T20-01.md @@ -0,0 +1,14 @@ +# P2-T15 — AC4 check-off + +Timestamp: 2026-09-30T11-14 +Command: Read the cited artifacts; Edit issue.md changing `- [ ] AC4:` to `- [x] AC4:` +EXIT_CODE: 0 +Output Summary: +- Evidence read: + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t3-verifier-import-tests.2026-09-28T20-01.md — the two in-memory Import-kind tests ('reports an Import whose package the manifest does not declare, with Kind Import' and 'reports no Import finding when the manifest declares the imported package'); ConsistencyVerifier.Tests.ps1 suite tests=14 failures=0 + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md — the tree Import test failing with 2 findings before the fix (QuickFiler.Test.csproj: line 8 and line 537 altcover.8.6.45) + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md — the tree Import test passing with 0 findings after AC1 + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t12-verifier-postfix.2026-09-28T20-01.md — ABSENT=0 on the tree (P0-T17 measured 2) + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md — the full local suite green (137 tests, 0 failures) and the CI Pester job green (379 passed, 0 failed) +- Decision D1: the detection rule pre-existed (Find-PackageAbsentFromManifest reports an Import whose package id the sibling manifest omits); AC4 is discharged by explicit in-memory tests and the tree observation, not by a new production rule. The fixtures are in-memory strings; the tree test reads tracked files only and creates no temporary file. +- Change to issue.md: only the AC4 checkbox. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t16-ac5-checkoff.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t16-ac5-checkoff.2026-09-28T20-01.md new file mode 100644 index 000000000..2ef27189c --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t16-ac5-checkoff.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T16 — AC5 check-off + +Timestamp: 2026-09-30T11-15 +Command: Read the cited artifacts; Edit issue.md changing `- [ ] AC5:` to `- [x] AC5:` +EXIT_CODE: 0 +Output Summary: +- Evidence read: + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t6-workflow-client-id.2026-09-28T20-01.md — WF_APPID=0, WF_CLIENTID=1, WF_SECRET=1 + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t7-actionlint.2026-09-28T20-01.md — actionlint 1.7.7: SCOPED_EXIT=0 and REPO_EXIT=0 with empty output; DependabotConfig.Tests.ps1 tests=17 failures=0 + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md — the workflow input test ('passes client-id and not app-id to the create-github-app-token step of the repair workflow') passing +- The CI run 36722780748 on the pushed head also reports the actionlint job as success (P2-T3). +- Change to issue.md: only the AC5 checkbox. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t17-ac6-checkoff.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t17-ac6-checkoff.2026-09-28T20-01.md new file mode 100644 index 000000000..48957cfb9 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t17-ac6-checkoff.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T17 — AC6 check-off + +Timestamp: 2026-09-30T11-16 +Command: Read the cited artifacts; Edit issue.md changing `- [ ] AC6:` to `- [x] AC6:` +EXIT_CODE: 0 +Output Summary: +- Evidence read: + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t8-runbook-client-id.2026-09-28T20-01.md — RB_APPID=0, RB_CLIENTID=1, RB_SECRET=2, RB_PARTB=0, PARTD_CLIENTID=2 + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t9-readme-client-id.2026-09-28T20-01.md — README row updated (README_NUMERIC=0, README_CLIENTID=1) + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md — the runbook secret-name test passing; it extracts the secret name from the workflow's client-id line and asserts it in the runbook sample and in Part D +- Decision D3: the secret name DEPENDABOT_REPAIR_APP_ID is kept and now holds the App's Client ID; the workflow passes it as client-id. Renaming would require maintainer credential action; the secret is not yet provisioned, so the change is merge-safe without maintainer action. +- Change to issue.md: only the AC6 checkbox. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t18-ac7-checkoff.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t18-ac7-checkoff.2026-09-28T20-01.md new file mode 100644 index 000000000..8fdf9deea --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t18-ac7-checkoff.2026-09-28T20-01.md @@ -0,0 +1,21 @@ +# P2-T18 — AC7 check-off + +Timestamp: 2026-09-30T11-17 +Command: Read the cited artifacts; Edit issue.md changing `- [ ] AC7:` to `- [x] AC7:` +EXIT_CODE: 0 +Output Summary: +- Evidence read: + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t5-package-restore.2026-09-28T20-01.md — cold restore: PACKAGE_DIRS_BEFORE=0, PACKAGE_DIRS_AFTER=172, "Build succeeded." and "0 Error(s)" + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t6-analyzer-item-census.2026-09-28T20-01.md + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t8-attestation-and-coverage-delta.2026-09-28T20-01.md and the seven iter2 artifacts it cites (P2-T1 to P2-T7, all EXIT_CODE 0) + - docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t10-change-footprint.2026-09-28T20-01.md +- Quoted verbatim from the P0-T6 artifact: + - `ANALYZER-ITEM-STATE: aligned` + - `ANALYZER_ITEMS=162 FILES=17 UNRESOLVED=0` +- The cold restore of P0-T5 (PACKAGE_DIRS_BEFORE=0) was followed by the P0-T10, P0-T11, P2-T5 and P2-T6 rebuilds exiting 0 with no back-fill performed (decision D8; the amended AC7's back-fill clause is permissive and was not exercised, so AC7 is satisfied with its text unchanged). +- The P2-T10 footprint records 0 other *.csproj, packages.config or app.config paths, which shows that no analyzer item or manifest was changed on this branch. +- No-new-failure comparison (P2-T8): + - C#: CSharpier check exit 0 with no findings (baseline exit 0, no findings); analyzer and nullable rebuilds exit 0 with 0 errors and OUT_LINES 36 (baseline identical); MSTest 7346 of 7346 passed with line 85.92 percent and branch 80.08 percent (baseline 7346 of 7346, 85.91 and 80.08; deltas +0.01 and 0.00). + - PowerShell: PoshQC format rewrote nothing, PoshQC analyze ok true, local PoshQC test 137 of 137 passed (baseline 131 of 131); CI Pester job 379 passed, 0 failed, LinePercent 94.51 on run 36722780748 (head b96926588) against 373 passed, 0 failed, LinePercent 94.51 on run 36666302259 (main, head 231e1c0b5). +- Disclosure: the final QC loop needed two iterations. Iteration 1 failed at P2-T7 on one timing-dependent QuickFiler.Test test (RemainingLoadActive_AcrossAsyncVoidFirstAwait_StaysTrueWhileLoaderProduces, a five-second wait that did not complete); iteration 2 passed on the unchanged tree. Separately, the CI mstest-coverage job on run 36722780748 failed one different QuickFiler.Test test (Transaction_SecondCallerCannotInstallUntilTheFirstRestores). This change edits no C# source, both tests passed in the local baseline and in the final local iteration, and both are reported to the caller as pre-existing timing-dependent tests outside this issue's scope. +- Change to issue.md: only the AC7 checkbox. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter1.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter1.2026-09-28T20-01.md new file mode 100644 index 000000000..cfc9e44cb --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter1.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T2 — PowerShell QC step 2, analyze (iteration 1) + +Timestamp: 2026-09-30T10-24 +Command: MCP mcp__drm-copilot__run_poshqc_analyze (workspace_root , scan_folders ["scripts/dependencies","tests/scripts/dependencies"]); pwsh -NoProfile -Command 'Set-Location ""; "FILES=" + @(Get-ChildItem -Recurse -File -Path "scripts/dependencies","tests/scripts/dependencies" -Include *.ps1,*.psm1).Count' +EXIT_CODE: 0 +Output Summary: +- MCP payload (verbatim, host prefix replaced): {"ok":true,"tool":"run_poshqc_analyze","workspace_root":"","summary":"Ran bundled PoshQC analyze against '' with 2 selected scan folder(s)."} +- scan_folders: ["scripts/dependencies","tests/scripts/dependencies"] +- PoshQC analyze: pass (0 findings); tool reports no count +- FILES=14 (P0-T14 measured 13, plus the created test file) + +GATE-SUBSTITUTION: PoshQC analyze ok flag stands in for a diagnostic count diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter2.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter2.2026-09-28T20-01.md new file mode 100644 index 000000000..6f6f337fa --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter2.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T2 — PowerShell QC step 2, analyze (iteration 2) + +Timestamp: 2026-09-30T10-56 +Command: MCP mcp__drm-copilot__run_poshqc_analyze (workspace_root , scan_folders ["scripts/dependencies","tests/scripts/dependencies"]); pwsh -NoProfile -Command 'Set-Location ""; "FILES=" + @(Get-ChildItem -Recurse -File -Path "scripts/dependencies","tests/scripts/dependencies" -Include *.ps1,*.psm1).Count' +EXIT_CODE: 0 +Output Summary: +- MCP payload (verbatim, host prefix replaced): {"ok":true,"tool":"run_poshqc_analyze","workspace_root":"","summary":"Ran bundled PoshQC analyze against '' with 2 selected scan folder(s)."} +- scan_folders: ["scripts/dependencies","tests/scripts/dependencies"] +- PoshQC analyze: pass (0 findings); tool reports no count +- FILES=14 (P0-T14 measured 13, plus the created test file) + +GATE-SUBSTITUTION: PoshQC analyze ok flag stands in for a diagnostic count diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t20-ac-status-summary.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t20-ac-status-summary.2026-09-28T20-01.md new file mode 100644 index 000000000..5a96f5e74 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t20-ac-status-summary.2026-09-28T20-01.md @@ -0,0 +1,25 @@ +# P2-T20 — Acceptance-criteria status summary + +Timestamp: 2026-09-30T11-19 +Command: Read the `## Acceptance Criteria` section of issue.md; CMD-HYGIENE with FOLDER-LIST "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929" +EXIT_CODE: 0 +Output Summary: + +### Acceptance Criteria Status +- Source: docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md (`## Acceptance Criteria`, work mode minor-audit) +- Total AC items: 7 +- Checked off (delivered): 7 +- Remaining (unchecked): 0 +- Items remaining: none + +Check-off tasks: AC1 P2-T12, AC2 P2-T13, AC3 P2-T14, AC4 P2-T15, AC5 P2-T16, AC6 P2-T17, AC7 P2-T18. AC18 to AC20 of issue 911 remain a maintainer follow-up record only (P2-T19) and are not marked passed. + +Pre-commit hygiene (CMD-HYGIENE over the feature folder): +- PATTERNS=3 +- SELFTEST=1 +- SELFTEST_NEG=0 +- SCANNED=67 +- HITS=0 +- PRE-FIX-HITS: 0 + +The head SHA, the git show listing and the porcelain capture of the commit that carries this artifact are transcribed into the P2-T21 index, because this artifact is inside the commit it describes. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter1.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter1.2026-09-28T20-01.md new file mode 100644 index 000000000..db82b236b --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter1.2026-09-28T20-01.md @@ -0,0 +1,60 @@ +# P2-T3 — PowerShell QC step 3, test, with coverage read from CI (iteration 1) + +Timestamp: 2026-09-30T10-45 +Command: pwsh -NoProfile -Command '[DateTime]::UtcNow.ToString("o")' (RUN-START); MCP mcp__drm-copilot__run_poshqc_test (workspace_root , scan_folders ["tests/scripts/dependencies"]); CMD-JUNIT-READ; CMD-CI-LIST; CMD-CI-DISPATCH; CMD-CI-LIST (re-run); CMD-CI-WATCH with RUN-ID 36722780748; CMD-CI-PESTER with RUN-ID 36722780748 and DIR coverage/ci-branch-pester-36722780748-1 +EXIT_CODE: 0 +Output Summary: + +Local MCP test run: +- RUN-START: 2026-09-30T13:34:53.3059426Z +- MCP payload (host prefix replaced): {"ok":true,"tool":"run_poshqc_test","workspace_root":"","summary":"Ran bundled PoshQC test against '' with 1 selected scan folder(s)."} +- JUNIT-WRITTEN=2026-09-30T13:35:27.6912381Z (later than RUN-START) +- JUNIT-ROOT tests=137 failures=0 errors=0 disabled=0; no JUNIT-NOTPASSED line +- JUNIT-SUITE RepositoryTreeConsistency.Tests.ps1 tests=4 failures=0 skipped=0 +- JUNIT-SUITE ConsistencyVerifier.Tests.ps1 tests=14 failures=0 skipped=0 +- JUNIT-SUITE DependabotConfig.Tests.ps1 tests=17 failures=0 skipped=0 +- Other suites: AnalyzerItemRepair 13, PackageCompatibility 8, PackageGraph 32, ProjectConsistency 18, Repair-PackageManifestConsistency 31, all failures=0 + +Push check: git rev-parse HEAD = b96926588d562f994430e7ba7301de5de86f206c equals PUSHED-HEAD from P1-T14, so no push was made in this task. + +CI locate, dispatch and watch: +- CMD-CI-LIST (first): HEAD=b96926588d562f994430e7ba7301de5de86f206c; REMOTE=b96926588d562f994430e7ba7301de5de86f206c refs/heads/bug/package-manifest-consistency-residuals-929; RUNS-FOR-HEAD=0 (no pull request run exists for this head) +- CMD-CI-DISPATCH (once): printed the run URL for run 36722780748; DISPATCH-EXIT=0 +- CMD-CI-LIST (re-run 1): HEAD and REMOTE as above; RUNS-FOR-HEAD=1; RUN id=36722780748 head=b96926588d562f994430e7ba7301de5de86f206c event=workflow_dispatch status=queued conclusion= +- Selected run: 36722780748 (greatest databaseId) +- CMD-CI-WATCH invocation 1: returned on its own after the run completed; WATCH-EXIT=0 + +CMD-CI-PESTER (run 36722780748, head b96926588d562f994430e7ba7301de5de86f206c): +- RUN id=36722780748 head=b96926588d562f994430e7ba7301de5de86f206c branch=bug/package-manifest-consistency-residuals-929 event=workflow_dispatch status=completed conclusion=failure workflow=CI +- PESTER-JOBS=1 +- JOB id=109911885533 name=pester / Run Pester suite with coverage status=completed conclusion=success +- LOG-LINES=1097 +- Log lines (verbatim after SGR stripping): + - "Tests Passed: 379, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0" + - "PESTER Passed=379 Failed=0 Skipped=0 Total=379" + - "COVERAGE LinePercent=94.51 Covered=1721 Total=1821" +- Total 379 equals BASELINE-TOTAL 373 plus 6 (four tree tests and two Import-kind tests); Failed 0; Skipped 0 +- DIR-PREEXISTS=False; DOWNLOAD-EXIT=0; ARTIFACT-FILES=1; DIR used: coverage/ci-branch-pester-36722780748-1 +- REPORT-LINE covered=1721 missed=100; computed percent 1721 / 1821 * 100 = 94.51, equal to the log's LinePercent 94.51 and at least 80 +- MEETS-85: true (observation only, convention 10) +- SOURCEFILE lines (run 36722780748, head b96926588): + - AnalyzerItemRepair.psm1 covered=106 missed=0 + - ConsistencyVerifier.psm1 covered=158 missed=2 + - PackageCompatibility.psm1 covered=33 missed=0 + - PackageGraph.psm1 covered=164 missed=0 + - ProjectConsistency.psm1 covered=103 missed=0 + - Repair-PackageManifestConsistency.ps1 covered=213 missed=14 +- ConsistencyVerifier.psm1 covered 158 is at least VERIFIER-COVERED 158 and missed 2 is at most VERIFIER-MISSED 2 (P0-T16, run 36666302259). + +Run-level conclusion (recorded as measured, reported to the caller, not a failure of this task): failure. Every job: +- build-analyzers / Build with analyzers and code style enforcement: success +- mstest-coverage / Run MSTest suite with coverage: failure — "Total tests: 7346 / Passed: 7345 / Failed: 1"; the failed test is Transaction_SecondCallerCannotInstallUntilTheFirstRestores (QuickFiler.Test/Controllers/QfcItemController.UiThreadDispatcherFixtureTests.cs), message "Expected observedByB to refer to because the first transaction restores before it releases the gate, so the waiter cannot observe the pre-restore value, but found System.Windows.Threading.Dispatcher ...". This change edits no C# source (the only QuickFiler.Test change removes two Exists()-guarded Import elements whose package was never restored), and the same test passed in the local P0-T12 run (7346 of 7346). +- hygiene / Repository hygiene guard: success +- pester / Run Pester suite with coverage: success +- actionlint / actionlint: success +- format-check / Verify formatting: success +- build-nullable / Build with nullable warnings treated as errors: success + +Pester emits no branch counter, so no PowerShell branch figure is claimed. These figures stand in for a permitted evidence form that the committed-evidence section does not define for the Pester route. The downloaded JaCoCo document is left under the ignored coverage directory. + +GATE-SUBSTITUTION: CI Pester job on the pushed head stands in for a local coverage run diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md new file mode 100644 index 000000000..7e61e59c2 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md @@ -0,0 +1,48 @@ +# P2-T3 — PowerShell QC step 3, test, with coverage read from CI (iteration 2) + +Timestamp: 2026-09-30T10-58 +Command: pwsh -NoProfile -Command '[DateTime]::UtcNow.ToString("o")' (RUN-START); MCP mcp__drm-copilot__run_poshqc_test (workspace_root , scan_folders ["tests/scripts/dependencies"]); CMD-JUNIT-READ; CMD-CI-LIST (twice); CMD-CI-WATCH with RUN-ID 36722780748; CMD-CI-PESTER with RUN-ID 36722780748 and DIR coverage/ci-branch-pester-36722780748-2 +EXIT_CODE: 0 +Output Summary: + +Local MCP test run: +- RUN-START: 2026-09-30T13:46:37.9133883Z +- MCP payload (host prefix replaced): {"ok":true,"tool":"run_poshqc_test","workspace_root":"","summary":"Ran bundled PoshQC test against '' with 1 selected scan folder(s)."} +- JUNIT-WRITTEN=2026-09-30T13:47:26.1351476Z (later than RUN-START) +- JUNIT-ROOT tests=137 failures=0 errors=0 disabled=0; no JUNIT-NOTPASSED line +- JUNIT-SUITE RepositoryTreeConsistency.Tests.ps1 tests=4 failures=0 skipped=0 +- JUNIT-SUITE ConsistencyVerifier.Tests.ps1 tests=14 failures=0 skipped=0 +- JUNIT-SUITE DependabotConfig.Tests.ps1 tests=17 failures=0 skipped=0 +- Other suites: AnalyzerItemRepair 13, PackageCompatibility 8, PackageGraph 32, ProjectConsistency 18, Repair-PackageManifestConsistency 31, all failures=0 + +Push check: HEAD b96926588d562f994430e7ba7301de5de86f206c equals PUSHED-HEAD (no P2-T1 or P2-T2 commit in either iteration), so no push was made. + +CI locate and watch (no dispatch: CMD-CI-DISPATCH was already made once for this pushed head in iteration 1, and the rule permits at most one dispatch per pushed head): +- CMD-CI-LIST (first): HEAD=b96926588d562f994430e7ba7301de5de86f206c; REMOTE names HEAD; RUNS-FOR-HEAD=0 (a transient empty list from gh; the run was listed in iteration 1) +- CMD-CI-LIST (re-run 1): HEAD and REMOTE as above; RUNS-FOR-HEAD=1; RUN id=36722780748 head=b96926588d562f994430e7ba7301de5de86f206c event=workflow_dispatch status=completed conclusion=failure; an unfiltered listing of the branch's ci.yml runs shows the same single run +- Selected run: 36722780748 +- CMD-CI-WATCH invocation 1: "Run CI (36722780748) has already completed with 'failure'"; WATCH-EXIT=0 + +CMD-CI-PESTER (second invocation against run 36722780748, head b96926588): +- RUN id=36722780748 head=b96926588d562f994430e7ba7301de5de86f206c branch=bug/package-manifest-consistency-residuals-929 event=workflow_dispatch status=completed conclusion=failure workflow=CI +- PESTER-JOBS=1; JOB id=109911885533 name=pester / Run Pester suite with coverage status=completed conclusion=success +- LOG-LINES=1097 +- "Tests Passed: 379, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0" +- "PESTER Passed=379 Failed=0 Skipped=0 Total=379" +- "COVERAGE LinePercent=94.51 Covered=1721 Total=1821" +- Total 379 equals BASELINE-TOTAL 373 plus 6; Failed 0; Skipped 0 +- DIR-PREEXISTS=False; DOWNLOAD-EXIT=0; ARTIFACT-FILES=1; DIR used: coverage/ci-branch-pester-36722780748-2 +- REPORT-LINE covered=1721 missed=100; computed percent 94.51, equal to the log's LinePercent and at least 80 +- MEETS-85: true (observation only, convention 10) +- SOURCEFILE AnalyzerItemRepair.psm1 covered=106 missed=0 +- SOURCEFILE ConsistencyVerifier.psm1 covered=158 missed=2 (covered at least VERIFIER-COVERED 158; missed at most VERIFIER-MISSED 2) +- SOURCEFILE PackageCompatibility.psm1 covered=33 missed=0 +- SOURCEFILE PackageGraph.psm1 covered=164 missed=0 +- SOURCEFILE ProjectConsistency.psm1 covered=103 missed=0 +- SOURCEFILE Repair-PackageManifestConsistency.ps1 covered=213 missed=14 + +Run-level conclusion failure, recorded and reported as in iteration 1: every job succeeded except mstest-coverage / Run MSTest suite with coverage (1 of 7346 failed: Transaction_SecondCallerCannotInstallUntilTheFirstRestores, QuickFiler.Test/Controllers/QfcItemController.UiThreadDispatcherFixtureTests.cs). build-analyzers, hygiene, pester, actionlint, format-check and build-nullable: success. + +Pester emits no branch counter, so no PowerShell branch figure is claimed. These figures stand in for a permitted evidence form that the committed-evidence section does not define for the Pester route. The downloaded JaCoCo document is left under the ignored coverage directory. + +GATE-SUBSTITUTION: CI Pester job on the pushed head stands in for a local coverage run diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter1.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter1.2026-09-28T20-01.md new file mode 100644 index 000000000..cdf2a53b5 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter1.2026-09-28T20-01.md @@ -0,0 +1,23 @@ +# P2-T4 — C# QC step 1, CSharpier check (iteration 1) + +Timestamp: 2026-09-30T10-47 +Command: pwsh -NoProfile -Command 'Set-Location ""; dotnet tool run csharpier check .; "CSHARPIER_EXIT=$LASTEXITCODE"' followed by the CMD-CSHARPIER-CHECK XML-candidate companion command +EXIT_CODE: 0 +Output Summary: +- "Checked 1625 files in 8208ms." +- CSHARPIER_EXIT=0 (equal to the P0-T9 exit code 0) +- CSHARPIER-FINDINGS: none (equal to the P0-T9 list) +- XML-CANDIDATES: 6 +``` +artifacts\pester\pester-junit.xml +artifacts\pester\powershell-coverage.koverage.xml +artifacts\pester\powershell-coverage.xml +coverage\ci-branch-pester-36722780748-1\pester-coverage.xml +coverage\ci-main-pester-36666302259-1\pester-coverage.xml +coverage\coverage.cobertura.jacoco.xml +``` +- CHECKED-DELTA: 0 (1625 minus the P0-T9 value 1625) +- XML-DELTA: 3 (6 minus the P0-T9 value 3) +- CHECKED-DELTA equals 0, one of the two admissible values. +- CSHARPIER-COUNTS-IGNORED-XML: false (three additional *.xml files under the ignored trees did not change "Checked N", so CSharpier 1.2.6 did not count them) +- The check subcommand is read-only; no file was rewritten. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter2.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter2.2026-09-28T20-01.md new file mode 100644 index 000000000..3f36d99ca --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter2.2026-09-28T20-01.md @@ -0,0 +1,24 @@ +# P2-T4 — C# QC step 1, CSharpier check (iteration 2) + +Timestamp: 2026-09-30T11-00 +Command: pwsh -NoProfile -Command 'Set-Location ""; dotnet tool run csharpier check .; "CSHARPIER_EXIT=$LASTEXITCODE"; ' (the check and its companion run in one pwsh invocation) +EXIT_CODE: 0 +Output Summary: +- "Checked 1625 files in 10893ms." +- CSHARPIER_EXIT=0 (equal to the P0-T9 exit code 0) +- CSHARPIER-FINDINGS: none (equal to the P0-T9 list) +- XML-CANDIDATES: 7 +``` +artifacts\pester\pester-junit.xml +artifacts\pester\powershell-coverage.koverage.xml +artifacts\pester\powershell-coverage.xml +coverage\ci-branch-pester-36722780748-1\pester-coverage.xml +coverage\ci-branch-pester-36722780748-2\pester-coverage.xml +coverage\ci-main-pester-36666302259-1\pester-coverage.xml +coverage\coverage.cobertura.jacoco.xml +``` +- CHECKED-DELTA: 0 (1625 minus the P0-T9 value 1625) +- XML-DELTA: 4 (7 minus the P0-T9 value 3) +- CHECKED-DELTA equals 0, one of the two admissible values. +- CSHARPIER-COUNTS-IGNORED-XML: false (four additional *.xml files under the ignored trees did not change "Checked N") +- The check subcommand is read-only; no file was rewritten. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter1.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter1.2026-09-28T20-01.md new file mode 100644 index 000000000..8a8f74756 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter1.2026-09-28T20-01.md @@ -0,0 +1,14 @@ +# P2-T5 — C# QC step 2, analyzer rebuild (iteration 1) + +Timestamp: 2026-09-30T10-49 +Command: CMD-OUTLOOK (pwsh -NoProfile -Command '"OUTLOOK_COUNT=" + @(Get-Process outlook -ErrorAction SilentlyContinue).Count'); pwsh -NoProfile -Command 'Set-Location ""; msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true "/flp:LogFile=coverage\analyzers.msbuild.log;Verbosity=normal" | Out-Null; "MSBUILD_EXIT=$LASTEXITCODE"; ...OUT_LINES...; ...CS0006_LINES...; Get-Content -LiteralPath $l -Tail 6' +EXIT_CODE: 0 +OUTLOOK-CLOSED: true +Output Summary: +- CMD-OUTLOOK printed OUTLOOK_COUNT=0 (nothing terminated). +- Console output was discarded with Out-Null to keep the capture readable; the msbuild arguments are exactly CMD-MSBUILD-ANALYZERS and the summary is read from the file log tail. +- File log tail: "Build succeeded." / "0 Warning(s)" / "0 Error(s)" / "Time Elapsed 00:00:31.37" +- MSBUILD_EXIT=0 +- OUT_LINES=36 (at least 18; equal to the P0-T10 value 36) +- CS0006_LINES=0 +- This is the post-change solution rebuild AC7 names. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter2.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter2.2026-09-28T20-01.md new file mode 100644 index 000000000..e1e41ea44 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter2.2026-09-28T20-01.md @@ -0,0 +1,14 @@ +# P2-T5 — C# QC step 2, analyzer rebuild (iteration 2) + +Timestamp: 2026-09-30T11-01 +Command: CMD-OUTLOOK (pwsh -NoProfile -Command '"OUTLOOK_COUNT=" + @(Get-Process outlook -ErrorAction SilentlyContinue).Count'); pwsh -NoProfile -Command 'Set-Location ""; msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true "/flp:LogFile=coverage\analyzers.msbuild.log;Verbosity=normal" | Out-Null; "MSBUILD_EXIT=$LASTEXITCODE"; ...OUT_LINES...; ...CS0006_LINES...; Get-Content -LiteralPath $l -Tail 6' +EXIT_CODE: 0 +OUTLOOK-CLOSED: true +Output Summary: +- CMD-OUTLOOK printed OUTLOOK_COUNT=0 (nothing terminated). +- Console output was discarded with Out-Null; the msbuild arguments are exactly CMD-MSBUILD-ANALYZERS and the summary is read from the file log tail. +- File log tail: "Build succeeded." / "0 Warning(s)" / "0 Error(s)" / "Time Elapsed 00:00:25.28" +- MSBUILD_EXIT=0 +- OUT_LINES=36 (at least 18; equal to the P0-T10 value 36) +- CS0006_LINES=0 +- This is the post-change solution rebuild AC7 names. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter1.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter1.2026-09-28T20-01.md new file mode 100644 index 000000000..ef06afd28 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter1.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T6 — C# QC step 3, nullable rebuild (iteration 1) + +Timestamp: 2026-09-30T10-50 +Command: CMD-OUTLOOK (pwsh -NoProfile -Command '"OUTLOOK_COUNT=" + @(Get-Process outlook -ErrorAction SilentlyContinue).Count'); pwsh -NoProfile -Command 'Set-Location ""; msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true "/flp:LogFile=coverage\nullable.msbuild.log;Verbosity=normal" | Out-Null; "MSBUILD_EXIT=$LASTEXITCODE"; ...OUT_LINES...; Get-Content -LiteralPath $l -Tail 6' +EXIT_CODE: 0 +OUTLOOK-CLOSED: true +Output Summary: +- CMD-OUTLOOK printed OUTLOOK_COUNT=0 (nothing terminated). +- Console output was discarded with Out-Null; the msbuild arguments are exactly CMD-MSBUILD-NULLABLE and the summary is read from the file log tail. +- File log tail: "Build succeeded." / "0 Warning(s)" / "0 Error(s)" / "Time Elapsed 00:00:21.14" +- MSBUILD_EXIT=0 +- OUT_LINES=36 (at least 18; equal to the P0-T11 value 36) diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter2.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter2.2026-09-28T20-01.md new file mode 100644 index 000000000..5508b8a64 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter2.2026-09-28T20-01.md @@ -0,0 +1,12 @@ +# P2-T6 — C# QC step 3, nullable rebuild (iteration 2) + +Timestamp: 2026-09-30T11-02 +Command: CMD-OUTLOOK (pwsh -NoProfile -Command '"OUTLOOK_COUNT=" + @(Get-Process outlook -ErrorAction SilentlyContinue).Count'); pwsh -NoProfile -Command 'Set-Location ""; msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true "/flp:LogFile=coverage\nullable.msbuild.log;Verbosity=normal" | Out-Null; "MSBUILD_EXIT=$LASTEXITCODE"; ...OUT_LINES...; Get-Content -LiteralPath $l -Tail 6' +EXIT_CODE: 0 +OUTLOOK-CLOSED: true +Output Summary: +- CMD-OUTLOOK printed OUTLOOK_COUNT=0 (nothing terminated). +- Console output was discarded with Out-Null; the msbuild arguments are exactly CMD-MSBUILD-NULLABLE and the summary is read from the file log tail. +- File log tail: "Build succeeded." / "0 Warning(s)" / "0 Error(s)" / "Time Elapsed 00:00:31.26" +- MSBUILD_EXIT=0 +- OUT_LINES=36 (at least 18; equal to the P0-T11 value 36) diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml new file mode 100644 index 000000000..417873222 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md new file mode 100644 index 000000000..851c571d7 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md @@ -0,0 +1,15 @@ +# P2-T7 — C# QC step 4, MSTest with coverage (iteration 1) — FAILED, loop restarts as iter2 + +Timestamp: 2026-09-30T10-53 +Command: pwsh -NoProfile -Command 'Set-Location ""; & "\scripts\vscode\Invoke-MSTestWithCoverage.ps1" -SearchRoot .' (run detached with its combined output redirected to a session scratch log outside the repository; the script and its arguments are unchanged) +EXIT_CODE: 1 +Output Summary: +- "Total tests: 7346" / "Passed: 7345" / "Failed: 1" / "Test Run Failed." +- The runner then threw at Invoke-MSTestWithCoverage.ps1 line 262: "MSTest with coverage failed with exit code 1"; no "First-party coverage:" line, no "Coverage projection: " line and no "Test-result summary: " line were printed, so no projection or summary was copied for this iteration. +- Failed test: RemainingLoadActive_AcrossAsyncVoidFirstAwait_StaysTrueWhileLoaderProduces (QuickFiler.Test/Controllers/QfcDatamodelLivenessTests.cs, line 192 via StartHeldOpenLoader line 172) +- Error message: "Expected entered.Task.Wait(TimeSpan.FromSeconds(5)) to be True because the started worker must reach the injected loader, but found False." +- "Coverage output" and "Results File" lines printed absolute paths under \coverage\ (placeholders applied, convention 4). + +Attribution: this change edits no C# source file. The only QuickFiler.Test change removes two Exists()-guarded Import elements whose package folder was never restored (P0-T5 ALTCOVER-RESTORED False), so the compiled test assembly is unaffected. The same test passed in the P0-T12 baseline (7346 of 7346). The failure is a five-second wall-clock wait inside the test that did not complete under a full parallel run, which is a pre-existing timing dependence outside the Write Set; it is reported to the caller and is not repaired on this branch. + +Loop action (convention 8): P2-T7 failed, so the loop restarts at P2-T1 with the artifact suffix iter2. No Write Set file is changed by the restart. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter2.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter2.2026-09-28T20-01.md new file mode 100644 index 000000000..9229e5247 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter2.2026-09-28T20-01.md @@ -0,0 +1,28 @@ +# P2-T7 — C# QC step 4, MSTest with coverage (iteration 2) + +Timestamp: 2026-09-30T11-06 +Command: pwsh -NoProfile -Command 'Set-Location ""; & "\scripts\vscode\Invoke-MSTestWithCoverage.ps1" -SearchRoot .' (run detached with its combined output redirected to a session scratch log outside the repository; the script and its arguments are unchanged) +EXIT_CODE: 0 +Output Summary: +- "Test Run Successful." +- "Total tests: 7346" / "Passed: 7346" +- First-party coverage: lines 56479/65736 (85.92%), branches 13657/17054 (80.08%) +- Line percentage 85.92; branch percentage 80.08 +- MEETS-85: true (observation only, convention 10) +- Test-result summary (copied): total 7346, executed 7346, passed 7346, failed 0; skipped 0 (derived); error 0, timeout 0, aborted 0, notExecuted 0, inconclusive 0; failed tests: none +- Path-printing lines, with host prefixes replaced (convention 4): + - "Using vstest.console: \Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe" + - "Coverage output: \coverage\coverage.cobertura.xml" + - "Coverage projection: \coverage\coverage.cobertura.jacoco.xml" + - "Test-result summary: \coverage\test-results\mstest-coverage-run.summary.txt" + - "Done. Coverage artifact: \coverage\coverage.cobertura.xml" + +Copies: +- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml — 1467 bytes; root element report; 9 package elements; PROJECTION-RAW-ELEMENTS: 0 +- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt — 298 bytes + +Reconciliation: the projection's package LINE covered sum is 56479, equal to the line numerator on the printed line. + +The raw Cobertura and trx documents stay under the ignored coverage directory and are not copied. + +Iteration note: iteration 1 of this step failed on one timing-dependent test (qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md); this iteration ran the same command on the same tree with no file changed between the two runs. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt new file mode 100644 index 000000000..81b9a776b --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt @@ -0,0 +1,5 @@ +Test run outcome: Completed +Total 7346, executed 7346, passed 7346, failed 0. +Skipped 0, derived as total minus executed rather than reported by the test platform. +Figures reported verbatim by the test platform: error 0, timeout 0, aborted 0, notExecuted 0, inconclusive 0. +Failed tests: none diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t8-attestation-and-coverage-delta.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t8-attestation-and-coverage-delta.2026-09-28T20-01.md new file mode 100644 index 000000000..1d8b44a9a --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t8-attestation-and-coverage-delta.2026-09-28T20-01.md @@ -0,0 +1,34 @@ +# P2-T8 — Single-pass attestation and coverage reconciliation + +Timestamp: 2026-09-30T11-07 +Command: Read the seven final-iteration (iter2) artifacts P2-T1 to P2-T7 and the P0-T12 and P0-T16 baselines; compute the deltas below. +EXIT_CODE: 0 +Output Summary: + +Final iteration: iter2 (iteration 1 failed at P2-T7 on one timing-dependent MSTest test; see qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md). + +| Task | Artifact | EXIT_CODE | Expected | Timestamp | +|---|---|---|---|---| +| P2-T1 | docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter2.2026-09-28T20-01.md | 0 | 0 | 2026-09-30T10-55 | +| P2-T2 | docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter2.2026-09-28T20-01.md | 0 | 0 | 2026-09-30T10-56 | +| P2-T3 | docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md | 0 | 0 | 2026-09-30T10-58 | +| P2-T4 | docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter2.2026-09-28T20-01.md | 0 | 0 (the P0-T9 exit code) | 2026-09-30T11-00 | +| P2-T5 | docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter2.2026-09-28T20-01.md | 0 | 0 | 2026-09-30T11-01 | +| P2-T6 | docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter2.2026-09-28T20-01.md | 0 | 0 | 2026-09-30T11-02 | +| P2-T7 | docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter2.2026-09-28T20-01.md | 0 | 0 | 2026-09-30T11-06 | + +- All seven exit codes equal their expected values. +- The seven timestamps are non-decreasing in task order and all seven artifacts carry the iter2 suffix. + +C# coverage (P2-T7 iter2 minus P0-T12): +- Line: 85.92 minus 85.91 = +0.01 percentage points (at least -0.5) +- Branch: 80.08 minus 80.08 = 0.00 percentage points (at least -0.5) + +PowerShell coverage (CI Pester job): +- Aggregate on the pushed head: 94.51 percent (run 36722780748, head b96926588d562f994430e7ba7301de5de86f206c, Pester job 109911885533 conclusion success); at least 80 +- Baseline: 94.51 percent (run 36666302259 on main, head 231e1c0b55105aeb626bf5a6e8d0266a567cacad, Pester job 109731601928 conclusion success) +- ConsistencyVerifier.psm1 covered: 158 on the pushed head versus 158 at baseline (at least the P0-T16 value); missed 2 versus 2 +- No PowerShell branch figure exists: Pester emits no branch counter. +- This change adds no new module, so no 90 percent new-module gate applies. + +Result: no blocking regression; no delta below -0.5. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t9-file-size-audit.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t9-file-size-audit.2026-09-28T20-01.md new file mode 100644 index 000000000..fbfdc506a --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t9-file-size-audit.2026-09-28T20-01.md @@ -0,0 +1,13 @@ +# P2-T9 — File size audit of the change footprint + +Timestamp: 2026-09-30T11-08 +Command: pwsh -NoProfile -Command 'Set-Location ""; foreach ($p in ) { "LINECOUNT " + $p + " " + @(Get-Content -LiteralPath $p).Count }' +EXIT_CODE: 0 +Output Summary: +- QuickFiler.Test/QuickFiler.Test.csproj: 568 (the post-merge 570 minus the two deleted imports) +- SVGControl/app.config: 23 +- .github/workflows/dependabot-repair.yml: 173 +- scripts/dependencies/ConsistencyVerifier.psm1: 499 (equals VERIFIER-LINES 499; at most 500) +- tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1: 337 (at most 500) +- tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1: 152 (at most 500) +- Exactly 6 files listed. Markdown files (the workflows README, the 911 runbook, issue.md and the plan) are exempt from the 500-line cap and are deliberately not listed. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t1-tree-test-authored.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t1-tree-test-authored.2026-09-28T20-01.md new file mode 100644 index 000000000..0a56ad91e --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t1-tree-test-authored.2026-09-28T20-01.md @@ -0,0 +1,21 @@ +# P1-T1 — Repository tree consistency test authored + +Timestamp: 2026-09-30T10-00 +Command: Write tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1; then pwsh -NoProfile -Command 'Set-Location ""; (BOM, CR byte, non-ASCII byte and line counts); Select-String -Pattern "^\s*It '"'"'" ...; Select-String -Pattern "Start-Sleep","GetTempFileName","New-TemporaryFile","Mock" ...; Select-String for It, Describe or Context names matching AC followed by a digit' (the quote character built from [char]39 for the name checks) +EXIT_CODE: 0 +WORKER: atomic-executor authored the file inline; no sub-agent dispatch tool is available to this executor, so the powershell-typed-engineer hand-off was performed within exactly the P1-T1 bounds. +Output Summary: +- File created: tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 +- Encoding: UTF-8 with BOM (BOM=True); line endings LF (0 CR bytes); ASCII content (0 bytes above 127 after the BOM) +- Line count: 152 (at most 200) +- Set-StrictMode -Version Latest; BeforeAll resolves $script:RepoRoot from $PSScriptRoot as ConsistencyVerifier.Tests.ps1 line 4 does and imports scripts/dependencies/ConsistencyVerifier.psm1 with -Force +- One Describe: 'Repository tree consistency (issue 929)' +- It lines matching ^\s*It ': 4, named verbatim: + 1. 'reports no Import element whose package the sibling manifest omits, for every project directory that carries a manifest' + 2. 'names in the SVGControl binding redirects the assembly version the SVGControl project reference declares' + 3. 'passes client-id and not app-id to the create-github-app-token step of the repair workflow' + 4. 'instructs the maintainer to store the Client ID in the secret the repair workflow reads by name' +- Select-String for Start-Sleep, GetTempFileName, New-TemporaryFile and Mock: 0 lines +- It, Describe or Context names matching AC followed by a digit: 0 +- Test 1 formats each finding as ": line "; test 3 carries -Because text containing client-id and app-id; test 4 carries -Because text containing secret name and client-id. +- The step-block helper re-implements the Get-WorkflowStepBlock approach locally (it is not dot-sourced); both helpers are defined inside BeforeAll. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md new file mode 100644 index 000000000..eb479a1ec --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md @@ -0,0 +1,24 @@ +# P1-T11 — Tree consistency tests pass after the fix + +Timestamp: 2026-09-30T10-17 +Command: pwsh -NoProfile -Command '[DateTime]::UtcNow.ToString("o")' (RUN-START); MCP mcp__drm-copilot__run_poshqc_test (workspace_root , scan_folders ["tests/scripts/dependencies"]); CMD-JUNIT-READ +EXIT_CODE: 0 +Output Summary: +- RUN-START: 2026-09-30T13:29:57.2124290Z +- MCP payload (host prefix replaced): {"ok":true,"tool":"run_poshqc_test","workspace_root":"","summary":"Ran bundled PoshQC test against '' with 1 selected scan folder(s)."} +- JUNIT-WRITTEN=2026-09-30T13:30:27.3304471Z (later than RUN-START) +- JUNIT-ROOT tests=137 failures=0 errors=0 disabled=0 (131 plus 6) +- Exactly 8 JUNIT-SUITE lines: + - AnalyzerItemRepair.Tests.ps1 tests=13 failures=0 skipped=0 + - ConsistencyVerifier.Tests.ps1 tests=14 failures=0 skipped=0 + - DependabotConfig.Tests.ps1 tests=17 failures=0 skipped=0 + - PackageCompatibility.Tests.ps1 tests=8 failures=0 skipped=0 + - PackageGraph.Tests.ps1 tests=32 failures=0 skipped=0 + - ProjectConsistency.Tests.ps1 tests=18 failures=0 skipped=0 + - Repair-PackageManifestConsistency.Tests.ps1 tests=31 failures=0 skipped=0 + - RepositoryTreeConsistency.Tests.ps1 tests=4 failures=0 skipped=0 +- No JUNIT-NOTPASSED line. + +Fail-before / pass-after pair: the fail-before run is recorded at docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md (RepositoryTreeConsistency.Tests.ps1 tests=4 failures=4); this run records the same four tests passing. + +GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md new file mode 100644 index 000000000..36dd73f9b --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md @@ -0,0 +1,34 @@ +# P1-T2 — Tree consistency tests fail before the fix [expect-fail] + +Timestamp: 2026-09-30T10-02 +Command: pwsh -NoProfile -Command '[DateTime]::UtcNow.ToString("o")' (RUN-START); MCP mcp__drm-copilot__run_poshqc_test (workspace_root , scan_folders ["tests/scripts/dependencies"]); CMD-JUNIT-READ +EXIT_CODE: 1 +ExpectedExitCode: 1 +Output Summary: +- RUN-START: 2026-09-30T13:24:02.1235733Z +- MCP payload (host prefix replaced): {"ok": false, "tool": "run_poshqc_test", "workspace_root": "", "summary": "Command exited with code 4."} (ok false, as expected) +- JUNIT-WRITTEN=2026-09-30T13:24:39.4564261Z (later than RUN-START) +- JUNIT-ROOT tests=135 failures=4 errors=0 disabled=0 (131 + 4) +- JUNIT-SUITE AnalyzerItemRepair.Tests.ps1 tests=13 failures=0 skipped=0 +- JUNIT-SUITE ConsistencyVerifier.Tests.ps1 tests=12 failures=0 skipped=0 +- JUNIT-SUITE DependabotConfig.Tests.ps1 tests=17 failures=0 skipped=0 +- JUNIT-SUITE PackageCompatibility.Tests.ps1 tests=8 failures=0 skipped=0 +- JUNIT-SUITE PackageGraph.Tests.ps1 tests=32 failures=0 skipped=0 +- JUNIT-SUITE ProjectConsistency.Tests.ps1 tests=18 failures=0 skipped=0 +- JUNIT-SUITE Repair-PackageManifestConsistency.Tests.ps1 tests=31 failures=0 skipped=0 +- JUNIT-SUITE RepositoryTreeConsistency.Tests.ps1 tests=4 failures=4 skipped=0 + +Not-passed test cases (exactly four, all under the Describe 'Repository tree consistency (issue 929)'): + +1. JUNIT-NOTPASSED Repository tree consistency (issue 929).reports no Import element whose package the sibling manifest omits, for every project directory that carries a manifest + JUNIT-MESSAGE Expected 0, because these Import elements name a package the sibling manifest omits: QuickFiler.Test.csproj: line 8 altcover.8.6.45; QuickFiler.Test.csproj: line 537 altcover.8.6.45, but got 2. +2. JUNIT-NOTPASSED Repository tree consistency (issue 929).names in the SVGControl binding redirects the assembly version the SVGControl project reference declares + JUNIT-MESSAGE Expected strings to be the same, because the Fizzler redirect must name the referenced assembly version, but they were different. String lengths are both 7. Strings differ at index 4. Expected: '1.3.1.0' But was: '1.3.0.0' +3. JUNIT-NOTPASSED Repository tree consistency (issue 929).passes client-id and not app-id to the create-github-app-token step of the repair workflow + JUNIT-MESSAGE Expected 1, because the token step must pass exactly one client-id input read from a secret, but got 0. +4. JUNIT-NOTPASSED Repository tree consistency (issue 929).instructs the maintainer to store the Client ID in the secret the repair workflow reads by name + JUNIT-MESSAGE Expected a value, because the workflow client-id line must name the secret name the runbook has to match, but got $null or empty. + +Message literal checks: message 1 contains QuickFiler.Test.csproj and altcover.8.6.45; message 2 contains 1.3.0.0 and 1.3.1.0; message 3 contains client-id; message 4 contains secret name. No failure occurred in any other suite. + +GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t3-verifier-import-tests.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t3-verifier-import-tests.2026-09-28T20-01.md new file mode 100644 index 000000000..db367ed0d --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t3-verifier-import-tests.2026-09-28T20-01.md @@ -0,0 +1,24 @@ +# P1-T3 — Two Import-kind verifier tests and sibling comment updates + +Timestamp: 2026-09-30T10-04 +Command: Edit tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1; pwsh -NoProfile -Command '[DateTime]::UtcNow.ToString("o")' (RUN-START); MCP mcp__drm-copilot__run_poshqc_test (workspace_root , scan_folders ["tests/scripts/dependencies"]); CMD-JUNIT-READ; Select-String -SimpleMatch for the four stale phrases; Select-String for test names matching AC followed by a digit; @(Get-Content).Count +EXIT_CODE: 1 +ExpectedExitCode: 1 +WORKER: atomic-executor edited the file inline; no sub-agent dispatch tool is available to this executor, so the powershell-typed-engineer hand-off was performed within exactly the P1-T3 bounds. +Output Summary: +- Edits: the comment at lines 57 to 59 now states that the fixture reproduces the shape QuickFiler.Test/QuickFiler.Test.csproj carried at lines 8 and 537 until issue 929 removed both imports, keeps the no-hard-coded-exception sentence, and drops the "Tracked separately" sentence; the comment formerly at line 275 now reads "the shape QuickFiler.Test carried before issue 929"; two It blocks were added in the Context 'Package absent from the manifest' after the It block that began at line 228: + - 'reports an Import whose package the manifest does not declare, with Kind Import' + - 'reports no Import finding when the manifest declares the imported package' +- RUN-START: 2026-09-30T13:25:29.0090061Z +- MCP payload (host prefix replaced): {"ok": false, "tool": "run_poshqc_test", "workspace_root": "", "summary": "Command exited with code 4."} +- JUNIT-WRITTEN=2026-09-30T13:26:06.8242883Z (later than RUN-START) +- JUNIT-ROOT tests=137 failures=4 errors=0 disabled=0 +- JUNIT-SUITE ConsistencyVerifier.Tests.ps1 tests=14 failures=0 skipped=0 (12 existing plus 2) +- JUNIT-SUITE RepositoryTreeConsistency.Tests.ps1 tests=4 failures=4 skipped=0 (red by design until P1-T4 to P1-T9; decision D13) +- Every other suite at failures=0: AnalyzerItemRepair 13, DependabotConfig 17, PackageCompatibility 8, PackageGraph 32, ProjectConsistency 18, Repair-PackageManifestConsistency 31 +- The four JUNIT-NOTPASSED lines all name the RepositoryTreeConsistency tests +- Stale phrases ("carries a live instance", "live shape", "lines 8 and 514", "Tracked separately") over the file: 0 lines +- Test names matching AC followed by a digit: 0 +- File line count: 337 (at most 500) + +GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/feature-audit.2026-09-30T10-30.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/feature-audit.2026-09-30T10-30.md new file mode 100644 index 000000000..72365fea5 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/feature-audit.2026-09-30T10-30.md @@ -0,0 +1,80 @@ +# Feature Audit — package-manifest-consistency-residuals (Issue #929) + +- Artifact timestamp label: 2026-09-30T10-30 (caller-assigned) +- Work mode: `minor-audit` (issue.md line 12); AC source: the `## Acceptance Criteria` section of issue.md only (AC1 to AC7) +- Branch: `bug/package-manifest-consistency-residuals-929`; head `5ce3c8c3b`; source diff base `231e1c0b5` +- Companion artifacts: `policy-audit.2026-09-30T10-30.md`, `code-review.2026-09-30T10-30.md` +- Total blocking findings: **0** +- Verdict: **PASS** — 7 of 7 acceptance criteria evaluated PASS; every executor check-off stands; no criterion is to be unchecked + +## Executive Summary + +Each of the seven acceptance criteria was evaluated against the files on disk in the item worktree and against the executor's committed evidence, not against the executor's check-off notes alone. AC1 to AC3 and AC5 to AC6 are verifiable by direct reading and all hold. AC4 holds on the two added in-memory detector tests plus the tree census test's red-then-green pair and the read-only verifier run whose absent-from-manifest count moved from 2 to 0. AC7 holds on the cold restore, the aligned analyzer census (no back-fill was needed, so the permissive back-fill clause was not exercised), and the two toolchains passing on the final iteration with no regression against the Phase 0 baseline. The one CI test failure and the one local iteration-1 test failure are on pre-existing timing-dependent C# tests and are not attributable to a change that edits no C# source. No blocking finding exists; follow-ups are listed for the orchestrator and not filed from this branch. + +## Scope and Baseline + +- Baseline: `231e1c0b55105aeb626bf5a6e8d0266a567cacad` (origin/main at merge 3091b8af9; P0-T1 BASE-SHA). Baseline measurements: MSTest 7346 of 7346, C# 85.91% lines / 80.08% branches (P0-T12); CI Pester on main run 36666302259: 373 passed, 94.51% lines (P0-T16); analyzer census `ANALYZER-ITEM-STATE: aligned`, `ANALYZER_ITEMS=162 FILES=17 UNRESOLVED=0` (P0-T6); pre-fix altcover lines 2 and verifier `ABSENT=2` (P0-T17); pre-fix redirect repairs 1 and 1 (P0-T18). +- Post-change: MSTest 7346 of 7346, C# 85.92% / 80.08% (P2-T7 iter2); CI Pester on branch run 36722780748 head `b96926588`: 379 passed, 94.51% (P2-T3 iter2); verifier `ABSENT=0` (P1-T12); redirect repairs 0 and 0 (P1-T5). +- Diff scope (P2-T10, verified on disk): `.github/workflows/README.md`, `.github/workflows/dependabot-repair.yml`, `QuickFiler.Test/QuickFiler.Test.csproj`, `SVGControl/app.config`, the 911 runbook, `scripts/dependencies/ConsistencyVerifier.psm1`, `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1`, `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1`, the promoted record, and the feature folder. Zero `.cs` files; zero other `.csproj`, `packages.config` or `app.config` files. +- Method: Read, Grep and Glob only (caller constraint). Branch head read from the worktree's git ref file. PR context artifacts are absent in the worktree and were not regenerable; scope was triangulated from the caller's diff, P2-T10 and disk. + +## Acceptance Criteria Inventory + +Source: `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md`, section `## Acceptance Criteria`, lines 44-50. Seven checkbox items, all `[x]` at review start. The maintainer follow-up paragraph (line 52) and Summary item 4 are not acceptance criteria and are not evaluated as such. + +| ID | Criterion (abridged) | State at review start | +|---|---|---| +| AC1 | No `altcover` `Import` in `QuickFiler.Test.csproj`; case-insensitive search across tracked project files and manifests returns zero | `[x]` | +| AC2 | `SVGControl/app.config` Fizzler redirect newVersion 1.3.1.0 and oldVersion range ending at 1.3.1.0, matching the project reference | `[x]` | +| AC3 | `SVGControl/app.config` System.Runtime.CompilerServices.Unsafe redirect newVersion 6.0.3.0 and range ending at 6.0.3.0, matching the project reference | `[x]` | +| AC4 | Verifier reports an Import whose package is absent from the manifest and no finding when declared; both covered by in-memory Pester tests, no temporary files; zero findings against the tree after AC1 | `[x]` | +| AC5 | Workflow passes `client-id`, no `app-id`; actionlint clean | `[x]` | +| AC6 | Runbook instructs storing the Client ID (not the numeric App ID) in the secret the workflow reads, naming it exactly | `[x]` | +| AC7 | Cold restore, solution rebuild succeeds (permissive back-fill clause), C# and PowerShell toolchains pass with no new failures relative to the Phase 0 baseline | `[x]` | + +## Acceptance Criteria Evaluation + +| ID | Verdict | Blocking | Evidence (reviewer-verified) | +|---|---|---|---| +| AC1 | PASS | No | Grep `altcover` (case-insensitive) over `*.csproj`, `*.config`, `*.props`, `*.targets` in the worktree: 0 matches. P1-T4: `ALTCOVER_LINES=0` over `*.csproj` and `*/packages.config` (P0-T17 measured 2), file 570 to 568 lines, the two deleted lines quoted verbatim. Residue: two tracked `.csproj.bak` copies still carry the token; they are not project files (MSBuild never reads `.bak`) and are outside the criterion's stated pathspec — recorded as a follow-up, not a gap. | +| AC2 | PASS | No | `SVGControl/app.config` line 15: `oldVersion="0.0.0.0-1.3.1.0" newVersion="1.3.1.0"`; `SVGControl/SVGControl.csproj` line 58: `Fizzler, Version=1.3.1.0`; `packages.config` line 4 pins Fizzler 1.3.1. P0-T18 `FIZZLER_ASM=1.3.1.0`; P1-T5 `FIZZLER_REPAIRS=0`. Tree test 2 green (P1-T11). | +| AC3 | PASS | No | `SVGControl/app.config` line 19: `oldVersion="0.0.0.0-6.0.3.0" newVersion="6.0.3.0"`; `SVGControl.csproj` line 82: `System.Runtime.CompilerServices.Unsafe, Version=6.0.3.0` (package 6.1.2 ships assembly version 6.0.3.0; P0-T18 `UNSAFE_ASM=6.0.3.0`); P1-T5 `UNSAFE_REPAIRS=0`. Tree test 2 green. | +| AC4 | PASS | No | Positive case: `ConsistencyVerifier.Tests.ps1` lines 240-251 (`GuardedUnmanifestedProject` fixture at 60-71, two guarded altcover Imports; FindingCount 2, every Kind `Import`, every PackageFolder `altcover.8.6.45`). Negative case: lines 253-263 (`AgreeingProject` declares its imported package; Import-kind subset empty; ExaminedCount greater than 0). Fixtures are here-strings; Grep over both test files for `Out-File`, `Set-Content`, `Add-Content`, `New-Item`, `New-TemporaryFile`, `[System.IO.File]::Write*`, `Remove-Item`: none. Suite: 14 of 14 (P1-T3 onward). Tree: `RepositoryTreeConsistency.Tests.ps1` test 1 red with 2 findings on the base tree (P1-T2 message names lines 8 and 537 of `QuickFiler.Test.csproj`) and green after AC1 (P1-T11); read-only verifier `ABSENT=0` (P1-T12) versus 2 (P0-T17). The detection rule pre-existed (plan decision D1); the criterion asks for the behaviour and its tests, both of which are present. | +| AC5 | PASS | No | `dependabot-repair.yml` line 51: `client-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }}`; Grep `app-id` under `.github/workflows`: no match. actionlint 1.7.7 scoped and repository-wide exit 0 with no output (P1-T7); CI actionlint job on run 36722780748 succeeded. Tree test 3 green. | +| AC6 | PASS | No | Runbook line 99 heading "Record the Client ID and generate a private key"; lines 101-106 instruct recording the Client ID and state the numeric App ID is not needed; lines 129-131 create the secret named `DEPENDABOT_REPAIR_APP_ID` with "the Client ID value recorded in step 10"; line 154 YAML sample `client-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }}`, identical to workflow line 51. Tree test 4 extracts the secret name from the workflow and asserts it in the runbook (green). README line 116 aligned. Cosmetic residue at line 301 ("App ID location") noted in the code review. | +| AC7 | PASS | No | Cold restore: P0-T5 `PACKAGE_DIRS_BEFORE=0`, `PACKAGE_DIRS_AFTER=172`, `Build succeeded.`, 0 errors. Analyzer census aligned, `UNRESOLVED=0` (P0-T6), so no back-fill occurred and the permissive clause was not exercised; P2-T10 records 0 other `.csproj`, `packages.config` or `app.config` paths changed. Rebuilds: P0-T10, P0-T11, P2-T5 iter2, P2-T6 iter2 each `Build succeeded.` 0 warnings 0 errors. C# toolchain final iteration: CSharpier check exit 0 (P2-T4), analyzer and nullable rebuilds exit 0, MSTest 7346 of 7346 with 85.92% / 80.08% (P2-T7 iter2) against baseline 7346 of 7346 with 85.91% / 80.08%. PowerShell toolchain: PoshQC format rewrote nothing (P2-T1), analyze pass (P2-T2), test 137 of 137 (P2-T3) against 131 of 131 baseline; CI Pester 379 of 379 at 94.51% against 373 of 373 at 94.51%. No new failure relative to the Phase 0 baseline. Iteration 1's single MSTest failure and CI run 36722780748's single `mstest-coverage` failure are assessed below as not attributable. | + +## Acceptance Criteria Check-off + +- Newly checked off by the reviewer: none (all seven were already `[x]`). +- Left unchecked or recommended to uncheck: none. Each criterion evaluated PASS, so every existing `[x]` stands. +- `issue.md` was not modified by this review. + +### Acceptance Criteria Status +- Source: `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` (`## Acceptance Criteria`) +- Total AC items: 7 +- Checked off (delivered): 7 +- Remaining (unchecked): 0 +- Items remaining: none + +## CI Failure Attribution + +- CI run 36722780748 (workflow_dispatch, head `b96926588`): `pester`, `build-analyzers`, `build-nullable`, `format-check`, `actionlint`, `hygiene` succeeded; `mstest-coverage` failed 1 of 7346 (`Transaction_SecondCallerCannotInstallUntilTheFirstRestores`, `QuickFiler.Test/Controllers/QfcItemController.UiThreadDispatcherFixtureTests.cs` line 206, a dispatcher-fixture concurrency test). +- Local final QC iteration 1 failed a different test (`RemainingLoadActive_AcrossAsyncVoidFirstAwait_StaysTrueWhileLoaderProduces`, `QfcDatamodelLivenessTests.cs` line 189, a five-second wall-clock wait); iteration 2 on the unchanged tree passed 7346 of 7346, as did the Phase 0 baseline. +- Attribution: this change edits no `.cs` file. The only QuickFiler.Test edit removes two `Exists()`-guarded imports whose target folder is never restored (no manifest declares altcover; P0-T5 `ALTCOVER-RESTORED: False`; CI has no cache fallback since issue 936), so the compiled test assembly is unchanged. Both tests exist on the base tree (they arrived via the origin/main merge) and both passed twice locally on this tree. Two different tests failing once each on two different hosts is the signature of pre-existing timing dependence, not of this diff. Verdict: not attributable; AC7's "no new failures relative to the Phase 0 baseline" holds on the local baseline-versus-final comparison it names. +- Residual gate owned by the orchestrator: the PR-time CI run on the branch head `5ce3c8c3b` (CI has so far built only `b96926588`; the later commits are feature-folder evidence and the second origin/main merge). + +## Recommended Follow-ups (list only; not filed from this branch) + +1. Promote the two timing-dependent QuickFiler.Test tests (`QfcDatamodelLivenessTests.cs` line 189 wall-clock `Task.Wait`; `QfcItemController.UiThreadDispatcherFixtureTests.cs` line 206) to an issue under the determinism rule (no real wall-clock waits in test code). +2. Delete the eight tracked `*.csproj.bak` copies listed in P0-T1 BAK-TRACKED; two still carry the `altcover` token. +3. Runbook line 301: reword "App ID location" to "Client ID location". +4. `dependabot-repair.yml` line 14: re-wrap the header comment. +5. Optional test hardening in `RepositoryTreeConsistency.Tests.ps1`: split test 2 per assembly; assert test 1 skips no manifest directory. +6. Maintainer follow-up already recorded at P2-T19 (not a merge gate): provision the GitHub App credential with `DEPENDABOT_REPAIR_APP_ID` holding the Client ID, confirm the secret store for a Dependabot-triggered `workflow_run`, then exercise AC18 to AC20 of issue 911 and obtain the first green run of the modified workflow. +7. Pre-existing: eleven other `app.config` files redirect Fizzler to 1.3.0.0 (tracked in `docs/features/potential/2026-08-04-stale-fizzler-and-unsafe-binding-redirects.md`). +8. Executor evidence hygiene: `Timestamp:` labels should be clock readings; on this run they lead the embedded UTC stamps by 38 to 72 minutes. + +## Summary + +Verdict PASS. 7 of 7 acceptance criteria PASS; 0 blocking findings; no remediation inputs. The delivered change satisfies the issue's invariant (a project's files and its own `packages.config` agree, and the repair workflow is runnable once its credential exists) with a minimal diff, a red-then-green regression suite, and toolchain evidence that reconciles to the committed projections and the CI logs. The orchestrator's remaining gate is the PR-time CI run on the branch head. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md new file mode 100644 index 000000000..ca8e11c35 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md @@ -0,0 +1,83 @@ +# package-manifest-consistency-residuals (Issue #929) + +- Date captured: 2026-09-28 +- Author: Dan Moisan +- Status: Promoted -> docs/features/active/package-manifest-consistency-residuals/ (Issue #929) + +> Automation note: Keep the section headings below unchanged; the promotion tooling maps each of them into the GitHub bug issue template. + +- Issue: #929 +- Issue URL: https://github.com/drmoisan/TaskMaster/issues/929 +- Last Updated: 2026-09-28 +- Work Mode: minor-audit + +## Summary +Consolidates #912 with the remaining parts of #914. PRs #920 and #921 fixed 8 of the 10 stale binding redirects and the `Invoke-ProjectConsistencyRepair` fallback defect. All remaining items break one invariant: a project's files and its own `packages.config` must agree, and the repair workflow that maintains them must be runnable. + +1. **#912:** `QuickFiler.Test/QuickFiler.Test.csproj` lines 8 and 535 import `altcover.8.6.45` build assets. No `packages.config` declares `altcover`, so the imports are silently skipped by their `Exists()` guard. +2. **#914 sub-item 3 residual:** two binding redirects in `SVGControl/app.config` are still stale: + - `Fizzler` redirects to 1.3.0.0, but the reference and the restored package are 1.3.1.0. + - `System.Runtime.CompilerServices.Unsafe` redirects to 6.0.2.0, but the reference and the restored package are 6.0.3.0. +3. **#914 comment item 1:** `.github/workflows/dependabot-repair.yml:51` passes the deprecated `app-id` input to `actions/create-github-app-token@v3`. It should pass `client-id`, and the runbook should say to store the App's Client ID. +4. **#914 sub-item 1 (verification only, requires the maintainer):** AC18, AC19 and AC20 of #911 can only be exercised after a GitHub App credential is provisioned. The runbook is at `docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md`. The secret store is also unconfirmed: a Dependabot-triggered `workflow_run` may read only Dependabot secrets. None of this is a merge gate for items 1 to 3. + +## Environment +- OS/version: Windows 11 Pro 10.0.26200 +- Python version: not applicable (.NET Framework 4.8.1 packages.config projects, GitHub Actions) +- Command/flags used: `nuget restore TaskMaster.sln` from cold; static inspection on `main` at `177b6d78e` +- Data source or fixture: `QuickFiler.Test/QuickFiler.Test.csproj`, `QuickFiler.Test/packages.config`, `SVGControl/app.config`, `SVGControl/packages.config`, `.github/workflows/dependabot-repair.yml` + +## Steps to Reproduce +1. `git grep -n altcover -- "*.csproj" "*packages.config"` finds two imports and no manifest entry. +2. Compare the `SVGControl/app.config` `bindingRedirect newVersion` values for `Fizzler` and `System.Runtime.CompilerServices.Unsafe` with the referenced assembly versions. +3. Read `dependabot-repair.yml:51`. + +## Expected Behavior +- Every `..\packages\` import corresponds to a manifest entry. +- Every binding redirect names the assembly version that actually ships. +- The repair workflow uses the non-deprecated input. + +## Acceptance Criteria + +Derived on 2026-09-28 from the Expected Behavior section and Summary items 1 to 3 (the orchestrator added this section because the promoted record carried none). Summary item 4 is maintainer-credential-gated and is deliberately not an acceptance criterion; see the maintainer follow-up note below the list. + +- [x] AC1: `QuickFiler.Test/QuickFiler.Test.csproj` contains no `Import` element that references an `altcover` package path; a case-insensitive search for the token altcover across every tracked project file and packages manifest in the repository returns zero matches. +- [x] AC2: In `SVGControl/app.config`, the `Fizzler` binding redirect names newVersion 1.3.1.0 and an oldVersion range ending at 1.3.1.0, matching the assembly version of the `Fizzler` reference in the SVGControl project file. +- [x] AC3: In `SVGControl/app.config`, the `System.Runtime.CompilerServices.Unsafe` binding redirect names newVersion 6.0.3.0 and an oldVersion range ending at 6.0.3.0, matching the assembly version of the corresponding reference in the SVGControl project file. +- [x] AC4: The package-manifest consistency verifier from issue 911 (the ConsistencyVerifier module under the scripts dependencies folder) reports a finding for a project whose file imports a build asset from a package directory whose package id is absent from that project's own packages manifest, and reports no such finding when the manifest declares the package. Both cases are covered by Pester tests whose fixtures are held in memory, with no temporary files, and the new detection reports zero findings against the repository tree after AC1 is applied. +- [x] AC5: `.github/workflows/dependabot-repair.yml` passes `client-id` and no longer passes `app-id` to the `actions/create-github-app-token` step, and actionlint reports no error for that workflow. +- [x] AC6: `docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md` instructs the maintainer to store the GitHub App's Client ID (not the numeric App ID) in the secret the workflow reads, and names that secret exactly as the workflow names it. +- [x] AC7: After a cold package restore, the solution rebuild succeeds (a pre-existing analyzer package that the project files reference at a version no packages manifest declares may be back-filled into the ignored packages folder, provided the back-fill is recorded in evidence as a pre-existing out-of-scope defect and not repaired on this branch) and the repository C# toolchain (format check, analyzer rebuild, nullable rebuild, MSTest with coverage) and the PowerShell toolchain (PoshQC format, analyze, test) pass with no new failures relative to the Phase 0 baseline. + +Maintainer follow-up (not an acceptance criterion and not a merge gate): acceptance criteria AC18, AC19 and AC20 of issue 911 remain deferred to the maintainer until a GitHub App credential is provisioned, and the secret store (repository Actions secrets versus Dependabot secrets for a Dependabot-triggered workflow_run) remains to be confirmed by the maintainer. This item records that deferral and does not mark those criteria passed. + +## Actual Behavior +As listed in the Summary. + +## Logs / Screenshots +- [x] Attached minimal logs or snippet +- Snippet: run https://github.com/drmoisan/TaskMaster/actions/runs/36281113978 fails at `Mint an installation token` with the deprecation warning for `app-id` (see the #914 comment of 2026-09-26). + +## Impact / Severity +- [ ] Blocker +- [ ] High +- [x] Medium +- [ ] Low + +## Suspected Cause / Notes +- The altcover imports are left over from an evaluation whose manifest entry was removed. +- The #911 repair pass reconciles redirects only for packages it upgraded, so the pre-existing drift in `SVGControl` was left in place. + +## Proposed Fix / Validation Ideas +- [ ] Delete both altcover `` elements. AltCover is not used by the coverage route, which is `dotnet-coverage`. +- [ ] Correct the two `SVGControl/app.config` redirects, preferably by running `scripts/dependencies/Repair-PackageManifestConsistency.ps1` rather than editing by hand. +- [ ] Switch `app-id` to `client-id` in the workflow, update the runbook, and confirm with actionlint. +- [ ] Add a verifier test case to the #911 consistency verifier that detects "an import whose package is absent from the manifest". Use the altcover case as the fixture shape, held in memory without temporary files. +- [ ] Rebuild the solution after a cold restore to confirm it still succeeds. +- [ ] Record AC18 to AC20 as deferred to the maintainer and cite the runbook. Do not mark them passed. + +## Next Step +- [x] Promote to GitHub issue (bug-report template) +- [ ] Move to active fix folder / branch + +Consolidates: #912, #914 (sub-items 1, 3 residual, and the `client-id` comment). #914 sub-item 2 moved to the coverage-runner item. #914 sub-item 4 is fixed by PR #920. \ No newline at end of file diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/plan.2026-09-28T20-01.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/plan.2026-09-28T20-01.md new file mode 100644 index 000000000..b25bb88bf --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/plan.2026-09-28T20-01.md @@ -0,0 +1,383 @@ +# package-manifest-consistency-residuals (Issue #929) — Atomic Plan + +- **Issue:** #929 (bug, minor-audit) +- **Branch:** bug/package-manifest-consistency-residuals-929 +- **Feature folder:** docs/features/active/2026-09-28-package-manifest-consistency-residuals-929 +- **Owner:** drmoisan +- **Last Updated:** 2026-09-30T08-32 +- **Status:** Draft (revision 3.2, 2026-09-30: the preflight round 5 delta D-1 applied in place; the P2-T1 formatter-rewrite branch keys its commit on git diff --numstat HEAD and records a terminator-only rewrite without a commit, because .gitattributes line 4 sets `* text=auto`; awaiting preflight round 6) +- **Version:** 1.3.2 +- **Task Count:** 56 (Phase 0: 21, Phase 1: 14, Phase 2: 21) +- **Work Mode:** minor-audit (persisted marker in issue.md line 12) +- **AC source:** the `## Acceptance Criteria` section of the feature folder's issue.md, AC1 to AC7, and nothing else. No spec.md, user-story.md or research.md exists in the feature folder and none may be created; their presence fails the run closed. AC7 carries the orchestrator's amendment permitting an evidence-recorded back-fill of a pre-existing analyzer package version into the ignored packages folder; the clause is permissive, and on the post-merge tree no back-fill is needed (P0-T6 expects UNRESOLVED=0), so a run that performs none satisfies AC7 with its text unchanged. + +## Conventions binding every task + +1. **Execution worktree.** Every command runs with the current directory at ``, the root of the non-isolated worktree the executor is given. Every pwsh invocation is written in the outer-single-quote, inner-double-quote form and begins with Set-Location to that root, because pwsh -File resolves a relative script path against the caller's directory and would run a sibling checkout's copy. A literal double quote inside such an inner string is written doubled, never backslash-escaped. A git command stated outside a pwsh invocation is issued as git -C followed by the stated arguments, with pathspecs kept repository-relative. No dotnet or msbuild command is issued outside a pwsh invocation that begins with Set-Location, because the Bash tool starts in the session checkout, which carries its own TaskMaster.sln and global.json. No gh-bearing command in this plan may contain the character sequence create: the pr-author PreToolUse hook (.claude/hooks/enforce-pr-author-skill-helpers.ps1 line 279) scans the whole command string, and for a wrapper-led segment such as pwsh -Command it applies ordinal case-insensitive containment of gh, pr and create in any arrangement (.claude/hooks/hook-command-invocation.ps1 lines 92 to 116 and 202 to 203), so a payload carrying -Property and createdAt is read as gh pr create and refused as PR_AUTHOR_SKILL_BLOCKED. +2. **Evidence location.** Every artifact lands under docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/ in one of the kinds baseline, regression-testing, qa-gates, other. Every artifact carries `Timestamp:` (yyyy-MM-ddTHH-mm), `Command:`, `EXIT_CODE:` (one row per artifact; further exit codes are named `Output Summary:` lines) and `Output Summary:`. An artifact that records a deliberately non-zero run carries `ExpectedExitCode:` with the observed value. +3. **Committed test evidence.** A coverage run is committed as the package-level JaCoCo projection plus the one-line first-party summary; a test run as the trx-derived summary. No raw .trx, raw .coverage, raw Cobertura document, raw Pester JaCoCo document or PoshQC JUnit document is copied under the evidence tree or named in any commit pathspec. The PoshQC test tool writes artifacts/pester/pester-junit.xml, artifacts/pester/powershell-coverage.xml and artifacts/pester/powershell-coverage.koverage.xml (all ignored at .gitignore line 57); the CI Pester job writes its JaCoCo document as the pester-coverage artifact, which the plan downloads under the coverage directory at the repository root (ignored at .gitignore line 150); in every case the figures are transcribed into the .md artifact, which stands in for a permitted form the section does not define for the Pester route. The CI hygiene guard (.github/workflows/_hygiene.yml, wired at ci.yml lines 36 to 38) fails the branch when a tracked .xml file's root element is report and it carries a class, sourcefile, method or line element (scripts/hygiene/Test-RepositoryHygiene.Rules.ps1 lines 114 to 119), so only the package-level projection may ever be committed. +4. **Hygiene.** No committed text (evidence, plan, issue, potential entry, runbook, README, workflow) may contain an absolute host path, a developer account name or a host name. Use the placeholders ``, ``, ``, ``, ``, ``. Record expressions such as Join-Path $env:TEMP, never their values. Tool output that prints an absolute path (for example the coverage runner's "Using vstest.console: ", "Coverage output: ", "Coverage projection: ", "Test-result summary: " and "Done. Coverage artifact: " lines at Invoke-MSTestWithCoverage.ps1 lines 373, 375, 423, 447 and 456, the restore script's "Using MSBuild: " line, gh's "The file exists." download error line and -WhatIf target names) is recorded with the prefix replaced by its placeholder. The PoshQC JUnit document names every testsuite and testcase classname by absolute path and carries machine-name and user properties: only the leaf file name (Split-Path -Leaf) and the testcase name are ever transcribed, and a failure message carrying a path is transcribed with the prefix replaced by ``. The CI hygiene guard's rule B (Test-RepositoryHygiene.Rules.ps1 line 21) additionally fails the branch on any tracked line carrying a drive letter, a colon and a users segment, which the placeholders above never produce. A CMD-HYGIENE hit at any task that runs it (P0-T20, P1-T14, P2-T11, P2-T20, P2-T21) is remedied as P0-T20 states: the leaked value is replaced with its placeholder in the offending file this plan authored and CMD-HYGIENE is re-run until HITS=0, with the pre-fix hit count recorded; a hit in a scanned file this plan did not author stops the task with a report. +5. **Git mechanics.** Never run a whole-tree add. Stage with explicit pathspecs. Commit messages contain none of the characters dollar, backtick, less-than, greater-than, so any attribution trailer is written without angle brackets, matching the form of commit f0e9b4c53. Anchored diffs use ``, the merge-base of origin/main and HEAD recorded at P0-T1, ``, the head recorded at P0-T21, or ``, the head recorded at P0-T1, where a task says so. The branch merged origin/main at commit 3091b8af9 on 2026-09-30 (second parent 231e1c0b55105aeb626bf5a6e8d0266a567cacad, the origin/main tip at that time), so `` is that merged tip unless main has since merged this branch, and a two-point diff against it lists only this branch's own changes: none of main's 105 merged commits lies between `` and HEAD. The value is recorded, never asserted. Porcelain gates assert scope, never membership or count: the agent-memory tree under the .claude directory may carry entries at any time and is excluded from every scope clause; the presence of the plan file in porcelain is never asserted either way. +6. **No temporary files in tests, no sleeps.** The new Pester tests read tracked repository files resolved from $PSScriptRoot and hold every other fixture in memory. Start-Sleep, retries and timing hacks are prohibited in every test and in every command payload this plan states. Waiting for the CI run at P2-T3 is done by gh run watch, the GitHub CLI's own blocking poll, re-invoked unchanged when the executor's tool call times out before the run completes; each invocation is recorded. +7. **Out-of-bounds trees.** No task writes under the .claude directory tree, under .github/instructions, under the config directory, or to any C# source file. A solution-wide Rebuild is issued through the literal msbuild commands below and never through the Invoke-VSBuild.ps1 wrapper, because that wrapper invokes Sync-PackageReferences.ps1 first (scripts/vscode/Invoke-VSBuild.ps1 lines 250 to 253), which rewrites project files outside the Write Set. +8. **Loop rule for Phase 2.** The seven command tasks P2-T1 to P2-T7 run in order. If any of them fails, or rewrites a Write Set member, the loop restarts at P2-T1 and the next iteration's artifacts carry the suffix iter2, iter3 and so on. A PoshQC formatter rewrite of a tracked file outside the Write Set is pre-existing drift: P2-T1 reverts and lists it under D9, and it does not restart the loop. The C# formatter step P2-T4 runs the read-only check subcommand, which rewrites nothing, so no C# rewrite branch exists; P2-T4 states what a check failure does. `EXIT_CODE: SKIPPED` is not a passing outcome for any task in this plan. +9. **Check-off protocol.** One acceptance criterion per check-off task (P2-T12 to P2-T18). A check-off changes only `- [ ]` to `- [x]` on the criterion's line in issue.md and cites the artifacts it read. A criterion whose evidence is incomplete stays unchecked and the gap is recorded. +10. **Policy conflict, reported not resolved.** CLAUDE.md (highest precedence) states an 80 percent line floor and a four-step loop; .claude/rules/general-unit-test.md, .claude/rules/quality-tiers.md and .claude/rules/powershell.md state 85 percent and a seven-stage loop with no architecture, contract or integration stage configured for these files. This plan gates on CLAUDE.md; P0-T12, P0-T16, P2-T3 and P2-T7 each additionally record `MEETS-85:` true or false as an observation only, and the conflict is reported to the caller. The conflict is already tracked as open GitHub issue 668 (coverage threshold discrepancy between CLAUDE.md and the rules), so it is recorded here and not re-reported as a halt. +11. **PowerShell gates are MCP-and-CI sourced (coordinator ruling 2026-09-30).** Every local PowerShell format, analyze and test gate runs through the PoshQC MCP tools with the worktree path passed explicitly. The analyze tool's ok flag is the lint result and is recorded as "PoshQC analyze: pass (0 findings); tool reports no count". Test counts and failure messages come from the JUnit document the test tool writes; coverage figures come only from the CI Pester job (P0-T16 for the baseline run on main, P2-T3 for the run on this branch's pushed head). No raw Invoke-Pester or Invoke-ScriptAnalyzer invocation exists in this plan; a gate criterion that neither PoshQC nor CI can produce stops the task with a report. + +## Re-derived tree facts (planner, 2026-09-28, worktree agent-a74dcedbc13b789fd; round 1 revision at HEAD c417c249a, round 2 revision at HEAD 62448256a, round 3 revision on 2026-09-30 at HEAD 3091b8af9, the merge of origin/main 231e1c0b5) + +| Fact | Location | Consequence | +|---|---|---| +| Two Exists()-guarded altcover imports | QuickFiler.Test/QuickFiler.Test.csproj lines 8 (AltCover.props) and 537 (AltCover.targets); the file is 570 lines (re-derived 2026-09-30 after the merge, which added two lines above the second import; before the merge they were 8 and 535 in a 568-line file) | AC1 edit removes exactly these two lines; no Error guard names altcover | +| No manifest declares altcover | git grep over all packages.config returns nothing for altcover; two .csproj.bak copies also carry the token but are not project files | AC1 search pathspec is project files and manifests only; the .bak copies are recorded, not edited | +| Stale redirects | SVGControl/app.config line 15 (Fizzler 0.0.0.0-1.3.0.0 / 1.3.0.0) and line 19 (Unsafe 0.0.0.0-6.0.2.0 / 6.0.2.0); the file has four dependentAssembly blocks | AC2, AC3 | +| Reference versions | SVGControl/SVGControl.csproj line 58 (Fizzler, Version=1.3.1.0; HintPath line 59 under Fizzler.1.3.1) and line 82 (Unsafe, Version=6.0.3.0; HintPath line 83 under System.Runtime.CompilerServices.Unsafe.6.1.2); SVGControl/packages.config lines 4 and 10 pin 1.3.1 and 6.1.2 | Target values 1.3.1.0 and 6.0.3.0 | +| Repair script cannot reconcile these redirects | scripts/dependencies/Repair-PackageManifestConsistency.ps1 line 425 skips the redirect pass unless the run applied an upgrade, and line 177 skips a candidate equal to the current version | Decision D2: hand-edit, observe with the pure module function | +| Repair script verifies the repaired text, not the tree | scripts/dependencies/Repair-PackageManifestConsistency.ps1 lines 411 to 422 build the repaired project text in memory and pass it to Get-ProjectVerification, so a what-if run's VersionDisagreementCount describes the text after repair and may be 0 while the tree still disagrees | P0-T17 and P1-T12 record DISAGREE with no expectation | +| Redirect reconciliation function | scripts/dependencies/ProjectConsistency.psm1 lines 271 to 375 (parameters AppConfigText, AssemblyName, AssemblyVersion; result carries Text, Repair, ExaminedCount), exported at 377 to 381; returns Repair records only when the text changes | Pre-fix count 1 per assembly, post-fix count 0 | +| Absent-from-manifest detector already covers Import | scripts/dependencies/ConsistencyVerifier.psm1 lines 215 to 250; Import is a folder-bearing kind at scripts/dependencies/AnalyzerItemRepair.psm1 line 70; identity split at lines 95 to 126 keys on the manifest id, so a version-skewed known id is not "absent" | Decision D1: no new production rule | +| Stale comment in the detector | ConsistencyVerifier.psm1 lines 221 to 223 state QuickFiler.Test "carries a live instance"; the module is 499 lines (git grep -c and Get-Content agree; a viewer that renders the position after the final newline shows a 500th empty line) | Line-count-neutral comment replacement (P1-T10) | +| Existing in-memory altcover fixture | tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 lines 57 to 71 (comment at 57 to 59 cites lines 8 and 514, already stale, and carries a "Tracked separately" sentence), test at 272 to 290 (comment at 275 says "the live shape"); the file has 12 It blocks and 312 lines; header lines 7 to 10 forbid test names matching AC followed by a digit | Sibling comments updated; two explicit Import-kind tests added (P1-T3) | +| Tree-wide Import census | Every package id named by a packages-directory Import in all 18 project files is declared by that project's manifest, except altcover in QuickFiler.Test | The tree-level Import test can be tree-wide and reports zero after AC1 | +| Analyzer Include census | 162 Analyzer Include lines across 17 project files (re-derived 2026-09-30 on the post-merge tree; equals the 911 census); every item names a package folder its own directory's packages.config declares, and a search for Meziantou.Analyzer.3.0.235 over every project file returns 0 lines | P0-T6 pins 162 and 17 and expects UNRESOLVED=0 | +| Deprecated input | .github/workflows/dependabot-repair.yml line 49 uses actions/create-github-app-token@v3, line 51 passes app-id from secrets.DEPENDABOT_REPAIR_APP_ID, lines 13 to 14 describe the secret | AC5 | +| Runbook | docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md: Part B heading at line 99 reads "Record the App ID and generate a private key", step 10 at lines 101 to 106, step 22 at 129 to 132, YAML sample at 149 to 156 with app-id at 154, citations at 301 and 318 | AC6 | +| Workflows README | .github/workflows/README.md line 116 says the secret holds "the numeric App identifier" (line 115 before the merge; the table is at lines 114 to 117) | Sibling doc edit (P1-T9) | +| Existing workflow tests | tests/scripts/dependencies/DependabotConfig.Tests.ps1 has 17 It blocks, none asserting app-id; Get-WorkflowStepBlock at 156 to 178 is the step-parsing pattern; its AC26 test reads every backticked three-part version literal in the workflows README | Regression tests for AC5/AC6 use the same text-based style; the README edit adds no such literal | +| actionlint | scripts/dev-tools/run-actionlint.ps1 runs actionlint-bin/actionlint.exe over the repository; CI runs version 1.7.7 (.github/workflows/_actionlint.yml line 26); success prints nothing and exits 0 | Decision D4 | +| CI Pester scope | .github/workflows/_pester.yml line 41 runs tests/scripts/dependencies, tests/scripts/hygiene and tests/scripts/vscode; line 45 measures scripts/dependencies, scripts/hygiene and scripts/vscode; line 47 writes coverage/pester-coverage.xml; line 51 prints "PESTER Passed=... Failed=... Skipped=... Total=..."; line 64 prints "COVERAGE LinePercent=... Covered=... Total=..."; line 71 exits 1 below 80 percent; lines 74 to 80 upload that document as the artifact pester-coverage (one file). The tree holds 131 It blocks under tests/scripts/dependencies (7 files: AnalyzerItemRepair 13, DependabotConfig 17, PackageGraph 32, PackageCompatibility 8, ConsistencyVerifier 12, Repair-PackageManifestConsistency 31, ProjectConsistency 18), 31 under tests/scripts/hygiene (3 files) and 211 under tests/scripts/vscode (20 files), 373 in all | The new test file is collected by CI; CI is the coverage source (P0-T16, P2-T3); the local PoshQC test run over tests/scripts/dependencies reports 131 tests before this change and 137 after | +| CI trigger | .github/workflows/ci.yml (name: CI, line 1) triggers on push to main and development, on pull_request to those branches, and on workflow_dispatch (lines 3 to 8); jobs pester (lines 33 to 35) and hygiene (lines 36 to 38) | A push to this branch alone starts no CI run: P2-T3 dispatches ci.yml on the branch ref unless a run for the pushed head already exists | +| CI baseline run | ci.yml run 36666302259 on main at head 231e1c0b55105aeb626bf5a6e8d0266a567cacad, conclusion success; Pester job 109731601928 "pester / Run Pester suite with coverage" (coordinator-measured 2026-09-30: Tests Passed 373, Failed 0, Skipped 0; COVERAGE LinePercent=94.51 Covered=1721 Total=1821) | P0-T16 reads the run itself and records the figures it prints; the coordinator's figures are expectations, not acceptance values | +| CI hygiene guard | .github/workflows/_hygiene.yml runs scripts/hygiene/Test-RepositoryHygiene.ps1 (line 24), which enumerates tracked files (Test-RepositoryHygiene.Git.ps1 line 70), skips the .claude prefix (line 35 of the entry script), reports a raw test-platform or coverage-collector document by content (rule A, Rules.ps1 lines 88 to 122) and any line carrying a user-profile path (rule B, Rules.ps1 line 21), printing "HYGIENE Findings=N" and exiting 1 on any finding | The committed projection copies are package-level and classify as jacoco-projection; P2-T21 runs the guard locally before its commit | +| No CI package-cache fallback | .github/workflows/_build-analyzers.yml line 41 and _build-nullable.yml line 41 state "No restore-keys fallback (issue #936)" (the restore-keys lines the earlier revisions cited at 57 to 58 no longer exist) | The cache inference the removed P1-T13 entry would have stated is void; nothing in this plan depends on it | +| PoshQC test output | mcp__drm-copilot__run_poshqc_test writes artifacts/pester/pester-junit.xml (root testsuites with tests, errors, failures and disabled attributes; one testsuite per test file whose name attribute is the file's absolute path, with tests, failures and skipped attributes; one testcase per It with name equal to Describe dot Context dot It, a status attribute and an absolute-path classname; hostname, machine-name and user properties) and artifacts/pester/powershell-coverage.xml, whose counters read 0 covered, plus artifacts/pester/powershell-coverage.koverage.xml (a JaCoCo-shaped document with a report root; present in the worktree on 2026-09-30); all three are ignored at .gitignore line 57. The document present in the worktree on 2026-09-30 reads tests=131 failures=0 with ConsistencyVerifier.Tests.ps1 tests=12 and DependabotConfig.Tests.ps1 tests=17 | CMD-JUNIT-READ derives every local test count from it; the coverage document is never a coverage source | +| CSharpier and ignored XML | .csharpierignore (lines 4 to 8, 12 to 14, 16, 18) excludes the evidence tree, *.cobertura.xml, *.coverage, *.coveragexml, *.trx, project files, packages.config and app.config, and names neither artifacts/ nor coverage/; CSharpier 1.2.6 processes *.xml; whether it also honours .gitignore was not observed by the planner | P0-T9 and P2-T4 record the XML candidate list under artifacts/ and coverage/ beside "Checked N", and the P2-T4 gate admits a delta equal to the candidate-count delta or to zero, so those ignored files alone cannot break it | +| Formatter scope | .csharpierignore lines 12, 16, 18 exclude project files, packages.config and app.config; line 4 excludes the evidence tree | CSharpier never touches the edited files | +| Coverage runner | scripts/vscode/Invoke-MSTestWithCoverage.ps1 (461 lines after the merge; 26 lines changed by issue 928) lines 297 to 298 fix the results directory and trx name; line 313 dot-sources the new Invoke-MSTestWithCoverage.Scope.ps1 (scoped-run gate, issue 928); lines 344 to 346 throw when dotnet-coverage is absent; line 373 prints "Using vstest.console: " and line 375 "Coverage output: ", each with an absolute path; line 410 prints the one-line first-party report (format at Invoke-MSTestWithCoverage.FirstParty.ps1 line 120); lines 415 to 423 write and print the projection (line 423 prints "Coverage projection: " with an absolute path); lines 430 to 447 write and print the summary (warning at 436, "Test-result summary: " at 447); line 456 prints "Done. Coverage artifact: " with an absolute path; lines 459 to 461 guard the entry point; floors thrown at Invoke-MSTestWithCoverage.Threshold.ps1 lines 54 and 124 | CMD-MSTEST-COVERAGE; convention 4 names the path-printing lines | +| Bootstrap | global.json pins SDK 8.0.205 under .dotnet-sdk (lines 3 and 7); scripts/vscode/Install-RepoDotNetSdk.ps1 default version at line 3 and install directory .dotnet-sdk under the repository root at line 36; scripts/vscode/Invoke-Restore.ps1 parameters at lines 1 to 10 and its "Using MSBuild: " line at 101 prints an absolute path; .gitignore ignores artifacts (57), coverage (150, `coverage/*`), packages (197, `**/[Pp]ackages/*`) and .dotnet-sdk (356, `.dotnet*/`) | P0-T3 to P0-T7 | +| Analyzer items aligned | The merge of origin/main (analyzer-path hotfix 89e202ed6 among its 105 commits) removed the Meziantou.Analyzer.3.0.235 skew the earlier revisions described: the analyzer folders in use are AsyncFixer.2.1.0, Roslynator.Analyzers.5.0.0, Microsoft.CodeAnalysis.BannedApiAnalyzers.5.6.0, SonarAnalyzer.CSharp.10.34.0.3385, Meziantou.Analyzer.3.0.290 and MSTest.Analyzers.4.4.1, each declared by the sibling manifest | Decision D8 revised; a cold restore alone suffices; no back-fill, no nuget CLI, no potential entry | +| Pre-existing transitive Fizzler redirects | 13 app.config files redirect Fizzler: 12 to 1.3.0.0 (SVGControl plus 11 others), UtilitiesCS to 1.3.1.0; only SVGControl and UtilitiesCS carry a Fizzler Reference; already recorded in docs/features/potential/2026-08-04-stale-fizzler-and-unsafe-binding-redirects.md (Draft) | Decision D5: redirect test scoped to SVGControl | +| Promotion commit on the branch | The branch carries the promotion commit whose promoted record lies under docs/features/potential/promoted, outside the Write Set and the feature folder | CMD-FOOTPRINT is anchored at ``, not `` | + +## Decisions + +- **D1 — No new production detection rule.** The rule AC4 describes exists and is tested: Find-PackageAbsentFromManifest reports an Import whose package id the sibling manifest omits. AC4 is discharged by (a) two explicit in-memory Import-kind tests added beside the existing ones, (b) a new tree-reading regression test that fails on the current tree and passes after AC1, and (c) a read-only what-if run of the composition root whose AbsentFromManifestCount moves from 2 to 0. Editing the module for a rule it already has would be an opportunistic refactor. +- **D2 — Redirects are hand-edited.** The repair script reconciles binding redirects only for packages the run upgraded (line 425) and skips a candidate equal to the current version (line 177), so no invocation can rewrite the two SVGControl lines; running it with any candidate would also rewrite other manifests through normalisation. The read-only observation that no redirect drift remains is Invoke-BindingRedirectReconciliation over the file text for each assembly returning zero Repair records, paired with the pre-fix count of one each at P0-T18. +- **D3 — Secret name kept, value semantics changed.** The workflow keeps reading secrets.DEPENDABOT_REPAIR_APP_ID and passes it as `client-id`; the runbook and the workflows README instruct the maintainer to store the App's Client ID under that exact name. Reason: renaming would require maintainer credential action; the secret is not yet provisioned (issue item 4, 911 evidence p8-t1-credential-availability), so the token step already fails and the change is merge-safe without any maintainer action. AC6's "names that secret exactly as the workflow names it" is carried by a test that extracts the name from the workflow and asserts it in the runbook. +- **D4 — actionlint gate.** The local runner scripts/dev-tools/run-actionlint.ps1 (repository-wide) plus a workflow-scoped invocation of actionlint-bin/actionlint.exe are the AC5 gate. actionlint prints nothing on success and exits 0; the recorded -version line is the proof the binary ran. CI's 1.7.7 is recorded beside the local version. +- **D5 — Regression test file.** A new file tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 holds four tests (Import census, SVGControl redirects, workflow input, runbook secret). It reads tracked files resolved from $PSScriptRoot, the pattern DependabotConfig.Tests.ps1 already uses in this folder, and creates nothing on disk. The Import test is tree-wide because the census found no other violation. The redirect test is scoped to SVGControl because eleven other configs redirect Fizzler to 1.3.0.0 without a Reference to compare against; that residual is tracked by the 2026-08-04 potential entry and is not widened into this fix. +- **D6 — Line-count invariant.** ConsistencyVerifier.psm1 is 499 lines at the planning snapshot; the comment replacement at lines 221 to 223 is three lines for three lines. The gate is stated against `VERIFIER-LINES:`, the count P0-T13 records after the baseline format run as @(Get-Content -LiteralPath scripts/dependencies/ConsistencyVerifier.psm1).Count (expected 499), so a formatter rewrite in Phase 0 cannot make the gate unsatisfiable; the count must also be at most 500. Every later line count of that module uses the same Get-Content expression so the figures are comparable. +- **D7 — msbuild literal commands.** The analyzer and nullable gates use the exact CLAUDE.md commands with a file logger under the coverage directory, never the Invoke-VSBuild.ps1 wrapper (convention 7). Outlook must be closed by the user and is never terminated. +- **D8 — Analyzer items are aligned on the post-merge tree; the census is the evidence.** Revisions 1 and 2 described a skew (16 Analyzer Include items naming Meziantou.Analyzer.3.0.235 against manifests pinning 3.0.290) that made a cold rebuild fail CS0006 and required an environment back-fill. The origin/main merge at 3091b8af9 (hotfix 89e202ed6) removed it: on 2026-09-30 every one of the 162 Analyzer Include items names a folder its manifest declares and no project file names 3.0.235. AC7's "after a cold package restore, the solution rebuild succeeds" is therefore executed as: restore the solution (P0-T5), census every Analyzer Include for resolvability (P0-T6, expected UNRESOLVED=0 and `ANALYZER-ITEM-STATE: aligned`), then rebuild (P0-T10, P0-T11, P2-T5, P2-T6). No back-fill, no nuget CLI and no potential entry remain in the plan; an UNRESOLVED count above 0 at P0-T6 stops the run with a report, because it would describe a tree the coordinator has not measured. AC7's back-fill clause is permissive and stays unexercised; the P2-T18 check-off cites the aligned census and the P2-T10 zero count of other project files and manifests. +- **D9 — PowerShell scope.** PoshQC format, analyze and test run with scan_folders equal to scripts/dependencies and tests/scripts/dependencies, the blast radius of this change; the test tool's scan_folders is tests/scripts/dependencies alone, so its JUnit root counts that folder only (131 before this change, 137 after). Coverage figures are read from the CI Pester job, whose population is the three test folders and three script folders _pester.yml names, so the aggregate figures are comparable between P0-T16 (main) and P2-T3 (this branch). A formatter rewrite of a file outside the Write Set is pre-existing drift: it is reverted and listed, never committed by this change, and it does not restart the Phase 2 loop (convention 8). +- **D10 — Issue item 4 is a maintainer follow-up only.** AC18, AC19 and AC20 of issue 911 and the secret-store question are recorded at P2-T19 and never marked passed. +- **D11 — Tree-reading tests and coverage.** The four tests exercise production lines in ConsistencyVerifier.psm1 already covered; the change adds no executable production line, so the per-file no-regression gate is the covered-line count of that module. +- **D12 — The .csproj.bak copies.** QuickFiler.Test/QuickFiler.Test.csproj.bak and QuickFiler/QuickFiler.csproj.bak carry altcover tokens. They are not project files (MSBuild never reads a .bak), so AC1's search is scoped by pathspec to project files and manifests; their tracked status is recorded at P0-T1 and their removal is reported to the caller, not performed here. +- **D13 — Test evidence shape under the MCP-and-CI ruling.** A local test task records the MCP payload's ok value, `EXIT_CODE:` 0 when ok is true and the JUnit root failures attribute is 0 and 1 otherwise, and the CMD-JUNIT-READ lines (root counts, one line per testsuite with its leaf name, and every non-passed testcase with its failure message). A task that runs while the four tree tests are red by design (P1-T3 and P1-T7) carries `ExpectedExitCode: 1` and states the exact root failure count it expects, so a fix leaking early or a test failing to reproduce its defect both fail the task. The four tests are red at P1-T2 and P1-T3 (P1-T4 to P1-T9 not yet applied), tests 1 to 3 are green and test 4 red at P1-T7 (P1-T8 not yet applied), and all are green from P1-T11 on. Coverage figures are never read locally: P0-T16 and P2-T3 read them from the CI Pester job's log and pester-coverage artifact. + +## Revision Log + +- **Revision 3.2 (2026-09-30, planner, worktree agent-a74dcedbc13b789fd; preflight round 5 delta D-1 applied in place; task IDs and the count of 56 unchanged; issue.md and every acceptance criterion untouched).** + - **D-1 (major) — the P2-T1 formatter commit can be refused.** .gitattributes line 4 sets `* text=auto`, so a PoshQC rewrite that changes line terminators only is normalised out of the content git commits, and the P2-T1 branch's git commit exits 1 with "nothing to commit" while the task demanded a commit SHA. P2-T1 now runs git diff --numstat HEAD -- after a non-zero Write Set rewrite count and records it as `REWRITE-NUMSTAT:`; a non-empty output takes the existing commit branch (re-run P1-T11, commit, record the SHA, restart as iter2) and an empty output records `FORMAT-REWRITE-TERMINATOR-ONLY:` with the member list and restarts as iter2 with no commit; the post-revert porcelain clause is evaluated after the commit, or after the numstat capture when no commit is made. Sibling adjustment: Residual Risk 6 no longer states unconditionally that a P0-T13 rewrite is committed at P0-T21, because the same rule reaches that step; P0-T21's own clauses hold in the terminator-only case without edit (the member stages nothing, the evidence commit succeeds, git show lists no path outside the feature folder, and the plain message applies because no rewrite is committed). Convention 8 (restart on any Write Set rewrite, no commit named), P2-T3 (push only when HEAD differs from `PUSHED-HEAD:`) and P2-T21 ("any P2-T1 formatter commit") were checked and hold for both branches unchanged. +- **Revision 3.1 (2026-09-30, planner, worktree agent-a74dcedbc13b789fd at HEAD 3091b8af985df2410aaf83954825b3ef8a743452; preflight round 4 deltas applied in place, one entry per delta; task IDs and the count of 56 unchanged; issue.md and every acceptance criterion untouched).** + - **R1 (blocking) — Actions log colour escapes.** CMD-CI-PESTER now strips every SGR escape sequence from each captured log line before the three Select-String patterns run, because Pester colours each segment of its summary line in the Actions log (observed on job 109731601928 at preflight 2026-09-30) and the "Tests Passed: [0-9]+, Failed: [0-9]+" pattern matched nothing. Affects P0-T16 and P2-T3 through the shared block. + - **R2 (blocking) — the pr-author hook.** createdAt was removed from the run-list --json field list and created= from its RUN line; convention 1 now states that no gh-bearing command may contain the character sequence create and names the containment rule the hook applies to a pwsh-wrapped payload. Every other gh-bearing command (CMD-CI-PESTER, CMD-CI-LIST, CMD-CI-DISPATCH, CMD-CI-WATCH) was scanned for the sequence and carries none; the remaining occurrences of the word in this file are prose, an It name inside the test file P1-T1 authors and the tree-facts row quoting dependabot-repair.yml, none of them a command the executor issues. + - **R3 (major) — cancelled runs.** The single locate-and-dispatch block was replaced by CMD-CI-LIST, CMD-CI-DISPATCH and CMD-CI-WATCH with the rule stated under CMD-CI-DISPATCH: one dispatch per pushed head, re-list until a run for HEAD exists, watch the greatest databaseId, and re-list and re-select when the selected run reads conclusion=cancelled, because ci.yml lines 13 to 15 cancel an in-progress run on the same ref. A pull_request-event run for the same head satisfies RUNS-FOR-HEAD and suppresses the dispatch. P2-T3 was reworded to cite the three commands; no other reference to the removed block remains (the revision 3 entry below was reworded to describe it without naming it). + - **R4 (major) — download folder collision.** CMD-CI-PESTER prints DIR-PREEXISTS immediately before gh run download and requires False; `` is coverage/ci-main-pester-36666302259- at P0-T16 and coverage/ci-branch-pester-- at P2-T3, increasing by 1 on each further invocation against the same run; gh's "The file exists." error line is recorded under convention 4. + - **R5 (major) — pwsh-with-Set-Location form.** CMD-CSHARPIER-CHECK, CMD-MSBUILD-ANALYZERS, CMD-MSBUILD-NULLABLE and P0-T4 are now pwsh invocations beginning with Set-Location that print CSHARPIER_EXIT, MSBUILD_EXIT plus OUT_LINES (and CS0006_LINES for the analyzer build) and TOOL_RESTORE_EXIT; P0-T7 and P0-T8 payloads gained the Set-Location prefix; convention 1 gained the git -C and no-bare-dotnet-or-msbuild sentences; P0-T10, P0-T11, P2-T5 and P2-T6 state their acceptance in terms of OUT_LINES, CS0006_LINES and MSBUILD_EXIT. + - **R6 (minor) — failure-message text.** P1-T1 test (1) now formats a finding as ": line ", tests (3) and (4) carry -Because text with the literals client-id, app-id and secret name, and P1-T2 expects the four JUNIT-MESSAGE lines to contain QuickFiler.Test.csproj and altcover.8.6.45, 1.3.0.0 and 1.3.1.0, client-id, and secret name respectively. + - **R7 (minor) — path-printing lines.** CMD-MSTEST-COVERAGE, P0-T12 and convention 4 name the five lines "Using vstest.console: ", "Coverage output: ", "Coverage projection: ", "Test-result summary: " and "Done. Coverage artifact: " at Invoke-MSTestWithCoverage.ps1 lines 373, 375, 423, 447 and 456 (re-derived by the planner on 2026-09-30); P2-T7 inherits through its reference to P0-T12. + - **R8 (minor) — artifact totals.** P2-T11 states 44 evidence .md artifacts by that task (21 from Phase 0, 13 from Phase 1 with P1-T13 producing none, 10 from P2-T1 to P2-T10 in a single-iteration run); P2-T21's index floor was re-derived to 54 (the 44 plus P2-T11 to P2-T20); the P0-T20, P0-T21 and P1-T14 floors (20, 20, 12) were re-checked and hold. + - **R9 (minor) — P2-T21 commit list.** The index names the P2-T2 repair commit beside the P2-T1 formatter commit. + - **A1 (text correction).** The PoshQC test route also writes artifacts/pester/powershell-coverage.koverage.xml; convention 3, the tree-facts row and CMD-POSHQC-TEST name it. + - **A2 (residual risk, accepted).** Residual Risk 12 records that tree test 4 reads the 911 runbook at its active-folder path, which AC6 names, so the feature-promotion move of that folder must update the test path in the same change. +- **Revision 3 (2026-09-30, planner, worktree agent-a74dcedbc13b789fd at HEAD 3091b8af985df2410aaf83954825b3ef8a743452).** The branch merged origin/main at merge commit 3091b8af9 (second parent 231e1c0b55105aeb626bf5a6e8d0266a567cacad; 105 commits from main including the analyzer-path hotfix 89e202ed6; clean automatic merge). The plan was authored against HEAD 14177b8cf. Every citation was re-derived against the post-merge tree by reading the files; no task ID changed and the task count stays 56. + - **Re-anchored figures (old to new):** QuickFiler.Test/QuickFiler.Test.csproj second altcover import line 535 to 537, line count 568 to 570, post-edit expectation 566 to 568 (P1-T4, P2-T9, P2-T12, D-table, tree facts, CITATION); .github/workflows/README.md row line 115 to 116 (P1-T9, Write Set, tree facts, CITATION); .github/workflows/_pester.yml lines 41 and 45 unchanged in number but now naming three folders each (tests/scripts/hygiene and scripts/hygiene added), lines 47, 51, 64, 71 and 74 to 80 newly cited; .gitignore coverage rule 144 to 150, packages rule 191 to 197, .dotnet-sdk rule 350 to 356, artifacts rule 57 newly cited (conventions 3, P0-T6, tree facts, CITATION); scripts/vscode/Invoke-MSTestWithCoverage.ps1 results-directory lines 283 to 284 became 297 to 298, dotnet-coverage guard 326 to 328 became 344 to 346, "Using vstest.console: " 355 became 373, first-party report 388 became 410, projection 393 to 401 became 415 to 423, summary 417 to 425 became 430 to 447, entry guard 437 became 459 to 461, and line 313 (dot-source of the new Invoke-MSTestWithCoverage.Scope.ps1) is newly cited (P0-T7, tree facts, CITATION); .github/workflows/_build-analyzers.yml and _build-nullable.yml restore-keys lines 57 to 58 no longer exist (line 41 now states "No restore-keys fallback (issue #936)"), so the CI package cache row and both CITATION lines were replaced; the Pester baseline population became 373 tests (131 dependencies, 31 hygiene, 211 vscode) and the local PoshQC population 131 (P0-T15, P0-T16, P1-T2, P1-T3, P1-T7, P1-T11, P2-T3). + - **Hotfix-obsoleted work:** the P0-T6 back-fill branch (NUGET-PATH, nuget install, `ANALYZER-ITEM-STATE: skewed-backfilled`, `PRE-EXISTING-OUT-OF-SCOPE-DEFECT:`) is N/A: the census stays, expects UNRESOLVED=0 and `ANALYZER-ITEM-STATE: aligned`, and any UNRESOLVED above 0 stops the run. Evidence: 0 lines match Meziantou.Analyzer.3.0.235 across every *.csproj; 162 Analyzer Include items across 17 files each name a folder the sibling packages.config declares. D8, Residual Risks 1 and 8, the P2-T18 check-off, the P2-T21 index and the AC7 sentence in the header were revised accordingly; AC7's text in issue.md is unchanged. + - **P0-T8 marked N/A:** no raw Pester invocation remains, so no Pester module provisioning is needed; the task records a read-only Get-Module listing and the JUnit framework-version property P0-T15 reads. + - **P1-T13 removed (coordinator ruling 2026-09-30):** the Meziantou potential entry is not authored; the coordinator checks the skew and files it through the promotion path if it survives. The ID stays as a stub with no action and no artifact. The entry's path was removed from the Write Set, from the P0-T20 remedy sentence, from the P1-T14 and P2-T11 folder lists and the P1-T14 git add pathspec, the P2-T10 and P1-T14 count "nine" became "eight", and the `PROMOTION-HANDOFF:` item was removed from P2-T21. + - **PowerShell-gate rewrites (coordinator ruling, LOCAL POWERSHELL GATES block):** CMD-PESTER-ALL and CMD-PESTER-FILE were replaced by CMD-JUNIT-READ (per-file counts from artifacts/pester/pester-junit.xml), CMD-CI-PESTER (figures from a CI Pester job) and a single branch-run locate block (superseded in revision 3.1 by CMD-CI-LIST, CMD-CI-DISPATCH and CMD-CI-WATCH); CMD-POSHQC-ANALYZE lost its paired Invoke-ScriptAnalyzer run, tuple list and multiset comparison (P0-T14, P2-T2); P0-T16 reads the baseline from CI run 36666302259 (head 231e1c0b5, Pester job 109731601928); P2-T3 runs the MCP test locally and reads coverage from the CI run on the pushed head, completing only after CI reports; P1-T14 gained the push; P1-T2, P1-T3, P1-T7, P1-T11 and P2-T8 were re-sourced; every substitution is recorded in the gate artifact by the executor as `GATE-SUBSTITUTION:`. + - **CSharpier count handling:** P0-T9 and P2-T4 record the list of *.xml files under artifacts/ and coverage/ (excluding *.cobertura.xml, which .csharpierignore excludes) beside "Checked N", and the P2-T4 gate admits a "Checked N" delta equal to the candidate-count delta or to zero (Residual Risk 10). + - **New CI facts folded in:** the hygiene guard (_hygiene.yml) is run locally at P2-T21 before its commit; ci.yml's trigger set means P2-T3 dispatches the workflow on the branch ref when no run exists for the pushed head. + - **Unchanged (verified 2026-09-30):** SVGControl files, scripts/dependencies (ConsistencyVerifier.psm1 499 lines, comment at 221 to 223), tests/scripts/dependencies (ConsistencyVerifier.Tests.ps1 312 lines, 12 It blocks, comments at 57 to 59 and 275, It at 228; DependabotConfig.Tests.ps1 17 It blocks, Get-WorkflowStepBlock at 156, AC26 test at 323), dependabot-repair.yml lines 13 to 14, 49 and 51, the 911 runbook (Part B at 99, step 22 at 129 to 132, YAML sample at 152 to 154, citations at 301 and 318), the 911 spec AC18 to AC20 at 506, 512 and 520, .csharpierignore, global.json, Install-RepoDotNetSdk.ps1, Invoke-Restore.ps1, Invoke-VSBuild.ps1 lines 245 and 250 to 253, run-actionlint.ps1, _actionlint.yml line 26, issue.md (work mode at line 12, AC1 to AC7 at 44 to 50). + +## Write Set + +Every repository file the execution diff creates, modifies or deletes: + +- `QuickFiler.Test/QuickFiler.Test.csproj` (modify: delete lines 8 and 537) +- `SVGControl/app.config` (modify: lines 15 and 19) +- `.github/workflows/dependabot-repair.yml` (modify: lines 13 to 14 and 51) +- `.github/workflows/README.md` (modify: line 116) +- `docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md` (modify: the Part B heading at line 99, steps 10 and 22, the sentence at lines 103 to 106, the YAML sample line 154) +- `scripts/dependencies/ConsistencyVerifier.psm1` (modify: comment lines 221 to 223, line count held) +- `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1` (modify: comments at 57 to 59 and 275, two It blocks added) +- `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` (create) +- `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` (modify: check-offs only) +- `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/plan.2026-09-28T20-01.md` (modify: check-offs only) +- `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/` (create; every artifact named in a task line lies under this directory) + +Exclusions, by category: no C# source file, no other project file or manifest, no other app.config, no file under the .claude tree, no file under .github/instructions, no file under the config directory, no policy document, no file under docs/features/potential (the Meziantou potential entry of revisions 1 and 2 is not authored; the coordinator files it through the promotion path if the skew survives) and none under docs/features/potential/promoted. The two .csproj.bak copies are not edited. The eight non-feature-folder Write Set paths are the first eight entries above. + +## Command Reference + +Each block is stated once and cited by name. `` is the executor's worktree root; `` is the merge-base P0-T1 records; `` is the head P0-T1 records before any execution commit; `` is the head P0-T21 records; `` is a ci.yml run id and `` a download folder under the ignored coverage directory, both supplied by the calling task. + +**CMD-OUTLOOK** — precondition for the two solution-wide Rebuild commands only. Run Get-Process outlook -ErrorAction SilentlyContinue | Measure-Object | Select-Object -ExpandProperty Count; it must print 0 and the task's artifact records `OUTLOOK-CLOSED: true`. When it is non-zero the task stops and reports; the process is never terminated. + +**CMD-CSHARPIER-CHECK** — pwsh -NoProfile -Command 'Set-Location ""; dotnet tool run csharpier check .; "CSHARPIER_EXIT=$LASTEXITCODE"' The artifact's `EXIT_CODE:` is the CSHARPIER_EXIT value. Success prints one line beginning "Checked " and ending "ms." and CSHARPIER_EXIT=0. The check subcommand is read-only: it rewrites no file, so it has no formatter-rewrite branch anywhere in this plan. Every task that runs it also runs, immediately afterwards, pwsh -NoProfile -Command 'Set-Location ""; $root = (Get-Location).Path; $x = @(Get-ChildItem -Path "artifacts","coverage" -Recurse -File -Filter *.xml -ErrorAction SilentlyContinue | Where-Object { $_.Name -notlike "*.cobertura.xml" } | ForEach-Object { [System.IO.Path]::GetRelativePath($root, $_.FullName) } | Sort-Object); "XML-CANDIDATES=$($x.Count)"; $x' and records the count as `XML-CANDIDATES:` with the list. These are the *.xml files under the two ignored trees that .csharpierignore does not exclude (it excludes *.cobertura.xml but names neither artifacts/ nor coverage/); the PoshQC test tool, the coverage runner and the CI artifact downloads create such files between P0-T9 and P2-T4, and whether CSharpier counts gitignored files was not observed, so P2-T4 compares its "Checked N" against P0-T9's through this list rather than assuming either behaviour. + +**CMD-MSBUILD-ANALYZERS** — pwsh -NoProfile -Command 'Set-Location ""; msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true "/flp:LogFile=coverage\analyzers.msbuild.log;Verbosity=normal"; "MSBUILD_EXIT=$LASTEXITCODE"; $l = "coverage\analyzers.msbuild.log"; "OUT_LINES=" + @(Select-String -LiteralPath $l -SimpleMatch -Pattern ("/out:obj" + [char]92 + "Debug" + [char]92)).Count; "CS0006_LINES=" + @(Select-String -LiteralPath $l -SimpleMatch -Pattern "CS0006").Count' The artifact's `EXIT_CODE:` is the MSBUILD_EXIT value. The log lands under the coverage directory, which exists on every checkout (coverage/.gitkeep is tracked) and is ignored at .gitignore line 150. + +**CMD-MSBUILD-NULLABLE** — pwsh -NoProfile -Command 'Set-Location ""; msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true "/flp:LogFile=coverage\nullable.msbuild.log;Verbosity=normal"; "MSBUILD_EXIT=$LASTEXITCODE"; $l = "coverage\nullable.msbuild.log"; "OUT_LINES=" + @(Select-String -LiteralPath $l -SimpleMatch -Pattern ("/out:obj" + [char]92 + "Debug" + [char]92)).Count' The artifact's `EXIT_CODE:` is the MSBUILD_EXIT value; no CS0006 count is required for this build. Do not add a Nullable property and do not substitute the Build target (CLAUDE.md C#1.3). Non-vacuity for both msbuild commands is OUT_LINES, the count of log lines containing the substring /out:obj\Debug\ (built from [char]92 so no backslash crosses the Bash boundary), which must be at least 18 (one per compiled project). + +**CMD-MSTEST-COVERAGE** — pwsh -NoProfile -Command 'Set-Location ""; & "\scripts\vscode\Invoke-MSTestWithCoverage.ps1" -SearchRoot .' Success prints "Test Run Successful.", one line beginning "First-party coverage: lines " with both percentages, a line beginning "Coverage projection: " and a line beginning "Test-result summary: ". The projection is written beside the Cobertura output as coverage.cobertura.jacoco.xml and the summary as mstest-coverage-run.summary.txt under the test-results directory; both are copied into the evidence tree by the calling task, the raw documents never. The "Using vstest.console: ", "Coverage output: ", "Coverage projection: ", "Test-result summary: " and "Done. Coverage artifact: " lines (Invoke-MSTestWithCoverage.ps1 lines 373, 375, 423, 447 and 456) each print an absolute path and are recorded with the prefix replaced by its placeholder (convention 4). + +**CMD-JUNIT-READ** — pwsh -NoProfile -Command 'Set-Location ""; $p = "artifacts/pester/pester-junit.xml"; $f = Get-Item -LiteralPath $p; "JUNIT-WRITTEN=" + $f.LastWriteTimeUtc.ToString("o"); [xml]$j = Get-Content -LiteralPath $p -Raw; $r = $j.testsuites; "JUNIT-ROOT tests=$($r.tests) failures=$($r.failures) errors=$($r.errors) disabled=$($r.disabled)"; foreach ($s in @($r.testsuite)) { "JUNIT-SUITE " + (Split-Path -Leaf $s.name) + " tests=$($s.tests) failures=$($s.failures) skipped=$($s.skipped)" }; foreach ($c in @(@($r.testsuite) | ForEach-Object { $_.testcase } | Where-Object { $_.status -ne "Passed" })) { "JUNIT-NOTPASSED " + $c.name; if ($c.failure) { "JUNIT-MESSAGE " + [string]$c.failure.message } }' Run immediately after every CMD-POSHQC-TEST call. It reads the JUnit document the test tool wrote (ignored at .gitignore line 57) and prints the root counts, one JUNIT-SUITE line per test file with the leaf name only, and one JUNIT-NOTPASSED line per testcase whose status is not Passed with its failure message. The calling task records `RUN-START:` as the output of pwsh -NoProfile -Command '[DateTime]::UtcNow.ToString("o")' taken before the MCP call and requires JUNIT-WRITTEN to be later than it, so a stale document from an earlier run can never be read. Machine-name, user, cwd and classname values are never transcribed; a JUNIT-MESSAGE line carrying a path is transcribed with the worktree prefix replaced by `` (convention 4). The suite line whose leaf name is the file under test supplies that file's counts; the expected leaf names are AnalyzerItemRepair.Tests.ps1 (13), ConsistencyVerifier.Tests.ps1 (12, then 14 from P1-T3), DependabotConfig.Tests.ps1 (17), PackageCompatibility.Tests.ps1 (8), PackageGraph.Tests.ps1 (32), ProjectConsistency.Tests.ps1 (18), Repair-PackageManifestConsistency.Tests.ps1 (31) and, from P1-T1, RepositoryTreeConsistency.Tests.ps1 (4). + +**CMD-CI-PESTER `` ``** — pwsh -NoProfile -Command 'Set-Location ""; $run = gh run view --repo drmoisan/TaskMaster --json databaseId,headSha,headBranch,event,status,conclusion,workflowName | ConvertFrom-Json; "RUN id=$($run.databaseId) head=$($run.headSha) branch=$($run.headBranch) event=$($run.event) status=$($run.status) conclusion=$($run.conclusion) workflow=$($run.workflowName)"; $jobs = @((gh run view --repo drmoisan/TaskMaster --json jobs | ConvertFrom-Json).jobs); $pester = @($jobs | Where-Object { $_.name -like "pester*" }); "PESTER-JOBS=$($pester.Count)"; foreach ($job in $pester) { "JOB id=$($job.databaseId) name=$($job.name) status=$($job.status) conclusion=$($job.conclusion)" }; $esc = [string][char]27; $log = @(gh run view --repo drmoisan/TaskMaster --job $pester[0].databaseId --log) | ForEach-Object { $_ -replace ($esc + "[[][0-9;]*m"), "" }; "LOG-LINES=$($log.Count)"; $log | Select-String -Pattern "Tests Passed: [0-9]+, Failed: [0-9]+", "PESTER Passed=[0-9]+", "COVERAGE LinePercent=[0-9]+" | ForEach-Object { $_.Line }; "DIR-PREEXISTS=" + (Test-Path -LiteralPath ""); gh run download --repo drmoisan/TaskMaster --name pester-coverage --dir ""; "DOWNLOAD-EXIT=$LASTEXITCODE"; $files = @(Get-ChildItem -LiteralPath "" -File -Recurse); "ARTIFACT-FILES=$($files.Count)"; [xml]$d = Get-Content -LiteralPath $files[0].FullName -Raw; $line = @($d.SelectNodes("/report/counter")) | Where-Object { $_.type -eq "LINE" }; "REPORT-LINE covered=$($line.covered) missed=$($line.missed)"; $want = @("AnalyzerItemRepair.psm1","ConsistencyVerifier.psm1","PackageCompatibility.psm1","PackageGraph.psm1","ProjectConsistency.psm1","Repair-PackageManifestConsistency.ps1"); foreach ($sf in @($d.SelectNodes("//sourcefile") | Where-Object { $want -contains (Split-Path -Leaf $_.name) })) { $c = @($sf.SelectNodes("counter")) | Where-Object { $_.type -eq "LINE" }; "SOURCEFILE " + (Split-Path -Leaf $sf.name) + " covered=$($c.covered) missed=$($c.missed)" }' The gh CLI is reached only inside this pwsh invocation (the executor has Bash(pwsh *) and Bash(git *) only). Pester colours each segment of its summary line in the Actions log (observed on job 109731601928 at preflight 2026-09-30), so every captured line has its SGR escape sequences removed before matching; the class [[] matches a literal opening square bracket, so the expression carries no backslash. The three Select-String patterns carry a digit class so the workflow script's own echo in the log (the same literal followed by a dollar sign) does not match; "Tests Passed:" is Pester's summary line, "PESTER Passed=" is _pester.yml line 51 and "COVERAGE LinePercent=" is line 64. The run id is omitted from the --log call because gh ignores it when --job is given. `` is coverage/ci-main-pester-36666302259- at P0-T16 and coverage/ci-branch-pester-- at P2-T3, where is 1 for the first CMD-CI-PESTER invocation against that run and increases by 1 on each further invocation; DIR-PREEXISTS must print False, because a second gh run download into an existing --dir exits 1 with "The file exists.", and gh's error line carries an absolute path and is recorded under convention 4. The artifact holds one file, so ARTIFACT-FILES must be 1. The report LINE counter is read by XPath, as _pester.yml lines 53 to 61 do, because the document's DOCTYPE makes dotted access ambiguous; the percent is covered / (covered + missed) * 100 to two decimals and must equal the log's COVERAGE LinePercent figure, which proves the document is the log's source. Per-file LINE figures come from the sourcefile elements whose leaf name is one of the six scripts/dependencies file names, matched on the leaf so either package shape Pester may write is read; six SOURCEFILE lines are expected (AnalyzerItemRepair.psm1, ConsistencyVerifier.psm1, PackageCompatibility.psm1, PackageGraph.psm1, ProjectConsistency.psm1, Repair-PackageManifestConsistency.ps1). Pester emits no branch counter, so no PowerShell branch figure is claimed anywhere in this plan. The downloaded document is a raw JaCoCo document and stays under the coverage directory; only its figures are transcribed. + +**CMD-CI-LIST** — pwsh -NoProfile -Command 'Set-Location ""; $head = (git rev-parse HEAD).Trim(); "HEAD=$head"; $remote = (git ls-remote --heads origin bug/package-manifest-consistency-residuals-929).Trim(); "REMOTE=$remote"; $runs = @(gh run list --repo drmoisan/TaskMaster --workflow ci.yml --branch bug/package-manifest-consistency-residuals-929 --limit 50 --json databaseId,headSha,status,conclusion,event | ConvertFrom-Json | Where-Object { $_.headSha -eq $head } | Sort-Object -Property databaseId -Descending); "RUNS-FOR-HEAD=$($runs.Count)"; foreach ($r in $runs) { "RUN id=$($r.databaseId) head=$($r.headSha) event=$($r.event) status=$($r.status) conclusion=$($r.conclusion)" }' Lists the ci.yml runs for the current HEAD on this branch, greatest databaseId first. REMOTE must name HEAD, which proves the head was pushed before any dispatch. The --json list carries no timestamp field and the RUN line no timestamp value, under the convention 1 rule on the character sequence the pr-author hook refuses; ordering by databaseId supplies the recency the timestamp would have. + +**CMD-CI-DISPATCH** — pwsh -NoProfile -Command 'Set-Location ""; gh workflow run ci.yml --repo drmoisan/TaskMaster --ref bug/package-manifest-consistency-residuals-929; "DISPATCH-EXIT=$LASTEXITCODE"' ci.yml triggers on push only for main and development and otherwise on pull_request and workflow_dispatch (lines 3 to 8), so a push of this branch starts no run by itself. Rule: P2-T3 runs CMD-CI-LIST once. When RUNS-FOR-HEAD is 0 it runs CMD-CI-DISPATCH exactly once per pushed head; DISPATCH-EXIT must be 0, and a non-zero value stops the task with a report (Residual Risk 11). It then re-runs CMD-CI-LIST, never CMD-CI-DISPATCH, until RUNS-FOR-HEAD is at least 1, recording each re-run. The selected run is the first listed (greatest databaseId). CMD-CI-WATCH is re-invoked unchanged when the tool call times out, until it returns on its own; CMD-CI-PESTER then runs once. When CMD-CI-PESTER's RUN line reads conclusion=cancelled, the task re-runs CMD-CI-LIST, selects the greatest databaseId and watches that run, because a cancelled selection is a run superseded under ci.yml lines 13 to 15 (concurrency group keyed on the ref with cancel-in-progress true), not a test outcome. When a pull request for this branch already exists, its pull_request-event run for the same head SHA satisfies RUNS-FOR-HEAD and no dispatch is made. + +**CMD-CI-WATCH** — pwsh -NoProfile -Command 'Set-Location ""; gh run watch --repo drmoisan/TaskMaster --interval 60; "WATCH-EXIT=$LASTEXITCODE"' gh's own blocking poll (convention 6); each invocation is recorded. + +**CMD-POSHQC-FORMAT** — MCP tool mcp__drm-copilot__run_poshqc_format with workspace_root set to `` and scan_folders supplied explicitly as ["scripts/dependencies","tests/scripts/dependencies"]. The scan set must be explicit because no config/poshqc-scan.json exists. The tool exits 0 whether or not it rewrote anything, so its observation is a SHA-256 hash set taken before and after over every .ps1, .psm1 and .psd1 file under the two folders, plus git status --porcelain --untracked-files=all over the two folders. + +**CMD-POSHQC-ANALYZE** — MCP tool mcp__drm-copilot__run_poshqc_analyze with the same workspace_root and scan_folders. Its payload carries ok, tool, workspace_root and summary and no count, file list or diagnostic. Under convention 11 an ok value of true is the lint result and is recorded verbatim together with the exact line "PoshQC analyze: pass (0 findings); tool reports no count"; an ok value of false (or a payload without ok) is recorded verbatim and the task stops with a report (Phase 0) or fails the loop step (Phase 2). No Invoke-ScriptAnalyzer run, tuple list or count comparison exists anywhere in this plan; the executor records `GATE-SUBSTITUTION: PoshQC analyze ok flag stands in for a diagnostic count` in each analyze artifact. + +**CMD-POSHQC-TEST** — MCP tool mcp__drm-copilot__run_poshqc_test with workspace_root set to `` and scan_folders ["tests/scripts/dependencies"]. Its payload carries ok, tool, workspace_root and summary only; it also writes artifacts/pester/pester-junit.xml, artifacts/pester/powershell-coverage.xml and artifacts/pester/powershell-coverage.koverage.xml under the worktree (all three ignored at .gitignore line 57; the coverage document's counters read 0 covered and neither coverage document is ever a coverage source). Every test task records `RUN-START:` before the call, the payload verbatim after it, then runs CMD-JUNIT-READ and derives every count from its lines; `EXIT_CODE:` is 0 when ok is true and JUNIT-ROOT failures is 0, and 1 otherwise, with the ok value recorded beside it, so a task that expects red tests carries `ExpectedExitCode: 1`. Coverage is never read from this route: P0-T16 and P2-T3 read it from CI through CMD-CI-PESTER. The three XML files it writes are counted by CMD-CSHARPIER-CHECK's XML-CANDIDATES list. + +**CMD-ACTIONLINT** — pwsh -NoProfile -Command 'Set-Location ""; & ".\actionlint-bin\actionlint.exe" -version; & ".\actionlint-bin\actionlint.exe" ".github/workflows/dependabot-repair.yml"; "SCOPED_EXIT=$LASTEXITCODE"; & ".\scripts\dev-tools\run-actionlint.ps1"; "REPO_EXIT=$LASTEXITCODE"' Success prints the version line, then nothing from either lint invocation, then SCOPED_EXIT=0 and REPO_EXIT=0. The run-actionlint.ps1 script throws when the binary is absent, so an empty capture with both exits 0 and a version line present is the success-case observation. + +**CMD-VERIFIER-WHATIF** — pwsh -NoProfile -Command 'Set-Location ""; $files = @(Get-ChildItem -Path "*/packages.config","*/app.config","*/*.csproj" -File); $before = @($files | Get-FileHash -Algorithm SHA256 | ForEach-Object { $_.Hash }) -join ","; $r = & ".\scripts\dependencies\Repair-PackageManifestConsistency.ps1" -WhatIf; $after = @($files | Get-FileHash -Algorithm SHA256 | ForEach-Object { $_.Hash }) -join ","; "ABSENT=$($r.AbsentFromManifestCount) DISAGREE=$($r.VersionDisagreementCount) WRITTEN=$(@($r.WrittenPath).Count) SUCCESS=$($r.IsSuccess) PROJECTS=$($r.ExaminedProjectCount) FILES=$($files.Count) HASHES_EQUAL=$($before -eq $after)"' A read-only run: every write is behind ShouldProcess and the normalisation receives -WhatIf explicitly (script lines 443 to 446). HASHES_EQUAL=True is the non-write assertion and FILES must be at least 50 (18 project files, 18 manifests, 17 app.config files). The -WhatIf messages name absolute target paths and are recorded with the prefix replaced by its placeholder (convention 4). DISAGREE is computed over the in-memory repaired project text (script lines 411 to 422), so it carries no expectation anywhere in this plan. + +**CMD-REDIRECT-OBSERVE** — pwsh -NoProfile -Command 'Set-Location ""; Import-Module ".\scripts\dependencies\ProjectConsistency.psm1"; $t = [System.IO.File]::ReadAllText((Join-Path (Get-Location).Path "SVGControl/app.config")); $f = Invoke-BindingRedirectReconciliation -AppConfigText $t -AssemblyName "Fizzler" -AssemblyVersion "1.3.1.0"; $u = Invoke-BindingRedirectReconciliation -AppConfigText $t -AssemblyName "System.Runtime.CompilerServices.Unsafe" -AssemblyVersion "6.0.3.0"; "FIZZLER_REPAIRS=$(@($f.Repair).Count) UNSAFE_REPAIRS=$(@($u.Repair).Count) EXAMINED=$($f.ExaminedCount)"' The function is pure over text and writes nothing; the path is made absolute because a .NET file API resolves a relative path against the process directory, which Set-Location does not change; EXAMINED must be 4 (the file's four dependentAssembly blocks). + +**CMD-HYGIENE ``** — pwsh -NoProfile -Command 'Set-Location ""; $acct = Split-Path -Leaf $env:USERPROFILE; $machine = [System.Environment]::MachineName; $root = (Get-Location).Path; $bs = [regex]::Escape([string][char]92); $pattern = @(("(^|[^A-Za-z0-9_-])[A-Za-z]:" + $bs), ("(^|[^A-Za-z0-9])" + [regex]::Escape($acct) + "([^A-Za-z0-9]|$)"), ("(^|[^A-Za-z0-9])" + [regex]::Escape($machine) + "([^A-Za-z0-9]|$)")); $ext = @(".md",".txt",".xml",".yml",".ps1",".psm1"); $files = @(Get-ChildItem -Recurse -File -Path | Where-Object { $ext -contains $_.Extension }); $hits = @($files | Select-String -Pattern $pattern | Where-Object { $_.Line -notmatch "https?://" }); "PATTERNS=" + $pattern.Count; "SELFTEST=" + @(("Q:" + [string][char]92 + "x") | Select-String -Pattern $pattern).Count; "SELFTEST_NEG=" + @(("client-id:" + [string][char]92 + "s") | Select-String -Pattern $pattern).Count; "SCANNED=$($files.Count) HITS=$($hits.Count)"; $hits | ForEach-Object { [System.IO.Path]::GetRelativePath($root, $_.Path) + ":" + $_.LineNumber }' The drive-letter pattern requires a backslash after the colon so URLs do not match it, and a hit on a line carrying an https URL is excluded because the account-name pattern would otherwise flag a repository owner segment. PATTERNS must be 3, SELFTEST must be 1, SELFTEST_NEG must be 0, HITS must be 0 and SCANNED at least 1; every task that cites CMD-HYGIENE inherits all five conditions. Each concatenated element of the pattern array is parenthesised because the PowerShell comma operator binds more tightly than +, so an unparenthesised element splits into its fragments and the boundary fragments match every line; PATTERNS=3 and SELFTEST_NEG=0 fail when that happens. The drive-letter element also requires the letter to follow the start of the line or a character other than a letter, digit, underscore or hyphen, so a YAML-key regex such as the client-id pattern in P1-T1 (a key, a colon, then a backslash escape) does not match it; SELFTEST_NEG exercises that case. Hit locations are printed relative to the worktree root so the listing itself carries no host path. The drive-letter pattern is built from [char]92 because a doubled backslash is de-doubled between Bash and pwsh, which leaves a pattern that cannot match a backslash path. The account and machine values are derived at run time and are never written into any artifact. + +**CMD-FOOTPRINT** — git diff --name-only -- . together with git status --porcelain --untracked-files=all, both captured verbatim. It is anchored at because the branch already carries the promotion commit, whose promoted record under docs/features/potential/promoted lies outside the Write Set and the feature folder. + +### Phase 0 — Baseline Capture + +- [x] [P0-T1] Anchor the run: from `` run git rev-parse --show-toplevel, git rev-parse --abbrev-ref HEAD, git fetch origin main, git rev-parse origin/main, git merge-base origin/main HEAD (recorded as ``), git rev-parse HEAD (recorded as ``), git rev-list --count ..HEAD (recorded as measured, no literal asserted), git merge-base --is-ancestor 231e1c0b55105aeb626bf5a6e8d0266a567cacad HEAD followed by its exit code (recorded as `MERGED-MAIN-ANCESTOR:`; 0 proves the worktree carries the 2026-09-30 merge of origin/main, and 1 or 128 stops the task with a report because every re-anchored figure in this plan describes the post-merge tree), git status --porcelain --untracked-files=all (recorded verbatim as `BASE-UNTRACKED:`), git ls-files -- "*.csproj.bak" (recorded verbatim as `BAK-TRACKED:`), and git diff --name-only HEAD -- QuickFiler.Test/QuickFiler.Test.csproj SVGControl/app.config .github/workflows/dependabot-repair.yml .github/workflows/README.md docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md scripts/dependencies/ConsistencyVerifier.psm1 tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1; write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t1-worktree-anchor.2026-09-28T20-01.md`. Acceptance: the recorded branch is exactly bug/package-manifest-consistency-residuals-929; `` and `` are each 40 hexadecimal characters and git cat-file -t on each prints commit; the seven-path diff against HEAD is empty (none of the files this plan edits is already modified); `BASE-UNTRACKED:` contains no entry matching *.cs, *.csproj, packages.config or app.config; `BAK-TRACKED:` is recorded whether empty or not; the show-toplevel output is recorded as ``, never as its value. Fails when the branch name differs or any Write Set source file is already dirty. + +- [x] [P0-T2] Read the policy documents in the order fixed by the policy-compliance-order skill — CLAUDE.md, .claude/rules/general-code-change.md, .claude/rules/general-unit-test.md, .claude/rules/powershell.md, .claude/rules/csharp.md, .claude/rules/quality-tiers.md, .claude/rules/tonality.md, .claude/rules/ci-workflows.md, .claude/rules/plan-acceptance-gates.md, then the skills .claude/skills/atomic-plan-contract/SKILL.md, .claude/skills/evidence-and-timestamp-conventions/SKILL.md and .claude/skills/acceptance-criteria-tracking/SKILL.md — and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/phase0-instructions-read.2026-09-28T20-01.md` carrying `Timestamp:`, `Policy Order:` and the explicit list of the twelve files read, each with its line count. Acceptance: twelve files are listed in that order, each with a non-zero integer line count, and the artifact records that issue.md carries `- Work Mode: minor-audit` at line 12 and a `## Acceptance Criteria` heading with exactly 7 checkbox lines matching `^- \[ \] AC\d+:` beneath it, that no spec.md, user-story.md or research.md exists in the feature folder, and the coverage-floor conflict of convention 10 with its issue number 668. + +- [x] [P0-T3] Provision the repository-pinned .NET SDK with the guarded form pwsh -NoProfile -Command 'Set-Location ""; if (-not (Test-Path ".dotnet-sdk\sdk")) { & ".\scripts\vscode\Install-RepoDotNetSdk.ps1" }; dotnet --version; dotnet --list-sdks' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t3-sdk-bootstrap.2026-09-28T20-01.md`. Acceptance: dotnet --version prints 8.0.205, and dotnet --list-sdks prints a line of the form 8.0.205 [] in which the bracketed path names the sdk folder under the repository-root .dotnet-sdk folder (the path segments .dotnet-sdk\sdk are the last two before the closing square bracket; the install location is Install-RepoDotNetSdk.ps1 line 36 and global.json line 7); that line is recorded with the worktree prefix inside the brackets replaced by ``, so the recorded form reads 8.0.205 [\.dotnet-sdk\sdk]; every other SDK line the command prints (a machine-wide install) is recorded with its bracketed prefix replaced by `` or `` under convention 4, so the artifact carries no host path. Fails when dotnet prints the global.json errorMessage instead of a version, the state of a fresh worktree. + +- [x] [P0-T4] Run pwsh -NoProfile -Command 'Set-Location ""; dotnet tool restore; "TOOL_RESTORE_EXIT=$LASTEXITCODE"' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t4-tool-restore.2026-09-28T20-01.md`. Acceptance: `EXIT_CODE: 0`, the TOOL_RESTORE_EXIT value, and the `Output Summary:` names csharpier at version 1.2.6, the version the repository-root dotnet-tools.json pins. + +- [x] [P0-T5] Restore NuGet packages with pwsh -NoProfile -Command 'Set-Location ""; $before = @(Get-ChildItem -Path ".\packages" -Directory -ErrorAction SilentlyContinue).Count; "PACKAGE_DIRS_BEFORE=$before"; & ".\scripts\vscode\Invoke-Restore.ps1"; "RESTORE_EXIT=$LASTEXITCODE"; $after = @(Get-ChildItem -Path ".\packages" -Directory).Count; "PACKAGE_DIRS_AFTER=$after"' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t5-package-restore.2026-09-28T20-01.md`. Acceptance: the restore output contains "Build succeeded." and "0 Error(s)"; PACKAGE_DIRS_AFTER is an integer greater than 100 and not lower than PACKAGE_DIRS_BEFORE; PACKAGE_DIRS_BEFORE is recorded as measured (0 in a fresh worktree, which is the cold state AC7 names); the script's "Using MSBuild: " line is recorded with its absolute path replaced by `` (convention 4). The artifact also records `ALTCOVER-RESTORED:` as the boolean Test-Path of packages\altcover.8.6.45 after the restore; a restore cannot produce that folder because no manifest declares the package, so True means a lingering folder and is recorded, not asserted. + +- [x] [P0-T6] Census every Analyzer Include item for resolvability (the back-fill branch of revisions 1 and 2 is N/A after the origin/main merge; the census stays because it is the evidence): run pwsh -NoProfile -Command 'Set-Location ""; $items = @(); foreach ($p in @(git ls-files -- "*.csproj")) { $dir = Split-Path -Parent $p; foreach ($line in (Get-Content -LiteralPath $p)) { if ($line -match "Analyzer Include=""([^""]+)""") { $rel = $Matches[1]; $items += [pscustomobject]@{ Project = $p; Item = $rel; Resolves = (Test-Path -LiteralPath (Join-Path $dir $rel)) } } } }; "ANALYZER_ITEMS=$($items.Count) FILES=$(@($items | Select-Object -ExpandProperty Project -Unique).Count) UNRESOLVED=$(@($items | Where-Object { -not $_.Resolves }).Count)"; "SKEW_235=" + @(git grep -n "Meziantou.Analyzer.3.0.235" -- "*.csproj").Count; $items | Where-Object { -not $_.Resolves } | ForEach-Object { $_.Project + " " + $_.Item }' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t6-analyzer-item-census.2026-09-28T20-01.md`. Acceptance: ANALYZER_ITEMS is exactly 162 and FILES exactly 17 (re-derived by the planner on 2026-09-30 on the post-merge tree); UNRESOLVED is exactly 0 and SKEW_235 is exactly 0; the artifact carries exactly one line `ANALYZER-ITEM-STATE: aligned` and the sentence "No back-fill was performed and none is permitted by this plan; the AC7 back-fill clause is not exercised."; it states that the packages tree is ignored at .gitignore line 197 and that the restore of P0-T5 is the only step that populated it. An UNRESOLVED or SKEW_235 value above 0 stops the run with a report listing every unresolved (project, item) pair: it would describe a tree the coordinator did not measure on 2026-09-30, no nuget back-fill exists in this plan, and every Rebuild below would fail CS0006 for a cause outside this issue. Decision D8 governs. + +- [x] [P0-T7] Provision the dotnet-coverage global tool with pwsh -NoProfile -Command 'Set-Location ""; if (-not (Get-Command dotnet-coverage -ErrorAction SilentlyContinue)) { dotnet tool install --global dotnet-coverage }; (Get-Command dotnet-coverage).Source' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t7-dotnet-coverage.2026-09-28T20-01.md`. Acceptance: Get-Command resolves to a path (recorded with the user-profile prefix replaced by the placeholder); fails when it does not, because the coverage runner throws before running anything when the tool is absent (Invoke-MSTestWithCoverage.ps1 lines 344 to 346). + +- [x] [P0-T8] N/A (revision 3, 2026-09-30): Pester module provisioning is not needed because no raw Pester invocation remains in this plan; every test run goes through mcp__drm-copilot__run_poshqc_test, which loads its own Pester (the JUnit document's framework-version property, read at P0-T15, records the version it used). The executor records the read-only observation pwsh -NoProfile -Command 'Set-Location ""; Get-Module Pester -ListAvailable | Select-Object Name,Version | Format-Table -AutoSize | Out-String' (no Install-Module is run) and writes `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t8-pester-provision.2026-09-28T20-01.md` carrying `Timestamp:`, `Command:`, `EXIT_CODE:` (the listing command's exit code, expected 0), `Output Summary:` (the listing as printed, plus the line `N/A: no raw Pester invocation in this plan; the MCP test route supplies its own Pester`) and `GATE-SUBSTITUTION: Pester provisioning replaced by the PoshQC MCP test route`. Acceptance: the artifact exists with those fields; the listing content carries no expectation and is recorded as measured. The checkbox is ticked only once the artifact exists. + +- [x] [P0-T9] Capture the C# formatter baseline by running CMD-CSHARPIER-CHECK and writing `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t9-csharpier-check.2026-09-28T20-01.md`. Acceptance: `EXIT_CODE:` recorded as the CSHARPIER_EXIT value the command prints; the verbatim "Checked N files in Xms." line recorded with N as an integer greater than 900; `XML-CANDIDATES:` recorded as the count and the sorted list the CMD-CSHARPIER-CHECK companion command prints (the empty case as `XML-CANDIDATES: 0`); the full list of any files reported with findings recorded as `CSHARPIER-FINDINGS:` (expected empty, recorded as `CSHARPIER-FINDINGS: none`; a non-empty list is recorded with each path repository-relative and reported, not fixed, because no C# file is in the Write Set, and P2-T4 compares against it). Fails when no "Checked " line is present. + +- [x] [P0-T10] Capture the analyzer-build baseline: satisfy CMD-OUTLOOK, run CMD-MSBUILD-ANALYZERS, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t10-msbuild-analyzers.2026-09-28T20-01.md` carrying `OUTLOOK-CLOSED: true` and the MSBUILD_EXIT, OUT_LINES and CS0006_LINES lines the command prints. Acceptance: `EXIT_CODE: 0` (the recorded MSBUILD_EXIT value), CS0006_LINES exactly 0, OUT_LINES at least 18 with the exact integer recorded, and the msbuild summary line "0 Error(s)" quoted. A non-zero exit stops the run with the first error line quoted verbatim: with P0-T6 green the only remaining causes are outside this issue and no later task can pass. + +- [x] [P0-T11] Capture the nullable-build baseline: satisfy CMD-OUTLOOK, run CMD-MSBUILD-NULLABLE, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t11-msbuild-nullable.2026-09-28T20-01.md` carrying `OUTLOOK-CLOSED: true` and the MSBUILD_EXIT and OUT_LINES lines the command prints. Acceptance: `EXIT_CODE: 0` (the recorded MSBUILD_EXIT value), OUT_LINES at least 18 with the exact integer recorded, and "0 Error(s)" quoted. A non-zero exit stops the run with the first error line quoted verbatim. + +- [x] [P0-T12] Capture the C# test and coverage baseline by running CMD-MSTEST-COVERAGE and writing `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-mstest-coverage.2026-09-28T20-01.md`; copy the file the run printed after "Coverage projection: " to `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-coverage-projection.2026-09-28T20-01.jacoco.xml` and the file printed after "Test-result summary: " to `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t12-test-results.2026-09-28T20-01.summary.txt`. Acceptance: `EXIT_CODE: 0`; the "First-party coverage: lines A/B (L%), branches C/D (R%)" line quoted verbatim with L and R recorded as the numeric baseline percentages; the summary's total, passed and failed counts recorded with failed 0 and passed greater than 0; both copies made and their byte sizes recorded; the sum of the projection's package LINE covered counters equals A (the reconciliation that proves the copy describes this run); `MEETS-85:` recorded as true when L is at least 85 and false otherwise, an observation only under convention 10; the "Using vstest.console: ", "Coverage output: ", "Coverage projection: ", "Test-result summary: " and "Done. Coverage artifact: " lines (Invoke-MSTestWithCoverage.ps1 lines 373, 375, 423, 447 and 456) recorded with their absolute paths replaced by placeholders (convention 4); and the artifact states that the raw Cobertura and trx documents stay under the ignored coverage directory and are not copied; the projection copy's root element is report and it carries no class, sourcefile, method or line element (Select-String over the copy for the patterns " every path whose hash changed and that is not a Write Set member, record `VERIFIER-LINES:` as @(Get-Content -LiteralPath "scripts/dependencies/ConsistencyVerifier.psm1").Count after the run, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t13-poshqc-format.2026-09-28T20-01.md`. Acceptance: both hash sets recorded with exactly 13 entries each (6 production files, 7 test files); the rewrite count derived from the hash difference recorded as an integer; the exact scan_folders value recorded; `REVERT-SET:` recorded explicitly, including the empty case as `REVERT-SET: empty`; `FORMAT-REWROTE-WRITE-SET:` recorded as the list of Write Set members the run rewrote, or as none; the post-revert porcelain over the two folders lists nothing but Write Set members; `VERIFIER-LINES:` recorded as an integer at most 500 (expected 499); and the MCP payload's ok value recorded but not asserted. The empty pre-revert case is the expected truthful result and is not a failure; a post-revert porcelain that still lists a reverted path is. + +- [x] [P0-T14] Capture the PowerShell analyzer baseline: run CMD-POSHQC-ANALYZE, then pwsh -NoProfile -Command 'Set-Location ""; "FILES=" + @(Get-ChildItem -Recurse -File -Path "scripts/dependencies","tests/scripts/dependencies" -Include *.ps1,*.psm1).Count' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t14-poshqc-analyze.2026-09-28T20-01.md`. Acceptance: the MCP payload (ok, tool, workspace_root, summary, any stderr excerpt) recorded verbatim with the exact scan_folders value; ok is true and the artifact carries the exact line "PoshQC analyze: pass (0 findings); tool reports no count" and `EXIT_CODE: 0`; FILES recorded as exactly 13 (6 production, 7 test files); `GATE-SUBSTITUTION: PoshQC analyze ok flag stands in for a diagnostic count` recorded. An ok value of false is recorded verbatim with the summary and stderr excerpt and stops the run with a report: the pre-change folders are expected clean (the 911 close-out measured every finding in scripts/vscode, outside this scan set) and a red baseline here is a cause outside this issue. No Invoke-ScriptAnalyzer run, tuple list or route comparison is made. + +- [x] [P0-T15] Record the MCP test-route baseline and the local per-file test counts: record `RUN-START:`, run CMD-POSHQC-TEST, run CMD-JUNIT-READ, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t15-poshqc-test-mcp.2026-09-28T20-01.md`. Acceptance: the payload's ok value and summary recorded verbatim; JUNIT-WRITTEN later than RUN-START (the document was written by this run); JUNIT-ROOT reads tests=131 failures=0 errors=0 (the 131 It blocks under tests/scripts/dependencies re-derived by the planner on 2026-09-30) and `EXIT_CODE: 0` under the CMD-POSHQC-TEST rule; exactly 7 JUNIT-SUITE lines, among them ConsistencyVerifier.Tests.ps1 tests=12 failures=0 and DependabotConfig.Tests.ps1 tests=17 failures=0, and no JUNIT-NOTPASSED line; the JUnit document's framework-version property value recorded as `PESTER-VERSION:` (read with pwsh -NoProfile -Command 'Set-Location ""; [xml]$j = Get-Content -LiteralPath "artifacts/pester/pester-junit.xml" -Raw; @($j.testsuites.testsuite)[0].properties.property | Where-Object { $_.name -eq "framework-version" } | ForEach-Object { $_.value }'; expected 5.6.1, recorded as measured); the artifact states that this route reports no coverage figure and that P0-T16 reads coverage from CI, and carries `GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run`. A different tests total or a non-zero failures value is recorded and stops the run with a report. + +- [x] [P0-T16] Capture the Pester coverage baseline from the CI run on main that the branch merged: run CMD-CI-PESTER with `` 36666302259 and `` coverage/ci-main-pester-36666302259- ( is 1 for the first invocation and increases by 1 on each further invocation), and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t16-pester.2026-09-28T20-01.md` carrying `Timestamp:`, `Command:`, `EXIT_CODE:` (the pwsh invocation's exit code, expected 0) and `Output Summary:`. Acceptance: the RUN line records head=231e1c0b55105aeb626bf5a6e8d0266a567cacad, branch=main, status=completed, conclusion=success and workflow=CI, and the artifact records `git merge-base --is-ancestor 231e1c0b55105aeb626bf5a6e8d0266a567cacad HEAD` exiting 0 (the run's head is an ancestor of the executor's HEAD, so the baseline describes code this branch carries); PESTER-JOBS=1 with JOB id=109731601928 and conclusion=success; the "Tests Passed: N, Failed: N, Skipped: N, ..." line, the "PESTER Passed=... Failed=... Skipped=... Total=..." line and the "COVERAGE LinePercent=... Covered=... Total=..." line each quoted verbatim from the log, with Failed 0, Skipped 0 and Total greater than 300; `BASELINE-TOTAL:` recorded as Passed plus Failed plus Skipped from the PESTER line and equal to its Total field; the report LINE percent computed to two decimals from REPORT-LINE, equal to the log's LinePercent figure and at least 80; DIR-PREEXISTS=False, DOWNLOAD-EXIT=0 and ARTIFACT-FILES=1, with the `` value used recorded; `MEETS-85:` recorded as true when the percent is at least 85 and false otherwise, an observation only under convention 10; the six SOURCEFILE lines recorded as covered and missed integers, the ConsistencyVerifier.psm1 pair recorded as `VERIFIER-COVERED:` and `VERIFIER-MISSED:`; the run id and head SHA recorded beside every figure; the artifact states that Pester emits no branch counter, that the figures stand in for a permitted evidence form the committed-evidence section does not define for the Pester route, that the downloaded JaCoCo document stays under the ignored coverage directory, and `GATE-SUBSTITUTION: CI Pester job 109731601928 stands in for a local coverage run`. The coordinator measured Tests Passed 373, LinePercent 94.51, Covered 1721 and Total 1821 on 2026-09-30; a differing figure printed by the run is recorded as `TRANSCRIPTION-MISMATCH:` with both values and the run's own figure governs every later comparison. A run whose head, status or conclusion differs from the values above stops the task with a report. + +- [x] [P0-T17] Record the pre-fix altcover state and the read-only verifier baseline: run pwsh -NoProfile -Command 'Set-Location ""; $m = @(git grep -i -n altcover -- "*.csproj" "*/packages.config"); "ALTCOVER_LINES=$($m.Count)"; $m' then CMD-VERIFIER-WHATIF, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t17-altcover-and-verifier-prefix.2026-09-28T20-01.md`. Acceptance: ALTCOVER_LINES is exactly 2 and both lines name QuickFiler.Test/QuickFiler.Test.csproj at lines 8 and 537; the what-if run prints ABSENT=2, WRITTEN=0, HASHES_EQUAL=True, PROJECTS=18 and FILES at least 50; DISAGREE and SUCCESS are recorded as measured, with no expectation stated for either: DISAGREE may be 0, because Get-ProjectVerification runs over the in-memory repaired project text (Repair-PackageManifestConsistency.ps1 lines 411 to 422) rather than over the tree; the "Manifest discovery" information line is quoted; every -WhatIf target path is recorded with its prefix replaced by ``. + +- [x] [P0-T18] Record the pre-fix redirect state: quote SVGControl/app.config lines 15 and 19 and SVGControl/SVGControl.csproj lines 58 and 82 verbatim; run pwsh -NoProfile -Command 'Set-Location ""; "FIZZLER_ASM=" + [System.Reflection.AssemblyName]::GetAssemblyName((Resolve-Path "packages/Fizzler.1.3.1/lib/netstandard2.0/Fizzler.dll").Path).Version; "UNSAFE_ASM=" + [System.Reflection.AssemblyName]::GetAssemblyName((Resolve-Path "packages/System.Runtime.CompilerServices.Unsafe.6.1.2/lib/net462/System.Runtime.CompilerServices.Unsafe.dll").Path).Version'; run CMD-REDIRECT-OBSERVE; run pwsh -NoProfile -Command 'Set-Location ""; foreach ($f in @(Get-ChildItem -Path "*/app.config" -File)) { $t = [System.IO.File]::ReadAllText($f.FullName); $m = [regex]::Match($t, "(?s)name=""Fizzler"".*?newVersion=""([^""]+)"""); if ($m.Success) { $f.Directory.Name + " Fizzler " + $m.Groups[1].Value } }'; write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t18-redirect-prefix.2026-09-28T20-01.md`. Acceptance: FIZZLER_ASM is 1.3.1.0 and UNSAFE_ASM is 6.0.3.0 (these confirm the issue's version claims against the restored assemblies and are what AC2 and AC3 name); FIZZLER_REPAIRS=1, UNSAFE_REPAIRS=1, EXAMINED=4 (the pre-fix drift as the reconciliation function sees it); the tree-wide Fizzler list records exactly 13 configs, 12 at 1.3.0.0 and UtilitiesCS at 1.3.1.0, with the 11 configs other than SVGControl and UtilitiesCS labelled `OUT-OF-SCOPE-RESIDUAL:` (SVGControl is the in-scope AC2 target; UtilitiesCS already names 1.3.1.0) with a citation of docs/features/potential/2026-08-04-stale-fizzler-and-unsafe-binding-redirects.md; a different tree-wide count is recorded and reported, not absorbed. + +- [x] [P0-T19] Record the pre-fix workflow, runbook and README state and the actionlint baseline: run pwsh -NoProfile -Command 'Set-Location ""; $w = Get-Content ".github/workflows/dependabot-repair.yml"; "WF_APPID=" + @($w | Select-String -Pattern "^\s+app-id:").Count; "WF_CLIENTID=" + @($w | Select-String -Pattern "^\s+client-id:").Count; $rb = Get-Content "docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md"; "RB_APPID=" + @($rb | Select-String -Pattern "^\s+app-id:").Count; "RB_CLIENTID=" + @($rb | Select-String -Pattern "^\s+client-id:").Count; "RB_PARTB=" + @($rb | Select-String -SimpleMatch -Pattern "Record the App ID").Count; "README_NUMERIC=" + @(Get-Content ".github/workflows/README.md" | Select-String -Pattern "numeric App identifier").Count' then CMD-ACTIONLINT, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t19-workflow-prefix-and-actionlint.2026-09-28T20-01.md`. Acceptance: WF_APPID=1, WF_CLIENTID=0, RB_APPID=1, RB_CLIENTID=0, RB_PARTB=1 (the Part B heading at line 99), README_NUMERIC=1; the actionlint version line quoted verbatim; SCOPED_EXIT=0 and REPO_EXIT=0 with the lint output recorded as empty (the baseline tree lints clean; the deprecation is a runtime warning of the action, not a lint finding); the CI version 1.7.7 from .github/workflows/_actionlint.yml line 26 recorded beside the local version. + +- [x] [P0-T20] Run CMD-HYGIENE with `` set to "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929" and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t20-hygiene.2026-09-28T20-01.md`. Acceptance: PATTERNS=3, SELFTEST=1, SELFTEST_NEG=0, HITS=0 and SCANNED at least 20 (the Phase 0 artifacts plus issue.md and the plan); the hit listing, when non-empty before a fix, is recorded as printed (repository-relative). Remedy: a hit in a file this plan's execution authored (every artifact under the evidence tree, and from Phase 1 on the Write Set text files) is fixed by replacing the leaked value with its placeholder in the offending file and re-running CMD-HYGIENE until HITS=0, with the pre-fix hit count recorded in the artifact as `PRE-FIX-HITS:` (0 when no fix was needed); a hit in a scanned file the execution did not author (issue.md and this plan file, whose only permitted edits are check-offs) stops the task with a report naming the file and line. Every later task that cites CMD-HYGIENE applies this same remedy. + +- [x] [P0-T21] Commit the Phase 0 evidence, plus any Write Set member P0-T13 listed under `FORMAT-REWROTE-WRITE-SET:`, with git add -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929 and git commit -m "docs(929): phase 0 baseline evidence" -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929 , then record git rev-parse HEAD (recorded as ``) and git status --porcelain --untracked-files=all in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/baseline/p0-t21-commit.2026-09-28T20-01.md`. Acceptance: the recorded head differs from ``; the porcelain capture contains no entry outside the feature folder and the agent-memory tree; git show --name-only --format= HEAD lists at least 20 paths under the feature folder and, outside it, only the members P0-T13 listed. When a formatter rewrite is committed here the commit message reads "style(929): apply the PoshQC formatter to pre-existing drift, plus phase 0 baseline evidence" instead. The artifact is written after the commit and is swept by P1-T14. + +### Phase 1 — Constrained Implementation + +- [x] [P1-T1] Hand off to powershell-typed-engineer (when the executor has no sub-agent dispatch tool it authors the file inline within exactly these bounds and records the substitution as a `WORKER:` line in this task's artifact): create `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` (UTF-8 with BOM, LF line endings, ASCII content only, Set-StrictMode -Version Latest, at most 200 lines, no Start-Sleep, no temporary file, no Mock) with a BeforeAll that resolves $script:RepoRoot from $PSScriptRoot as ConsistencyVerifier.Tests.ps1 line 4 does and imports scripts/dependencies/ConsistencyVerifier.psm1 with -Force, one Describe named 'Repository tree consistency (issue 929)', and exactly these four It blocks, named verbatim: (1) 'reports no Import element whose package the sibling manifest omits, for every project directory that carries a manifest' — enumerate the directories directly under $script:RepoRoot that contain packages.config and exactly one .csproj, assert the pair count is greater than 9, call Find-PackageAbsentFromManifest per pair with both texts read via [System.IO.File]::ReadAllText, keep findings whose Kind is Import as strings of the form ": line " (for example QuickFiler.Test.csproj: line 8 altcover.8.6.45), assert the summed ExaminedCount is greater than 0 and the finding list count is 0 with -Because listing the findings; (2) 'names in the SVGControl binding redirects the assembly version the SVGControl project reference declares' — for each of Fizzler and System.Runtime.CompilerServices.Unsafe read the Reference version from SVGControl/SVGControl.csproj by regex on Include=", Version=(...)", assert it is non-empty, read the dependentAssembly block for that name from SVGControl/app.config by regex, and assert newVersion equals the reference version and oldVersion ends with a hyphen followed by that version; (3) 'passes client-id and not app-id to the create-github-app-token step of the repair workflow' — locate the step block of .github/workflows/dependabot-repair.yml whose uses line contains actions/create-github-app-token@ using the Get-WorkflowStepBlock approach of DependabotConfig.Tests.ps1 lines 156 to 178 (re-implemented locally, not dot-sourced), assert the block is non-empty, exactly one line matches ^\s+client-id:\s*\$\{\{\s*secrets\.[A-Z0-9_]+\s*\}\}\s*$ and zero lines match ^\s+app-id:; the client-id count assertion carries -Because text containing the literal client-id and the app-id count assertion carries -Because text containing the literal app-id; (4) 'instructs the maintainer to store the Client ID in the secret the repair workflow reads by name' — extract the secret name from the workflow's client-id line (assert non-empty), read the runbook at its Write Set path, assert exactly one runbook line matches ^\s*client-id:\s*\$\{\{\s*secrets\.\s*\}\} , zero runbook lines match ^\s*app-id:, and the lines between the headings beginning "### Part D" and "### Part E" contain both the token Client ID and the secret name; the non-empty assertion on the extracted name carries -Because text containing the literal secret name, and the runbook client-id count assertion carries -Because text containing the literal client-id. Record the created file's line count and It names in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t1-tree-test-authored.2026-09-28T20-01.md`. Acceptance: the file exists; Select-String -Pattern "^\s*It '" over it returns exactly 4 lines whose quoted names equal the four above; Select-String for Start-Sleep, GetTempFileName, New-TemporaryFile and Mock returns 0 lines; no It or Describe name matches AC followed by a digit; the line count is at most 200. + +- [x] [P1-T2] [expect-fail] With the new test file present and the tree otherwise unfixed, record `RUN-START:`, run CMD-POSHQC-TEST, run CMD-JUNIT-READ, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md` carrying `ExpectedExitCode: 1`. Acceptance: the payload's ok value recorded verbatim (expected false) and `EXIT_CODE: 1` under the CMD-POSHQC-TEST rule; JUNIT-WRITTEN later than RUN-START; the JUNIT-SUITE line for RepositoryTreeConsistency.Tests.ps1 reads tests=4 failures=4 skipped=0; JUNIT-ROOT reads tests=135 failures=4 (the P0-T15 total 131 plus 4, every other suite line carrying failures=0); exactly four JUNIT-NOTPASSED lines, all naming the Describe 'Repository tree consistency (issue 929)', each followed by its JUNIT-MESSAGE line quoted with any worktree prefix replaced by the placeholder, and the first contains QuickFiler.Test.csproj and altcover.8.6.45, the second contains 1.3.0.0 and 1.3.1.0, the third contains client-id and the fourth contains secret name (the -Because literals P1-T1 fixes); `GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run` recorded. A failures value below 4 for that suite means a test does not reproduce its defect and the task is not complete; report rather than weaken the test. A failure in any other suite is a cause outside this task and stops it with a report. + +- [x] [P1-T3] Hand off to powershell-typed-engineer (when the executor has no sub-agent dispatch tool it edits inline within exactly these bounds and records the substitution as a `WORKER:` line in this task's artifact): in `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1` add, inside the Context 'Package absent from the manifest' after the It block that begins at line 228 (line numbers as at the planning snapshot, before this task's own edits), two It blocks named verbatim 'reports an Import whose package the manifest does not declare, with Kind Import' (Arrange with $script:GuardedUnmanifestedProject and $script:Manifest; Act Find-PackageAbsentFromManifest; Assert FindingCount 2, every Finding Kind equals Import, every PackageFolder equals altcover.8.6.45) and 'reports no Import finding when the manifest declares the imported package' (Arrange $script:AgreeingProject; Assert the Import-kind subset of Finding is empty and ExaminedCount is greater than 0); replace the comment at lines 57 to 59 so it drops the stale "Tracked separately" sentence, keeps the no-hard-coded-exception sentence, and reads that the fixture reproduces the shape QuickFiler.Test/QuickFiler.Test.csproj carried at lines 8 and 537 until issue 929 removed both imports; replace the comment at line 275 so "the live shape from QuickFiler.Test" reads "the shape QuickFiler.Test carried before issue 929"; then record `RUN-START:`, run CMD-POSHQC-TEST, run CMD-JUNIT-READ, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t3-verifier-import-tests.2026-09-28T20-01.md` carrying `ExpectedExitCode: 1` (the four tree tests of P1-T1 are still red by design until P1-T9; decision D13). Acceptance: the JUNIT-SUITE line for ConsistencyVerifier.Tests.ps1 reads tests=14 failures=0 skipped=0 (12 existing plus 2); JUNIT-ROOT reads tests=137 failures=4 with the four failures all in the RepositoryTreeConsistency.Tests.ps1 suite (tests=4 failures=4) and every other suite at failures=0; `EXIT_CODE: 1` under the CMD-POSHQC-TEST rule with the ok value recorded; JUNIT-WRITTEN later than RUN-START; Select-String for "carries a live instance", "live shape", "lines 8 and 514" and "Tracked separately" over the file returns 0 lines; no test name matches AC followed by a digit; the file is at most 500 lines with the count recorded; `GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run` recorded. + +- [x] [P1-T4] Delete the two altcover Import elements from `QuickFiler.Test/QuickFiler.Test.csproj` (the lines that were 8 and 537 on the post-merge tree, each an Import whose Project attribute names altcover.8.6.45) with no other change to the file, then run pwsh -NoProfile -Command 'Set-Location ""; "NUMSTAT=" + (git diff --numstat -- QuickFiler.Test/QuickFiler.Test.csproj); "LINES=" + @(Get-Content QuickFiler.Test/QuickFiler.Test.csproj).Count; "ALTCOVER_LINES=" + @(git grep -i -n altcover -- "*.csproj" "*/packages.config").Count' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t4-altcover-imports-removed.2026-09-28T20-01.md`. Acceptance: NUMSTAT reads 0 added and 2 deleted for that path; LINES is 568 (570 minus 2; re-derived 2026-09-30); ALTCOVER_LINES is 0 (the search P0-T17 measured at 2, over the same pathspec); the two deleted lines are quoted verbatim from git diff -- QuickFiler.Test/QuickFiler.Test.csproj. + +- [x] [P1-T5] Edit `SVGControl/app.config` so line 15 reads and line 19 reads with the surrounding indentation, encoding and line endings unchanged, then run git diff --numstat -- SVGControl/app.config and CMD-REDIRECT-OBSERVE and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t5-redirects-fixed.2026-09-28T20-01.md`. Acceptance: numstat reads 2 added and 2 deleted; FIZZLER_REPAIRS=0 and UNSAFE_REPAIRS=0 with EXAMINED=4 (P0-T18 measured 1, 1 and 4 on the same command); the two new lines quoted verbatim from git diff -- SVGControl/app.config; the Fizzler and Unsafe values equal FIZZLER_ASM and UNSAFE_ASM from P0-T18. + +- [x] [P1-T6] Edit `.github/workflows/dependabot-repair.yml`: replace line 51 with the same indentation followed by client-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }}, and rewrite the header comment at lines 13 to 14 so it states that the token is minted from the App's Client ID stored in DEPENDABOT_REPAIR_APP_ID and the private key in DEPENDABOT_REPAIR_APP_PRIVATE_KEY, keeping the comment within the same two lines; then run pwsh -NoProfile -Command 'Set-Location ""; $w = Get-Content ".github/workflows/dependabot-repair.yml"; "WF_APPID=" + @($w | Select-String -Pattern "^\s+app-id:").Count; "WF_CLIENTID=" + @($w | Select-String -Pattern "^\s+client-id:").Count; "WF_SECRET=" + @($w | Select-String -Pattern "secrets\.DEPENDABOT_REPAIR_APP_ID").Count; "NUMSTAT=" + (git diff --numstat -- .github/workflows/dependabot-repair.yml)' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t6-workflow-client-id.2026-09-28T20-01.md`. Acceptance: WF_APPID=0, WF_CLIENTID=1, WF_SECRET is at least 1 (the secret name is unchanged, per D3); NUMSTAT reads at most 3 added and at most 3 deleted; the diff hunks quoted verbatim touch only lines 13, 14 and 51. + +- [x] [P1-T7] Run CMD-ACTIONLINT, then record `RUN-START:`, run CMD-POSHQC-TEST and CMD-JUNIT-READ, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t7-actionlint.2026-09-28T20-01.md` carrying `ExpectedExitCode: 1` (tree test 4, the runbook test, is still red by design until P1-T8; decision D13). Acceptance: the actionlint version line quoted; SCOPED_EXIT=0 and REPO_EXIT=0 with the lint output recorded as empty; the JUNIT-SUITE line for DependabotConfig.Tests.ps1 reads tests=17 failures=0 skipped=0 (the existing workflow static tests still hold after the edit); the JUNIT-SUITE line for RepositoryTreeConsistency.Tests.ps1 reads tests=4 failures=1 with the single JUNIT-NOTPASSED line naming the fourth test (the secret-name runbook test) and JUNIT-ROOT reads tests=137 failures=1, which shows tests 1 to 3 now pass after P1-T4 to P1-T6 and test 4 still reproduces its defect; `EXIT_CODE: 1` under the CMD-POSHQC-TEST rule with the ok value recorded; JUNIT-WRITTEN later than RUN-START; `GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run` recorded. A non-empty actionlint output is quoted verbatim and the workflow edit is corrected before this task can pass; a root failures value other than 1 stops the task with a report. + +- [x] [P1-T8] Edit the runbook `docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md`: retitle the Part B heading at line 99 to "### Part B — Record the Client ID and generate a private key"; in step 10 (lines 101 to 106) instruct the maintainer to record the Client ID shown in the About section and state that the numeric App ID is not needed because the workflow passes the Client ID as the client-id input; in step 22 (lines 129 to 132) rename the item to the Client ID secret with Name DEPENDABOT_REPAIR_APP_ID and Secret "the Client ID value recorded in step 10"; replace line 154 of the YAML sample with the same indentation followed by client-id: ${{ secrets.DEPENDABOT_REPAIR_APP_ID }}; leave the citations at lines 301 and 318 unchanged. Then run pwsh -NoProfile -Command 'Set-Location ""; $rb = Get-Content "docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md"; "RB_APPID=" + @($rb | Select-String -Pattern "^\s+app-id:").Count; "RB_CLIENTID=" + @($rb | Select-String -Pattern "^\s+client-id:").Count; "RB_SECRET=" + @($rb | Select-String -Pattern "DEPENDABOT_REPAIR_APP_ID").Count; "RB_PARTB=" + @($rb | Select-String -SimpleMatch -Pattern "Record the App ID").Count; $d = [array]::IndexOf(@($rb | ForEach-Object { $_ -like "### Part D*" }), $true); $e = [array]::IndexOf(@($rb | ForEach-Object { $_ -like "### Part E*" }), $true); "PARTD_CLIENTID=" + @($rb[$d..$e] | Select-String -Pattern "Client ID").Count' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t8-runbook-client-id.2026-09-28T20-01.md`. Acceptance: RB_APPID=0, RB_CLIENTID=1, RB_SECRET at least 2 (step 22 and the YAML sample), PARTD_CLIENTID at least 1, a search for "Record the App ID" over the runbook returns 0 lines (RB_PARTB=0; P0-T19 measured 1); the diff hunks against quoted verbatim. + +- [x] [P1-T9] Edit `.github/workflows/README.md` line 116 (line 115 before the merge) so the DEPENDABOT_REPAIR_APP_ID row reads that the secret holds the App's Client ID, passed to the token action's client-id input (the numeric App ID is not stored), keeping the table shape and introducing no backticked three-part version literal (the AC26 test in DependabotConfig.Tests.ps1 reads every such literal in this file); then run pwsh -NoProfile -Command 'Set-Location ""; $r = Get-Content ".github/workflows/README.md"; "README_NUMERIC=" + @($r | Select-String -Pattern "numeric App identifier").Count; "README_CLIENTID=" + @($r | Select-String -Pattern "Client ID").Count; "NUMSTAT=" + (git diff --numstat -- .github/workflows/README.md)' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t9-readme-client-id.2026-09-28T20-01.md`. Acceptance: README_NUMERIC=0 (P0-T19 measured 1), README_CLIENTID at least 1, NUMSTAT reads 1 added and 1 deleted. + +- [x] [P1-T10] Replace lines 221 to 223 of `scripts/dependencies/ConsistencyVerifier.psm1` with exactly three lines of the same indentation stating that issue 929 removed the last live instance, two Exists() guarded Import elements in QuickFiler.Test naming an altcover package no manifest declared, that the shape survives as an in-memory test fixture, and that no exception is hard-coded for any package identifier (the phrase "issue 929" appears exactly once); then run pwsh -NoProfile -Command 'Set-Location ""; "LINES=" + @(Get-Content -LiteralPath "scripts/dependencies/ConsistencyVerifier.psm1").Count; "LIVE=" + @(Select-String -Path "scripts/dependencies/ConsistencyVerifier.psm1" -Pattern "carries a live instance").Count; "I929=" + @(Select-String -Path "scripts/dependencies/ConsistencyVerifier.psm1" -Pattern "issue 929").Count; "NUMSTAT=" + (git diff --numstat -- scripts/dependencies/ConsistencyVerifier.psm1)' and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t10-verifier-comment.2026-09-28T20-01.md`. Acceptance: LINES equals `VERIFIER-LINES:` from P0-T13 and is at most 500 (expected 499), LIVE=0, I929=1, NUMSTAT reads 3 added and 3 deleted against ``. Decision D6 governs; a count other than VERIFIER-LINES is a defect in the edit, never a reason to move a line elsewhere. + +- [x] [P1-T11] Record `RUN-START:`, run CMD-POSHQC-TEST once over the fixed tree, run CMD-JUNIT-READ, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md`. Acceptance: the payload's ok value recorded verbatim (expected true) and `EXIT_CODE: 0` under the CMD-POSHQC-TEST rule; JUNIT-WRITTEN later than RUN-START; JUNIT-ROOT reads tests=137 failures=0 errors=0 (131 plus 6) with no JUNIT-NOTPASSED line; exactly 8 JUNIT-SUITE lines, among them RepositoryTreeConsistency.Tests.ps1 tests=4 failures=0 skipped=0, ConsistencyVerifier.Tests.ps1 tests=14 failures=0 skipped=0 and DependabotConfig.Tests.ps1 tests=17 failures=0 skipped=0; the artifact cites the fail-before artifact of P1-T2 by path so the pair is auditable, and carries `GATE-SUBSTITUTION: JUnit per-file counts stand in for a direct Pester run`. + +- [x] [P1-T12] Run CMD-VERIFIER-WHATIF on the fixed tree and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t12-verifier-postfix.2026-09-28T20-01.md`. Acceptance: ABSENT=0 (P0-T17 measured 2), WRITTEN=0, HASHES_EQUAL=True, PROJECTS=18, FILES equal to the P0-T17 value; DISAGREE equals the P0-T17 value (this change moves no version; the value itself carries no expectation, as P0-T17 states), SUCCESS recorded as measured; every -WhatIf target path recorded with its prefix replaced by ``. + +- [x] [P1-T13] REMOVED (N/A, coordinator ruling 2026-09-30): the Meziantou analyzer-item potential entry is not authored on this branch because the origin/main merge removed the skew it would have described (Revision Log, D8); the coordinator checks the skew and files it through the promotion path if it survives. No action and no artifact; the executor ticks this line when it reaches it. + +- [x] [P1-T14] Run CMD-HYGIENE with `` set to "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929","tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1",".github/workflows/dependabot-repair.yml",".github/workflows/README.md","docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md","scripts/dependencies/ConsistencyVerifier.psm1","tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1", record the line counts of every Write Set file that is not Markdown, then commit with git add -- QuickFiler.Test/QuickFiler.Test.csproj SVGControl/app.config .github/workflows/dependabot-repair.yml .github/workflows/README.md docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md scripts/dependencies/ConsistencyVerifier.psm1 tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 docs/features/active/2026-09-28-package-manifest-consistency-residuals-929 and git commit -m "fix(929): remove altcover imports, correct SVGControl redirects, pass client-id to the token action", then push with git push origin bug/package-manifest-consistency-residuals-929 so the CI run P2-T3 reads is on the implementation commit, then record git rev-parse HEAD, git show --name-only --format= HEAD, git status --porcelain --untracked-files=all and git ls-remote --heads origin bug/package-manifest-consistency-residuals-929 (recorded as `PUSHED-HEAD:`) in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p1-t14-commit.2026-09-28T20-01.md`. Acceptance: the pre-commit hygiene run reports PATTERNS=3, SELFTEST=1, SELFTEST_NEG=0, HITS=0 and SCANNED at least 1 (all five CMD-HYGIENE conditions), with any hit remedied under the P0-T20 remedy before the commit is made and `PRE-FIX-HITS:` recorded; every non-Markdown Write Set file is at most 500 lines and ConsistencyVerifier.psm1 equals `VERIFIER-LINES:`; the commit lists all eight named non-feature-folder paths plus at least 12 paths under the feature folder; the recorded head differs from ``; the porcelain capture contains no entry outside the feature folder and the agent-memory tree; the push exits 0 and `PUSHED-HEAD:` names the recorded head. This commit of source paths relies on the orchestrator's pre-implementation checkpoint being present; the executor does not create or edit that checkpoint. The push starts no CI run by itself (ci.yml lines 3 to 8); P2-T3 dispatches one. + +### Phase 2 — Final QC Loop + +The seven command tasks P2-T1 to P2-T7 run in order in one pass. If any fails, or any rewrites a Write Set member, restart at P2-T1 with the artifact suffix incremented (iter2, iter3); a formatter rewrite outside the Write Set is reverted by P2-T1 under D9 and does not restart the loop. No task in this phase may record `EXIT_CODE: SKIPPED`. + +- [x] [P2-T1] PowerShell QC step 1 (format): hash every .ps1, .psm1 and .psd1 file under scripts/dependencies and tests/scripts/dependencies, run CMD-POSHQC-FORMAT, re-hash, revert with git checkout -- every path whose hash changed and that is not a Write Set member (pre-existing drift, per D9), capture git status --porcelain --untracked-files=all -- scripts/dependencies tests/scripts/dependencies, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t1-poshqc-format.iter1.2026-09-28T20-01.md`. Acceptance: both hash sets recorded with exactly 14 entries each (6 production, 8 test files); `REVERT-SET:` recorded explicitly, including the empty case; the rewrite count over Write Set members is exactly 0; the post-revert porcelain capture over the two folders is empty; ConsistencyVerifier.psm1 equals `VERIFIER-LINES:`; the scan_folders value recorded. A path in `REVERT-SET:` is pre-existing drift outside the Write Set: it is reverted and listed here, and per convention 8 it does not restart the loop. A non-zero Write Set rewrite count means the formatter changed one of this change's files; keep the rewrite (formatter output wins) and run git diff --numstat HEAD -- , recorded verbatim as `REWRITE-NUMSTAT:`. When that output is non-empty, re-run P1-T11 to confirm the tests still pass, commit the rewritten Write Set members with git add -- and git commit -m "style(929): apply the PoshQC formatter to this change" -- , record that commit SHA in this iteration's artifact, and restart this loop as iter2. When that output is empty, the rewrite changed line terminators only, which the `* text=auto` rule at .gitattributes line 4 normalises out of the committed content, so no commit is made: record `FORMAT-REWRITE-TERMINATOR-ONLY:` with the member list and restart this loop as iter2 without a commit. The post-revert porcelain clause is evaluated after the commit, or after the `REWRITE-NUMSTAT:` capture when no commit is made. + +- [x] [P2-T2] PowerShell QC step 2 (analyze): run CMD-POSHQC-ANALYZE and pwsh -NoProfile -Command 'Set-Location ""; "FILES=" + @(Get-ChildItem -Recurse -File -Path "scripts/dependencies","tests/scripts/dependencies" -Include *.ps1,*.psm1).Count', and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t2-poshqc-analyze.iter1.2026-09-28T20-01.md`. Acceptance: the MCP payload recorded verbatim with the exact scan_folders value; ok is true, recorded as the exact line "PoshQC analyze: pass (0 findings); tool reports no count" with `EXIT_CODE: 0`; FILES=14 (P0-T14 measured 13, plus the created test file); `GATE-SUBSTITUTION: PoshQC analyze ok flag stands in for a diagnostic count` recorded. An ok value of false fails this step: because P0-T14 read ok true over the same two folders and P2-T1's porcelain shows no rewrite outside the Write Set, the finding is attributable to this change, so the executor repairs the offending Write Set file (the summary and stderr excerpt name what the tool reports), re-runs P1-T11, commits the repair with git add -- and git commit -m "fix(929): resolve the PoshQC analyzer finding" -- , records that SHA, and restarts the loop as the next iteration. No Invoke-ScriptAnalyzer run, tuple list or multiset comparison is made. + +- [x] [P2-T3] PowerShell QC step 3 (test, with coverage read from CI): record `RUN-START:`, run CMD-POSHQC-TEST and CMD-JUNIT-READ; then, when git rev-parse HEAD differs from the `PUSHED-HEAD:` value P1-T14 recorded (a P2-T1 formatter commit or a P2-T2 repair commit moved it), push with git push origin bug/package-manifest-consistency-residuals-929 and record the new `PUSHED-HEAD:`; then run CMD-CI-LIST, CMD-CI-DISPATCH and CMD-CI-WATCH under the rule of CMD-CI-DISPATCH, run CMD-CI-PESTER with the selected `` and `` coverage/ci-branch-pester-- ( is 1 for the first invocation against that run and increases by 1 on each further invocation), and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t3-pester.iter1.2026-09-28T20-01.md`. This task completes only after the push and after CI has reported; the next task does not start before it. Acceptance: the MCP payload recorded with ok true and `EXIT_CODE: 0` under the CMD-POSHQC-TEST rule; JUNIT-WRITTEN later than RUN-START; JUNIT-ROOT reads tests=137 failures=0 errors=0 with no JUNIT-NOTPASSED line and the three suites RepositoryTreeConsistency.Tests.ps1 tests=4, ConsistencyVerifier.Tests.ps1 tests=14 and DependabotConfig.Tests.ps1 tests=17 each at failures=0; the final CMD-CI-LIST output recorded with REMOTE naming HEAD, every CMD-CI-LIST re-run, the single DISPATCH-EXIT=0 line when a dispatch was made and every WATCH-EXIT line recorded; the RUN line records head equal to HEAD, branch=bug/package-manifest-consistency-residuals-929, status=completed and workflow=CI, with the run id and head SHA recorded beside every CI figure; PESTER-JOBS=1 and the Pester job's conclusion=success (the run-level conclusion is recorded as measured and, when it is not success, every other job's name and conclusion is recorded and reported to the caller without failing this task, because those jobs gate nothing this task asserts); the "Tests Passed:", "PESTER Passed=" and "COVERAGE LinePercent=" lines quoted verbatim from the log with Failed 0, Skipped 0 and Total equal to `BASELINE-TOTAL:` plus 6 (four tree tests and two Import-kind tests); the report LINE percent computed from REPORT-LINE to two decimals, equal to the log's LinePercent figure and at least 80, with `MEETS-85:` recorded as true when it is at least 85 and false otherwise, an observation only under convention 10; DIR-PREEXISTS=False, DOWNLOAD-EXIT=0 and ARTIFACT-FILES=1, with the `` value used recorded; the six SOURCEFILE lines recorded and the ConsistencyVerifier.psm1 covered count at least `VERIFIER-COVERED:` with missed at most `VERIFIER-MISSED:` (no executable production line changed; both inequalities must hold, and equality is not required because the tree tests may execute additional lines); the standing-in statement and the no-branch-counter statement present; the downloaded JaCoCo document left under the coverage directory; `GATE-SUBSTITUTION: CI Pester job on the pushed head stands in for a local coverage run` recorded. A Pester job conclusion other than success, a Total other than BASELINE-TOTAL plus 6, or a covered count below VERIFIER-COVERED fails this step and the loop restarts after the cause is repaired within the Write Set. + +- [x] [P2-T4] C# QC step 1: run CMD-CSHARPIER-CHECK (with its XML-CANDIDATES companion) and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t4-csharpier-check.iter1.2026-09-28T20-01.md`. Acceptance: `EXIT_CODE:` equal to the P0-T9 exit code (expected 0); the verbatim "Checked N files in Xms." line recorded with N, and `XML-CANDIDATES:` recorded with its count and list; `CHECKED-DELTA:` recorded as N minus the P0-T9 N and `XML-DELTA:` as this task's XML-CANDIDATES count minus P0-T9's; CHECKED-DELTA equals 0 or equals XML-DELTA (no C# file was added or removed by this plan; the PoshQC test tool, the coverage runner and the CI downloads create *.xml files under the ignored artifacts/ and coverage/ trees between P0-T9 and this task, and whether CSharpier 1.2.6 counts gitignored files was not observed, so the two admissible values are the two behaviours; when XML-DELTA is 0 the only admissible CHECKED-DELTA is 0), the branch taken recorded as `CSHARPIER-COUNTS-IGNORED-XML:` true, false or undetermined; `CSHARPIER-FINDINGS:` recorded in the P0-T9 form and equal to the P0-T9 list (expected `CSHARPIER-FINDINGS: none`). The check subcommand is read-only and rewrites nothing, so the Write Set rewrite branch of convention 8 cannot arise for this task and no C# formatter commit exists anywhere in this plan; a findings list identical to the P0-T9 list is pre-existing drift outside the Write Set (no C# file is in the Write Set), recorded and reported to the caller, and it does not restart the loop because no task in this plan can change a C# file; a path in the findings list that P0-T9 did not list, or an exit code different from P0-T9's, stops the run with a report, because this change touches no C# file and cannot be its cause. + +- [x] [P2-T5] C# QC step 2: satisfy CMD-OUTLOOK, run CMD-MSBUILD-ANALYZERS and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t5-msbuild-analyzers.iter1.2026-09-28T20-01.md`. Acceptance: `EXIT_CODE: 0` (the recorded MSBUILD_EXIT value); `OUTLOOK-CLOSED: true`; CS0006_LINES exactly 0; OUT_LINES at least 18 with the exact count recorded and equal to the P0-T10 OUT_LINES; "0 Error(s)" quoted. This is the post-change solution rebuild AC7 names. + +- [x] [P2-T6] C# QC step 3: satisfy CMD-OUTLOOK, run CMD-MSBUILD-NULLABLE and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t6-msbuild-nullable.iter1.2026-09-28T20-01.md`. Acceptance: `EXIT_CODE: 0` (the recorded MSBUILD_EXIT value); `OUTLOOK-CLOSED: true`; OUT_LINES at least 18 with the exact count recorded and equal to the P0-T11 OUT_LINES; "0 Error(s)" quoted. + +- [x] [P2-T7] C# QC step 4: run CMD-MSTEST-COVERAGE and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md`; copy the printed projection to `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml` and the printed summary to `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt`. Acceptance: `EXIT_CODE: 0`; the "First-party coverage:" line quoted verbatim with both percentages recorded as numbers; `MEETS-85:` recorded as true when the line percentage is at least 85 and false otherwise, an observation only under convention 10; failed 0 and passed greater than 0 from the summary; both copies made (or the not-produced branch recorded exactly as P0-T12 specifies) with sizes recorded; the projection's package LINE covered sum equals the line numerator on the printed line; the path-printing lines recorded with placeholders as P0-T12 specifies; the raw documents not copied. + +- [x] [P2-T8] Record the single-pass attestation and the coverage reconciliation in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t8-attestation-and-coverage-delta.2026-09-28T20-01.md`, citing the seven P2-T1 to P2-T7 artifacts of the final iteration by path with their `EXIT_CODE:` values and `Timestamp:` values. Acceptance: all seven exit codes equal their expected values (0 for P2-T1 to P2-T3 and P2-T5 to P2-T7; the P0-T9 exit code, expected 0, for P2-T4); the seven timestamps are non-decreasing in task order and all carry the same iter suffix; C# line and branch percentages from P2-T7 minus those from P0-T12 are each at least -0.5 percentage points, with the two deltas recorded as numbers; the PowerShell aggregate from P2-T3 (CI run on the pushed head) is at least 80 and the ConsistencyVerifier.psm1 covered count from P2-T3 is at least the P0-T16 value (CI run 36666302259 on main), both CI run ids and head SHAs recorded; the artifact states that no PowerShell branch figure exists and names Pester as the reason, and that this change adds no new module so no 90 percent new-module gate applies. A delta below -0.5 is a blocking regression and the run stops with a report. + +- [x] [P2-T9] Audit file size across the change footprint into `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t9-file-size-audit.2026-09-28T20-01.md`: record the line count of every non-Markdown Write Set file — QuickFiler.Test/QuickFiler.Test.csproj, SVGControl/app.config, .github/workflows/dependabot-repair.yml, scripts/dependencies/ConsistencyVerifier.psm1, tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 and tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1. Acceptance: exactly 6 files listed with integer counts; ConsistencyVerifier.psm1 equals `VERIFIER-LINES:` and is at most 500; the two test files at most 500; the project file 568 (the post-merge 570 minus the two deleted imports). Markdown files are exempt from the 500-line cap and are deliberately not listed. + +- [x] [P2-T10] Verify the change footprint with CMD-FOOTPRINT into `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t10-change-footprint.2026-09-28T20-01.md`. Acceptance: every path in the union of the anchored name-only diff and the porcelain capture is a Write Set member, lies under the feature folder, or lies under the agent-memory tree; the union contains exactly the eight non-feature-folder Write Set paths named in P1-T14 (a Write Set member P0-T21 committed for formatter drift is one of those eight and adds nothing; no path under docs/features/potential appears); it contains exactly 0 paths matching *.cs, exactly 0 paths under .claude/rules, .github/instructions or the config directory, exactly 0 other *.csproj, packages.config or app.config paths (the count the AC7 check-off cites as proof the analyzer-item skew was not repaired on this branch); the two capture texts are quoted verbatim. + +- [x] [P2-T11] Run CMD-HYGIENE with `` set to "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929",".github/workflows/dependabot-repair.yml",".github/workflows/README.md","docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks","tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1" and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t11-hygiene.2026-09-28T20-01.md`. Acceptance: PATTERNS=3, SELFTEST=1, SELFTEST_NEG=0, HITS=0 and SCANNED at least 45 (all five CMD-HYGIENE conditions; 44 evidence .md artifacts exist by this task (21 from Phase 0, 13 from Phase 1 with P1-T13 producing none, 10 from P2-T1 to P2-T10 in a single-iteration run), plus issue.md, the plan, the four projection and summary copies, the runbook, the workflow, the README and the test file, 54 files in a single-iteration run; a further iteration adds its own artifacts and only raises the count); any hit remedied under the P0-T20 remedy with `PRE-FIX-HITS:` recorded; the projection and summary copies are included in the scan because their extensions are in the filter list. + +- [x] [P2-T12] Check off AC1 in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` after reading the P1-T4 artifact (0 altcover lines over project files and manifests, 568 lines, numstat 0/2) and the P2-T5 artifact, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t12-ac1-checkoff.2026-09-28T20-01.md`. Acceptance: the AC1 line changes from `- [ ] AC1:` to `- [x] AC1:` with no other character changed; the artifact cites both artifacts by path and quotes ALTCOVER_LINES=0. + +- [x] [P2-T13] Check off AC2 in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` after reading the P0-T18 artifact (FIZZLER_ASM 1.3.1.0, pre-fix FIZZLER_REPAIRS=1), the P1-T5 artifact (post-fix FIZZLER_REPAIRS=0, the new line 15 quoted) and the P1-T11 artifact (the SVGControl redirect test passing), and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t13-ac2-checkoff.2026-09-28T20-01.md`. Acceptance: only the AC2 checkbox changes; the artifact cites the three artifacts by path. + +- [x] [P2-T14] Check off AC3 in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` after reading the P0-T18 artifact (UNSAFE_ASM 6.0.3.0, pre-fix UNSAFE_REPAIRS=1), the P1-T5 artifact (post-fix UNSAFE_REPAIRS=0, the new line 19 quoted) and the P1-T11 artifact, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t14-ac3-checkoff.2026-09-28T20-01.md`. Acceptance: only the AC3 checkbox changes; the artifact cites the three artifacts by path. + +- [x] [P2-T15] Check off AC4 in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` after reading the P1-T3 artifact (the two Import-kind in-memory tests; the ConsistencyVerifier.Tests.ps1 suite line reads tests=14 failures=0), the P1-T2 and P1-T11 pair (the tree Import test failing at 2 findings before and passing at 0 after), the P1-T12 artifact (ABSENT=0 on the tree) and the P2-T3 artifact (the full suite green), and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t15-ac4-checkoff.2026-09-28T20-01.md`. Acceptance: only the AC4 checkbox changes; the artifact cites the five artifacts by path and records decision D1 (the rule pre-existed; AC4 is discharged by explicit tests and the tree observation, not by a new production rule). + +- [x] [P2-T16] Check off AC5 in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` after reading the P1-T6 artifact (WF_APPID=0, WF_CLIENTID=1), the P1-T7 artifact (actionlint clean, 17 workflow tests passing) and the P1-T11 artifact (the workflow input test passing), and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t16-ac5-checkoff.2026-09-28T20-01.md`. Acceptance: only the AC5 checkbox changes; the artifact cites the three artifacts by path. + +- [x] [P2-T17] Check off AC6 in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` after reading the P1-T8 artifact (RB_APPID=0, RB_CLIENTID=1, RB_PARTB=0, PARTD_CLIENTID at least 1), the P1-T9 artifact (README row updated) and the P1-T11 artifact (the runbook secret-name test passing, which extracts the name from the workflow), and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t17-ac6-checkoff.2026-09-28T20-01.md`. Acceptance: only the AC6 checkbox changes; the artifact cites the three artifacts by path and records decision D3. + +- [x] [P2-T18] Check off AC7 in `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md` after reading the P0-T5 artifact (the restore, with PACKAGE_DIRS_BEFORE as measured), the P0-T6 artifact (the ANALYZER-ITEM-STATE line), the P2-T8 attestation, the seven final-iteration artifacts it cites and the P2-T10 footprint artifact, and write `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t18-ac7-checkoff.2026-09-28T20-01.md`. Acceptance: only the AC7 checkbox changes; the artifact quotes the `ANALYZER-ITEM-STATE: aligned` line and the UNRESOLVED=0 census line verbatim from the P0-T6 artifact, states in one sentence that the cold restore of P0-T5 (PACKAGE_DIRS_BEFORE as measured) was followed by the P0-T10, P0-T11, P2-T5 and P2-T6 rebuilds exiting 0 with no back-fill performed (decision D8; the amended AC7's back-fill clause is permissive and was not exercised, so AC7 is satisfied with its text unchanged), cites the P2-T10 zero count of other project files and manifests as proof no analyzer item or manifest was changed on this branch, and records the C# and PowerShell no-new-failure comparison from P2-T8 with its numbers and the two CI run ids. An ANALYZER-ITEM-STATE value other than aligned cannot occur, because P0-T6 stops the run on any UNRESOLVED above 0; a missing element leaves AC7 unchecked with the gap recorded. + +- [x] [P2-T19] Write the maintainer follow-up record `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/other/p2-t19-maintainer-followup.2026-09-28T20-01.md` stating that acceptance criteria AC18, AC19 and AC20 of issue 911 remain deferred to the maintainer until a GitHub App credential is provisioned, that the secret store (repository Actions secrets versus Dependabot secrets for a Dependabot-triggered workflow_run) remains unconfirmed, that the secret named DEPENDABOT_REPAIR_APP_ID must now hold the App's Client ID, and citing the runbook path and the 911 spec; then run pwsh -NoProfile -Command 'Set-Location ""; "DEFERRED_UNCHECKED=" + @(Select-String -Path "docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/spec.md" -Pattern "^- \[ \] \*\*AC(18|19|20) ").Count'. Acceptance: DEFERRED_UNCHECKED=3 (the three criteria stay unchecked in the 911 spec and this plan changes nothing there); the artifact contains the sentence "This item is not an acceptance criterion and not a merge gate." and marks nothing passed. + +- [x] [P2-T20] Write the acceptance-criteria status summary to `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/qa-gates/p2-t20-ac-status-summary.2026-09-28T20-01.md` in the format the acceptance-criteria-tracking skill requires (Source, Total AC items 7, Checked off, Remaining, Items remaining), then run CMD-HYGIENE with `` set to "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929" and append its PATTERNS, SELFTEST, SELFTEST_NEG, SCANNED and HITS values to this artifact, then commit with git add -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929 and git commit -m "docs(929): final QC evidence, coverage projection and acceptance check-off" -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929. Acceptance: the pre-commit hygiene run reports PATTERNS=3, SELFTEST=1, SELFTEST_NEG=0, HITS=0 and SCANNED at least 1 (all five CMD-HYGIENE conditions), with any hit remedied under the P0-T20 remedy before the commit and `PRE-FIX-HITS:` recorded; the summary lists 7 items with 7 checked off and 0 remaining, or lists every unchecked item by criterion text; after the commit, git show --name-only --format= HEAD lists this artifact and the two paths p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml and p2-t7-test-results.2026-09-28T20-01.summary.txt under evidence/qa-gates (or, in the not-produced branch, the projection alone); git status --porcelain --untracked-files=all after the commit contains no entry outside the agent-memory tree except the plan file, whose presence is not asserted either way. The head SHA, the git show listing and the porcelain capture are transcribed into the P2-T21 index because this artifact is inside the commit it describes. + +- [x] [P2-T21] Write the reduced-audit handoff index `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/other/p2-t21-reduced-audit-handoff.2026-09-28T20-01.md` for the feature-reviewer's reduced audit: list every evidence artifact this plan produced with its path, task ID and `EXIT_CODE:`; the fail-before/pass-after pair (P1-T2, P1-T11); the two committed coverage-evidence copies and the baseline copies; the three commit SHAs (P0-T21, P1-T14, P2-T20) and any P2-T1 formatter commit or P2-T2 repair commit with the P2-T20 git show listing and porcelain capture; ``, `` and the `MERGED-MAIN-ANCESTOR:` line from P0-T1; the `ANALYZER-ITEM-STATE: aligned` line from P0-T6; the two CI run ids and head SHAs (36666302259 on main from P0-T16; the branch run from P2-T3) with their Pester job conclusions; the four `MEETS-85:` observations and the convention 10 conflict with issue 668; the `OUT-OF-SCOPE-RESIDUAL:` Fizzler line from P0-T18; every `GATE-SUBSTITUTION:` line the artifacts carry (the P1-T13 removal is recorded here as "no potential entry authored; coordinator ruling 2026-09-30"); the `CSHARPIER-COUNTS-IGNORED-XML:` value from P2-T4; the maintainer follow-up from P2-T19; and the AC status summary. Then run CMD-HYGIENE with `` set to "docs/features/active/2026-09-28-package-manifest-consistency-residuals-929" and append its PATTERNS, SELFTEST, SELFTEST_NEG, SCANNED and HITS values to the index, then run the CI hygiene guard locally with pwsh -NoProfile -Command 'Set-Location ""; & ".\scripts\hygiene\Test-RepositoryHygiene.ps1"; "GUARD_EXIT=$LASTEXITCODE"' and append its output (the "HYGIENE Findings=N" line and GUARD_EXIT), then tick this task's own checkbox in the plan, and commit with git add -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929 and git commit -m "docs(929): reduced-audit handoff index" -- docs/features/active/2026-09-28-package-manifest-consistency-residuals-929. Acceptance: the pre-commit hygiene run reports PATTERNS=3, SELFTEST=1, SELFTEST_NEG=0, HITS=0 and SCANNED at least 1 (all five CMD-HYGIENE conditions), with any hit remedied under the P0-T20 remedy before the commit and `PRE-FIX-HITS:` recorded; the guard prints "HYGIENE Findings=0" with GUARD_EXIT=0 over every tracked file (it reads the worktree content of the paths git ls-files enumerates, Test-RepositoryHygiene.Git.ps1 lines 70 and 124, so the P2-T20 commit's evidence and the Phase 1 Write Set are covered; a finding names a file and line this plan's execution authored and is remedied under the P0-T20 remedy before the commit, and a finding in a file it did not author stops the task with a report, because the merged main passed the same guard in run 36666302259); the index lists at least 54 evidence .md artifacts (the 44 counted at P2-T11 plus the ten P2-T11 to P2-T20 produce, before this index itself; a further loop iteration only raises the count) and every listed path exists on disk; the count of plan lines matching `^- \[x\] \[P\d+-T\d+\]` is 56 and the count matching `^- \[ \] \[P\d+-T\d+\]` is 0 at the moment of the commit; git status --porcelain --untracked-files=all after the commit contains no entry outside the agent-memory tree. + +## Acceptance-Criteria Traceability + +| Criterion | Implementation | Tests | Evidence (check-off task reads) | +|---|---|---|---| +| AC1 | P1-T4 | RepositoryTreeConsistency.Tests.ps1 test 1 (P1-T2 red, P1-T11 green) | P1-T4, P2-T5 artifacts; check-off P2-T12 | +| AC2 | P1-T5 | RepositoryTreeConsistency.Tests.ps1 test 2 | P0-T18, P1-T5, P1-T11; check-off P2-T13 | +| AC3 | P1-T5 | RepositoryTreeConsistency.Tests.ps1 test 2 | P0-T18, P1-T5, P1-T11; check-off P2-T14 | +| AC4 | P1-T1, P1-T3 (D1: no production rule added) | ConsistencyVerifier.Tests.ps1 two Import-kind tests; RepositoryTreeConsistency.Tests.ps1 test 1 | P1-T3, P1-T2, P1-T11, P1-T12, P2-T3; check-off P2-T15 | +| AC5 | P1-T6 | RepositoryTreeConsistency.Tests.ps1 test 3; DependabotConfig.Tests.ps1 (17) | P1-T6, P1-T7, P1-T11; check-off P2-T16 | +| AC6 | P1-T8, P1-T9 | RepositoryTreeConsistency.Tests.ps1 test 4 | P1-T8, P1-T9, P1-T11; check-off P2-T17 | +| AC7 | P0-T5, P0-T6, P2-T1 to P2-T7 | full PowerShell and C# toolchains | P0-T5, P0-T6, P2-T8, P2-T10 and the seven final-iteration artifacts; check-off P2-T18 | + +## Residual Risks and Reports for the Caller + +1. **Analyzer-item skew removed by the merge (D8).** Revisions 1 and 2 planned an environment back-fill of Meziantou.Analyzer.3.0.235 and a potential entry; the origin/main merge at 3091b8af9 (hotfix 89e202ed6) aligned every Analyzer Include item with its manifest, so the plan now performs no back-fill and authors no potential entry. The P0-T6 census is the evidence (162 items, 17 files, UNRESOLVED=0, SKEW_235=0); a non-zero count stops the run with a report rather than reviving the back-fill, because it would describe a tree the coordinator has not measured. The coordinator files the skew through the promotion path if it survives elsewhere. +2. **Transitive Fizzler redirects.** Eleven app.config files other than SVGControl redirect Fizzler to 1.3.0.0 with no Reference to compare against; the 2026-08-04 potential entry already records them. This plan fixes SVGControl only, as AC2 names. +3. **The .csproj.bak copies** carry altcover tokens and are not project files; P0-T1 records whether they are tracked. Their deletion is recommended as a separate housekeeping change. +4. **Workstation test hang.** Earlier runs on this workstation stalled on four UtilitiesCS.Test shell-icon classes; the 911 close-out run on 2026-09-19 completed through the same runner. If CMD-MSTEST-COVERAGE stalls, the task records the stall and stops rather than adding a filter the runner does not expose. +5. **Secret value semantics.** After merge, the maintainer must store the Client ID (not the numeric App ID) under DEPENDABOT_REPAIR_APP_ID; the runbook, the README and the workflow header say so, and P2-T19 carries it into the handoff. +6. **Formatter drift in Phase 0.** If the PoshQC formatter rewrites a Write Set member at P0-T13, that rewrite is committed at P0-T21 and P1-T10 anchors on ``; when the rewrite changed line terminators only, the `* text=auto` rule at .gitattributes line 4 normalises it out of the committed content (the P2-T1 `REWRITE-NUMSTAT:` rule), so the member stages nothing, P0-T21 commits the evidence alone under its plain message, and P1-T10's numstat against `` is unaffected because git diff applies the same normalisation; a rewrite outside the Write Set is reverted at every format step and listed, never committed, and never restarts the Phase 2 loop (convention 8). +7. **Coverage-floor policy conflict (convention 10).** The plan gates on CLAUDE.md's 80 percent floor and records `MEETS-85:` as an observation at four points; the conflict is tracked as open GitHub issue 668 and is not a halt condition for this plan. +8. **No nuget CLI dependency (revision 3).** The back-fill that needed a nuget executable on PATH no longer exists in the plan (risk 1); no task invokes nuget, and the restore of P0-T5 goes through scripts/vscode/Invoke-Restore.ps1 as before. +9. **Pre-existing C# formatter drift.** No C# file is in the Write Set, so a non-empty CSharpier findings list at P0-T9 is carried unchanged to P2-T4, recorded and reported; it is neither fixed nor a restart cause on this branch. +10. **CSharpier and gitignored XML.** .csharpierignore names neither artifacts/ nor coverage/, CSharpier 1.2.6 processes *.xml, and the PoshQC test tool, the coverage runner and the CI artifact downloads create *.xml files under those two ignored trees between P0-T9 and P2-T4. Whether CSharpier honours .gitignore was not observed by the planner (repository evidence of "Checked N" deltas is explained by added .cs files in every case found), so P2-T4 admits a "Checked N" delta equal to the XML-candidate delta or to zero and records which branch held. A C# file added and an XML file created in the same interval would be indistinguishable under that gate; no task in this plan can add a C# file, and P2-T10's footprint (0 paths matching *.cs) is the independent check. +11. **CI dependency at P2-T3.** The Pester coverage figures for this branch come from a ci.yml run on the pushed head, which the plan dispatches through gh workflow run because a push of this branch triggers no run by itself. The task waits for the run with gh run watch (re-invoked on tool timeout) and reads only the Pester job; a red unrelated job is recorded and reported, not absorbed and not a failure of this task. The dispatch needs the executor's gh authentication to carry actions write scope on drmoisan/TaskMaster; a dispatch that exits non-zero stops the task with a report and the caller decides whether to open the pull request (whose pull_request trigger would start the same workflow) or to dispatch by hand. +12. **Runbook path in tree test 4.** Tree test 4 reads the 911 runbook at its active-folder path, which AC6 names; the feature-promotion move of that folder must update the test path in the same change. + +## Planner Self-Review and Preflight Record + +SELF-REVIEW: RE-DERIVED THIS PASS + +In the revision 3.2 pass (2026-09-30, preflight round 5 delta D-1, no shell in the session) the citation the delta introduced was re-derived by reading the file in worktree agent-a74dcedbc13b789fd: .gitattributes line 4 reads `* text=auto` (the only other uncommented attribute line is the issue-400 whitespace rule at line 9). The delta's premise that the working-copy .ps1 and .psm1 files carry CRLF terminators was not independently observed in this session; the inserted text does not depend on it, because the branch is keyed on the git diff --numstat HEAD output rather than on the working-copy terminator state, and it takes the commit branch whenever the index does not normalise the path (a blob already carrying CRLF in the index is left unnormalised by text=auto). The sibling regions re-checked in the same pass: the P2-T1 acceptance clauses that precede the replaced sentence (14-entry hash sets, `REVERT-SET:`, rewrite count 0, post-revert porcelain empty, `VERIFIER-LINES:`); convention 8 and the Phase 2 preamble (restart on any Write Set rewrite, no commit named); P2-T2 (its attribution relies on P2-T1's porcelain, which is empty in both branches once normalisation applies); P2-T3 (push keyed on HEAD differing from `PUSHED-HEAD:`, so the no-commit branch pushes nothing); P2-T8 (same iter suffix); P2-T10 (the formatted member is one of the eight P1-T14 paths already in the anchored diff); the P2-T20 and P2-T21 porcelain clauses; P2-T21's "any P2-T1 formatter commit"; P0-T13, P0-T21 and P1-T10 (the Phase 0 analogue, satisfiable without edit; Residual Risk 6 adjusted); and decision D9. The enumeration is reproduced in the planner's handoff message. + +In the revision 3.1 pass (2026-09-30, preflight round 4 deltas, no shell in the session) every citation the deltas touched was re-derived by reading the files in worktree agent-a74dcedbc13b789fd at HEAD 3091b8af9: scripts/vscode/Invoke-MSTestWithCoverage.ps1 lines 373, 375, 423, 447 and 456 (the five path-printing lines, R7); .github/workflows/ci.yml lines 3 to 8 and 13 to 15 (triggers; concurrency group keyed on the ref with cancel-in-progress true, R3); .claude/hooks/enforce-pr-author-skill-helpers.ps1 line 279 and .claude/hooks/hook-command-invocation.ps1 lines 92 to 116 and 202 to 203 in both the worktree and the session checkout (the containment rule that refused createdAt, R2); artifacts/pester/powershell-coverage.koverage.xml (present, report root, A1); coverage/.gitkeep (tracked, so the msbuild file-logger directory exists at P0-T10, R5). The sibling regions re-checked in the same pass: every CMD-CI-* consumer (P0-T16, P2-T3, P2-T8, P2-T18, P2-T21, Residual Risk 11, the tree-facts CI rows, the revision 3 log entry), every msbuild and csharpier consumer (P0-T9, P0-T10, P0-T11, P2-T4, P2-T5, P2-T6, P2-T8, D7, convention 7), every artifact count (P0-T20 floor 20 against 19 Phase 0 .md artifacts plus issue.md, the plan and two copies; P0-T21 floor 20 against 20 .md plus two copies; P1-T14 floor 12 against 12 Phase 1 .md plus the P0-T21 artifact; P2-T11 44 .md; P2-T21 54 .md), every path-printing-line list (convention 4, CMD-MSTEST-COVERAGE, P0-T12, P2-T7 by reference), every gh-bearing pwsh payload for the sequence create (none carries it), and the three places naming the PoshQC XML files (convention 3, the tree-facts row, CMD-POSHQC-TEST). The enumeration is reproduced in the planner's handoff message. + +In the round 3 revision pass (2026-09-30) every citation in this plan was re-derived against worktree agent-a74dcedbc13b789fd at HEAD 3091b8af9, the merge of origin/main 231e1c0b5, by reading the files directly (the planner had no shell in this session; git facts were read from the worktree's HEAD, reflog and loose refs): the merge-changed files (QuickFiler.Test.csproj, README.md, _pester.yml, .gitignore, Invoke-MSTestWithCoverage.ps1, the new Invoke-MSTestWithCoverage.Scope.ps1 and _hygiene.yml, ci.yml, the build workflows' cache lines), the analyzer census (162 items, 17 files, 0 skewed), the PoshQC JUnit document present in the worktree, the hygiene guard scripts, and every file the revision did not touch (SVGControl, scripts/dependencies, tests/scripts/dependencies, dependabot-repair.yml, the 911 runbook and spec, .csharpierignore, global.json, the vscode scripts, run-actionlint.ps1, _actionlint.yml, issue.md, the two potential-folder records). The sibling regions of every edited citation (every CMD-POSHQC-TEST consumer, every CMD-HYGIENE consumer, every Phase 2 restart rule, every count that depends on the 131 and 373 test populations, every reference to the removed P1-T13 and to the eight-path Write Set) were re-checked in the same pass. The enumeration is reproduced in the planner's handoff message. + +PLANNER-INTERNAL-REVIEW: PASS +CITATION-TO-TREE: PASS +AC-TRACEABILITY: PASS +SCOPE-BOUNDARY: PASS +CITATION: QuickFiler.Test/QuickFiler.Test.csproj | lines 8 and 537 altcover imports, 570 lines (post-merge) +CITATION: SVGControl/app.config | lines 15 and 19, four dependentAssembly blocks +CITATION: SVGControl/SVGControl.csproj | lines 58, 59, 82, 83 +CITATION: SVGControl/packages.config | lines 4 and 10 +CITATION: scripts/dependencies/Repair-PackageManifestConsistency.ps1 | lines 177, 411-422, 425, 443-446 +CITATION: scripts/dependencies/ProjectConsistency.psm1 | Invoke-BindingRedirectReconciliation 271-375, exports 377-381 +CITATION: scripts/dependencies/ConsistencyVerifier.psm1 | Find-PackageAbsentFromManifest 215-250, comment 221-223, 499 lines +CITATION: scripts/dependencies/AnalyzerItemRepair.psm1 | FolderBearingKind line 70, Get-FolderPackageIdentity 95-126 +CITATION: tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 | lines 3-5, 7-10, 57-71, 214-239, 272-290, 12 It blocks, 312 lines +CITATION: tests/scripts/dependencies | 7 test files, 131 It blocks (13, 17, 32, 8, 12, 31, 18) +CITATION: scripts/dependencies | 6 production files (Repair-PackageManifestConsistency.ps1 475, ProjectConsistency.psm1 381, PackageCompatibility.psm1 172, PackageGraph.psm1 465, AnalyzerItemRepair.psm1 402, ConsistencyVerifier.psm1 499 lines) +CITATION: tests/scripts/dependencies/DependabotConfig.Tests.ps1 | Get-WorkflowStepBlock 156-178, AC26 test 323-345, 17 It blocks +CITATION: .github/workflows/dependabot-repair.yml | lines 13-14, 49, 51 +CITATION: .github/workflows/README.md | line 116 (table at 114-117) +CITATION: .github/workflows/_actionlint.yml | line 26 +CITATION: .github/workflows/_pester.yml | lines 41, 45, 47, 51, 53-61, 64, 71, 74-80 +CITATION: .github/workflows/_build-analyzers.yml | line 41 "No restore-keys fallback (issue #936)" +CITATION: .github/workflows/_build-nullable.yml | line 41 "No restore-keys fallback (issue #936)" +CITATION: .github/workflows/ci.yml | line 1 name CI, lines 3-8 triggers, lines 13-15 concurrency group keyed on the ref with cancel-in-progress true, lines 33-38 pester and hygiene jobs +CITATION: .claude/hooks/enforce-pr-author-skill-helpers.ps1 | line 279 Test-CommandLineInvocation gh pr create (identical in the worktree and the session checkout) +CITATION: .claude/hooks/hook-command-invocation.ps1 | lines 92-116 Test-CommandLineRawContainment, lines 202-203 wrapper-led segment routing +CITATION: artifacts/pester/powershell-coverage.koverage.xml | present on 2026-09-30, report root element (ignored at .gitignore 57) +CITATION: coverage/.gitkeep | tracked, so the coverage directory exists before the P0-T10 file logger writes +CITATION: .github/workflows/_hygiene.yml | lines 22-24 +CITATION: scripts/hygiene/Test-RepositoryHygiene.ps1 | lines 35, 51-56, 67-70, 73-75, 83-87 +CITATION: scripts/hygiene/Test-RepositoryHygiene.Rules.ps1 | line 21 pattern, lines 88-122 classifier +CITATION: scripts/hygiene/Test-RepositoryHygiene.Git.ps1 | line 70 ls-files, line 124 worktree read +CITATION: tests/scripts/hygiene | 3 files, 31 It blocks +CITATION: tests/scripts/vscode | 20 files, 211 It blocks +CITATION: artifacts/pester/pester-junit.xml | present on 2026-09-30 (ignored at .gitignore 57); root tests=131 failures=0; 7 testsuite elements with absolute-path name, tests, failures and skipped attributes; ConsistencyVerifier.Tests.ps1 tests=12, DependabotConfig.Tests.ps1 tests=17 +CITATION: .git/worktrees/agent-a74dcedbc13b789fd/logs/HEAD | line 8 merge origin/main 14177b8cf to 3091b8af9; loose refs origin/main 231e1c0b5, branch 3091b8af9 +CITATION: docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md | lines 99, 101-106, 129-132, 149-156, 301, 318 +CITATION: docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/spec.md | lines 506, 512, 520 AC18-AC20 checkboxes +CITATION: docs/features/potential/promoted/2026-09-28-package-manifest-consistency-residuals.md | promoted record carried by the promotion commit, outside the Write Set +CITATION: scripts/dev-tools/run-actionlint.ps1 | lines 5 and 11 +CITATION: scripts/vscode/Invoke-MSTestWithCoverage.ps1 | 461 lines; lines 297-298, 313, 344-346, 373, 375, 410, 415-423, 430-447, 456, 459-461 +CITATION: scripts/vscode/Invoke-MSTestWithCoverage.Scope.ps1 | lines 3-8 (issue 928; dot-sourced by the runner) +CITATION: scripts/vscode/Invoke-MSTestWithCoverage.FirstParty.ps1 | line 120 +CITATION: scripts/vscode/Invoke-MSTestWithCoverage.Threshold.ps1 | lines 54 and 124 +CITATION: scripts/vscode/Invoke-VSBuild.ps1 | lines 245, 250-253 +CITATION: scripts/vscode/Invoke-Restore.ps1 | lines 1-10, 101 +CITATION: scripts/vscode/Install-RepoDotNetSdk.ps1 | lines 3 and 36 +CITATION: global.json | lines 3 and 7 +CITATION: .csharpierignore | lines 4, 12, 16, 18 +CITATION: .gitattributes | line 4 `* text=auto` (line 9 the issue-400 whitespace rule; every other attribute line commented) +CITATION: .gitignore | lines 57 artifacts/, 147 *cobertura*.xml, 150 coverage/*, 197 **/[Pp]ackages/*, 356 .dotnet*/ +CITATION: .claude/rules/powershell.md | Testing Standards 85 percent line floor +CITATION: docs/features/potential/2026-08-04-stale-fizzler-and-unsafe-binding-redirects.md | Summary and Steps 1-4 +CITATION: docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/issue.md | line 12 work mode, lines 44-50 AC1-AC7 with the amended AC7 at line 50 +AC-INVENTORY: AC1, AC2, AC3, AC4, AC5, AC6, AC7 +AC-MAPPING: AC1 | IMPLEMENTATION: P1-T4 | TESTS: RepositoryTreeConsistency.Tests.ps1 test 1 via P1-T2 and P1-T11 | EVIDENCE: p1-t4-altcover-imports-removed and p2-t12-ac1-checkoff +AC-MAPPING: AC2 | IMPLEMENTATION: P1-T5 | TESTS: RepositoryTreeConsistency.Tests.ps1 test 2 via P1-T2 and P1-T11 | EVIDENCE: p0-t18-redirect-prefix, p1-t5-redirects-fixed and p2-t13-ac2-checkoff +AC-MAPPING: AC3 | IMPLEMENTATION: P1-T5 | TESTS: RepositoryTreeConsistency.Tests.ps1 test 2 via P1-T2 and P1-T11 | EVIDENCE: p0-t18-redirect-prefix, p1-t5-redirects-fixed and p2-t14-ac3-checkoff +AC-MAPPING: AC4 | IMPLEMENTATION: P1-T1 and P1-T3 | TESTS: ConsistencyVerifier.Tests.ps1 Import-kind tests via P1-T3 and RepositoryTreeConsistency.Tests.ps1 test 1 via P1-T2 and P1-T11 | EVIDENCE: p1-t3-verifier-import-tests, p1-t12-verifier-postfix, p2-t3-pester and p2-t15-ac4-checkoff +AC-MAPPING: AC5 | IMPLEMENTATION: P1-T6 | TESTS: RepositoryTreeConsistency.Tests.ps1 test 3 via P1-T11 and DependabotConfig.Tests.ps1 via P1-T7 | EVIDENCE: p1-t6-workflow-client-id, p1-t7-actionlint and p2-t16-ac5-checkoff +AC-MAPPING: AC6 | IMPLEMENTATION: P1-T8 and P1-T9 | TESTS: RepositoryTreeConsistency.Tests.ps1 test 4 via P1-T11 | EVIDENCE: p1-t8-runbook-client-id, p1-t9-readme-client-id and p2-t17-ac6-checkoff +AC-MAPPING: AC7 | IMPLEMENTATION: P0-T5, P0-T6 and P2-T1 to P2-T7 | TESTS: full PowerShell and C# toolchain runs P2-T1 to P2-T7 | EVIDENCE: p0-t5-package-restore, p0-t6-analyzer-item-census, p2-t8-attestation-and-coverage-delta, p2-t10-change-footprint and p2-t18-ac7-checkoff +UNRESOLVED-GAPS: NONE + +The record above ends at the gaps declaration and carries no handoff signal: executor preflight clearance is recorded by the orchestrator in its checkpoint, not in this file, because automation searches plan text for the signal strings. diff --git a/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/policy-audit.2026-09-30T10-30.md b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/policy-audit.2026-09-30T10-30.md new file mode 100644 index 000000000..01cf29312 --- /dev/null +++ b/docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/policy-audit.2026-09-30T10-30.md @@ -0,0 +1,296 @@ +# Policy Audit — package-manifest-consistency-residuals (Issue #929) + +- Artifact timestamp label: 2026-09-30T10-30 (assigned by the calling orchestrator; see Template Resolution Deviation, item 4) +- Reviewer: feature-review agent (reduced audit, work mode `minor-audit`) +- Branch: `bug/package-manifest-consistency-residuals-929` +- Branch head at review: `5ce3c8c3b585df9f8e724d4a740ee94c2df1ad1a` (read from the worktree's git ref) +- Base for the source diff: `231e1c0b55105aeb626bf5a6e8d0266a567cacad` (origin/main at the first merge, 3091b8af9; recorded by P0-T1 as BASE-SHA) +- Item commits: `488492f13` (phase 0 evidence), `b96926588` (implementation), `9e41ffbcf` (final QC evidence and check-off), `d9f50955d` (handoff index); second merge of origin/main `5ce3c8c3b` touched no file in this item's scope (caller statement, not re-derived here) +- Review worktree: `/.claude/worktrees/agent-a74dcedbc13b789fd` +- Feature folder: `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/` +- Total blocking findings: **0** +- Total non-blocking findings: **12** +- Verdict: **PASS** (no remediation required) + +## Template Resolution Deviation + +1. The MCP tools `mcp__drm-copilot__resolve_policy_audit_template_asset` and `mcp__drm-copilot__validate_orchestration_artifacts` are not in this session's tool set. This artifact is hand-authored and preserves the thirteen canonical headings listed in `.claude/skills/policy-audit-template-usage/SKILL.md` section 5 verbatim. +2. The caller's binding tool constraint forbids the Bash tool for this review. Every fact below was established with Read, Grep and Glob against the worktree, the executor's committed evidence, and the gitignored tool documents the executor left under `coverage/` and `artifacts/`. No command was executed by the reviewer; no coverage was regenerated (the review contract requires artifact inspection, not regeneration). +3. `artifacts/pr_context.summary.txt` and `artifacts/pr_context.appendix.txt` do not exist in the review worktree, and the copy in the session checkout belongs to a different branch (`bug/stale-analyzer-include-paths`, head `7ef8941e2`, generated 2026-09-29 15:21:41 UTC). Regeneration needs the PR-context MCP tool or `git`, neither of which is available under the tool constraint. Scope was therefore derived from three independent sources that agree: the caller's pasted diff, the executor's anchored name-only diff at P2-T10 (`git diff --name-only 481b33c59 -- .`), and on-disk verification of every named file. +4. No clock is available without Bash. The timestamp label `2026-09-30T10-30` was supplied by the caller; it sorts earlier than several executor evidence labels (the handoff index is labelled `11-22`), which is a property of caller-assigned labels and not a claim about ordering. See Finding NB-1 on the executor labels themselves. + +## Rejected Scope Narrowing + +None detected. The caller's directive restricts the acceptance-criteria source to the `## Acceptance Criteria` section of `issue.md`, which is the legitimate `minor-audit` rule, and states that Summary item 4 (the maintainer credential follow-up) is not an acceptance criterion, which `issue.md` line 52 itself states. The caller's pasted diff omits the feature folder, the promoted record and the new test file, but names all three as present in the branch diff; all three were audited from disk (Section 9 lists them). The audit scope is the full branch diff against the resolved base. + +## Evidence Location Compliance + +- Branch diff scanned (P2-T10 anchored name-only diff, 46 paths, plus the untracked porcelain capture): zero paths under `artifacts/baselines/`, `artifacts/qa/`, `artifacts/evidence/` or `artifacts/coverage/`. Every evidence artifact lies under `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/evidence/{baseline,regression-testing,qa-gates,other}/`. **PASS** +- `validate_evidence_locations.py` is not present in this checkout (Glob `**/validate_evidence_locations.py` returned nothing) and could not have been executed under the tool constraint; the scan above was performed by reading the P2-T10 footprint and the feature-folder Glob listing (69 files). +- Committed test evidence form (CLAUDE.md "Committed Test Evidence Format"): the four coverage copies are two package-level JaCoCo projections (9 `` elements each, no `class`, `sourcefile`, `method` or `line` element) and two trx-derived summaries. No raw Cobertura, raw trx, raw Pester JaCoCo or PoshQC JUnit document is tracked. **PASS** +- `EVIDENCE_LOCATION_OVERRIDE_REJECTED`: none; the caller supplied no non-canonical evidence path. + +## Executive Summary + +The change removes two `Exists()`-guarded `altcover` `` elements from `QuickFiler.Test/QuickFiler.Test.csproj`, corrects two stale binding redirects in `SVGControl/app.config` (Fizzler 1.3.1.0, System.Runtime.CompilerServices.Unsafe 6.0.3.0), switches `.github/workflows/dependabot-repair.yml` from the deprecated `app-id` input to `client-id`, aligns the 911 runbook and the workflows README with that input, updates a three-line comment in `scripts/dependencies/ConsistencyVerifier.psm1`, adds two in-memory Import-kind tests to `ConsistencyVerifier.Tests.ps1`, and adds a four-test tree-reading regression file `RepositoryTreeConsistency.Tests.ps1`. No C# source file changes. + +Every policy gate evaluated PASS. C# toolchain (CSharpier check, analyzer rebuild, nullable rebuild, MSTest with coverage) and PowerShell toolchain (PoshQC format, analyze, test; coverage read from the CI Pester job) passed on the final iteration with no regression against the Phase 0 baseline. Repo-wide line coverage: C# 85.92% (85.91% baseline), PowerShell 94.51% (94.51% baseline). The only modified PowerShell production file changed comment lines only and holds 158/160 lines covered in both CI documents, with the same two uncovered lines before and after. + +Twelve non-blocking findings are recorded in Section 8; none requires remediation before merge. The CI `mstest-coverage` failure on run 36722780748 is assessed as not attributable to this change (Section 6). + +## 1. General Unit Test Policy Compliance + +### 1.1 Core Principles + +| Principle | Verdict | Evidence | +|---|---|---| +| Independence | PASS | The six new `It` blocks share no mutable state; the tree tests read tracked files by absolute path resolved from `$PSScriptRoot` (`RepositoryTreeConsistency.Tests.ps1` lines 4, 10-11); fixtures in `ConsistencyVerifier.Tests.ps1` are script-scoped here-strings (lines 60-78). | +| Isolation | PASS | Each `It` targets one detector call or one repository invariant; failure messages name the offending element (line 89 lists each `Import` as `: line `). | +| Fast execution | PASS | Local PoshQC run over `tests/scripts/dependencies`: RUN-START 13:46:37Z, JUNIT-WRITTEN 13:47:26Z for 137 tests (P2-T3 iter2). | +| Determinism | PASS | No `Start-Sleep`, retry, wall-clock read or randomness in either test file (Grep for `Start-Sleep` returned nothing). Fail-before (4 of 4 red, P1-T2) and pass-after (4 of 4 green, P1-T11) reproduce deterministically; the intermediate state at P1-T7 (3 green, 1 red) matches the plan's decision D13 exactly. | +| Readability | PASS | Arrange/Act/Assert comments in every new `It`; every `Should` carries `-Because` text. | + +### 1.2 Coverage + +Coverage languages with changed files on this branch: PowerShell (`scripts/dependencies/ConsistencyVerifier.psm1` comment-only; `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1`; `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1`) and C# build configuration (`QuickFiler.Test/QuickFiler.Test.csproj`; zero `.cs` files). TypeScript and Python have zero changed files. + +### Coverage Evidence Checklist + +- C# baseline coverage artifact: `evidence/baseline/p0-t12-coverage-projection.2026-09-28T20-01.jacoco.xml` (package-level projection; LINE covered sum 56475 of 65736) with `evidence/baseline/p0-t12-test-results.2026-09-28T20-01.summary.txt` +- C# post-change coverage artifact: `evidence/qa-gates/p2-t7-coverage-projection.2026-09-28T20-01.jacoco.xml` (package-level projection; LINE covered sum 56479 of 65736) with `evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt`; the raw post-processed document survives gitignored at `coverage/coverage.cobertura.xml` (root `line-rate="0.859179" branch-rate="0.800809" lines-covered="56479" lines-valid="65736" branches-covered="13657" branches-valid="17054" timestamp="1790776305"`) +- TypeScript baseline coverage artifact: `N/A - out of scope` +- TypeScript post-change coverage artifact: `N/A - out of scope` +- PowerShell baseline coverage artifact: CI Pester job 109731601928 of run 36666302259 (main, head `231e1c0b5`), JaCoCo document downloaded gitignored at `coverage/ci-main-pester-36666302259-1/pester-coverage.xml` (report name `Pester (09/30/2026 03:53:09)`, report-level LINE covered 1721 missed 100), transcribed in `evidence/baseline/p0-t16-pester.2026-09-28T20-01.md` +- PowerShell post-change coverage artifact: CI Pester job 109911885533 of run 36722780748 (branch, head `b96926588`), JaCoCo document downloaded gitignored at `coverage/ci-branch-pester-36722780748-2/pester-coverage.xml` (report name `Pester (09/30/2026 13:37:22)`, report-level LINE covered 1721 missed 100), transcribed in `evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md` +- Python baseline coverage artifact: `N/A - out of scope` +- Python post-change coverage artifact: `N/A - out of scope` +- Per-language comparison summary: section 1.2.1 of this document + +**Coverage Metrics by Language:** + +| Language | Files Changed | Tests | Test Result | Baseline Coverage | Post-Change Coverage | New Code Coverage | +|---|---|---|---|---|---|---| +| C# | 1 (`QuickFiler.Test.csproj`; 0 `.cs`) | 7346 MSTest | 7346 passed, 0 failed (iteration 2) | 85.91% lines / 80.08% branches | 85.92% lines / 80.08% branches | N/A - no C# source line added or changed | +| PowerShell | 3 (1 production comment-only, 2 test files) | 137 local (PoshQC, `tests/scripts/dependencies`) / 379 CI | 137 passed, 0 failed local; 379 passed, 0 failed CI | 94.51% lines | 94.51% lines | 98.75% | +| TypeScript | 0 | N/A | N/A | N/A | N/A | N/A | +| Python | 0 | N/A | N/A | N/A | N/A | N/A | + +### 1.2.1 Per-Language Coverage Comparison + +- C#: Baseline: 85.91% lines (56475/65736) / 80.08% branches (13656/17054) -> Post-change: 85.92% lines (56479/65736) / 80.08% branches (13657/17054). Change: +0.01% lines (+4 covered, all in the untouched UtilitiesCS package) / 0.00% branches (+1 covered). Disposition: PASS. Evidence: the two committed projections reconcile to the printed first-party lines (P0-T12 and P2-T7 iter2); the raw Cobertura root counters match the projection sums; the delta lies entirely in an assembly this change does not touch and is within the known run-to-run band of the C# coverage constants; repo-wide line 85.92% is at or above both the 85% rules floor and the 80% CLAUDE.md floor and branch 80.08% is above the 75% floor; C# coverage verdict: PASS. +- PowerShell: Baseline: 94.51% lines (1721/1821). Post-change: 94.51% lines (1721/1821). Change: 0.00% lines (0 covered, 0 missed). New/changed-code coverage: 98.75%. Disposition: PASS. Evidence: CI Pester jobs 109731601928 (main) and 109911885533 (branch) both print `COVERAGE LinePercent=94.51 Covered=1721 Total=1821`; the only modified production file `dependencies/ConsistencyVerifier.psm1` reads LINE covered 158 missed 2 in both JaCoCo documents (98.75%), the two uncovered source lines are 430 and 475 in both documents (JaCoCo rows 495 and 525 inside the sourcefile block at rows 374-536), and the three changed lines 221-223 are comment-based-help lines that carry no JaCoCo line node, so zero executable production lines changed and no changed-line regression is possible; the 98.75% figure is that file's post-change line coverage, reported because no smaller changed-line population exists; the new files are test files and are outside the denominator by policy; Pester coverage verdict: PASS; Pester reports line and command coverage only, so the branch threshold does not apply to this language and no branch figure is claimed. +- TypeScript: Baseline: N/A. Post-change: N/A. Change: N/A. Disposition: N/A. Evidence: N/A - zero TypeScript files changed on this branch. +- Python: Baseline: N/A. Post-change: N/A. Change: N/A. Disposition: N/A. Evidence: N/A - zero Python files changed on this branch. + +### 1.2.2 Coverage Artifact State + +| Language | Canonical artifact path | State in review worktree | Disposition | +|---|---|---|---| +| C# | `artifacts/csharp/coverage.xml` | absent (gitignored path; the executor's runner writes `coverage/coverage.cobertura.xml`, present, and the committed projection stands in per the feature-evidence rule) | PASS on the committed projection and the raw Cobertura root counters | +| PowerShell | `artifacts/pester/powershell-coverage.xml` | present, written by the bundled PoshQC route at local time 09:47:03 on 2026-09-30; report-level LINE `missed="9294" covered="0"`; every `` it instruments lies under `.claude/hooks`, never under `scripts/` | Pester coverage on that document: FAIL (0.00%), a known limitation of the bundled route recorded at issue 928 (P-4) and pre-existing; it is not the measurement of record and is non-blocking | +| PowerShell (measurement of record) | CI `pester-coverage` artifact, run 36722780748 | present gitignored at `coverage/ci-branch-pester-36722780748-2/pester-coverage.xml` | PASS (94.51%) | + +Documentation conflict, recorded and not re-raised: CLAUDE.md states an 80% line floor and a 90% new-module target; `.claude/rules/general-unit-test.md`, `.claude/rules/quality-tiers.md` and `.claude/rules/powershell.md` state 85% line / 75% branch uniformly. Every figure above satisfies both sets. The conflict is tracked as open issue 668 (plan convention 10). + +### 1.3 Scenario Completeness, Structure, External Dependencies, Location + +| Check | Verdict | Evidence | +|---|---|---| +| Positive and negative flows for the AC4 detector | PASS | `ConsistencyVerifier.Tests.ps1` lines 240-251 (two guarded Imports of an unmanifested package: FindingCount 2, every Kind `Import`, every PackageFolder `altcover.8.6.45`) and lines 253-263 (manifest declares the imported package: Import-kind subset empty, ExaminedCount greater than 0). | +| Regression coverage of the three fixes | PASS | `RepositoryTreeConsistency.Tests.ps1` tests 1-4 red before the fix (P1-T2, messages quote `QuickFiler.Test.csproj` / `altcover.8.6.45`, `1.3.0.0` versus `1.3.1.0`, `client-id`, secret name) and green after (P1-T11). | +| Arrange-Act-Assert | PASS | Every new `It` is sectioned with the three comments. | +| Clear failure messages | PASS | Every `Should` carries `-Because`; test 1 concatenates every offending Import into the message. | +| No external services, no temporary files | PASS | Grep over both test files for `Out-File`, `Set-Content`, `Add-Content`, `New-Item`, `New-TemporaryFile`, `[System.IO.File]::Write*`, `Remove-Item`: no match. Reads are `ReadAllText` / `ReadAllLines` on tracked files. | +| No banned timing APIs | PASS | Grep for `Start-Sleep`: no match. | +| Test file location mirrors production | PASS | `tests/scripts/dependencies/` mirrors `scripts/dependencies/`, the existing convention of the seven sibling `*.Tests.ps1` files. | +| Test names avoid `AC` | PASS | Both files state the rule in their header (lines 7-9) and no `It` name matches it (P1-T3 count 0; confirmed by reading every `It` line). | + +## 2. General Code Change Policy Compliance + +| Requirement | Verdict | Evidence | +|---|---|---| +| Bugfix workflow: failing regression test first, minimal fix, verify | PASS | P1-T1/P1-T2 authored and ran the tree tests red (4 of 4) before P1-T4 to P1-T9 applied the fixes; P1-T11 ran them green; P2 loop ran the toolchain twice (iteration 1 failed at P2-T7 on a pre-existing timing test, iteration 2 passed all seven steps on the unchanged tree). | +| Simplicity, no opportunistic refactor | PASS | Decision D1: the detector already reported Import-kind absences; no production rule was added. The production diff to `ConsistencyVerifier.psm1` is three comment lines for three (499 lines before and after). | +| Reusability | PASS | The new test file reuses the step-block parsing approach of `DependabotConfig.Tests.ps1` (lines 14-21 say so) rather than a new framework. | +| Separation of concerns | PASS | The pure detector `Find-PackageAbsentFromManifest` is exercised with in-memory strings; the tree test isolates file reads to the Arrange step. | +| File size limit (500 lines) | PASS | P2-T9: `QuickFiler.Test.csproj` 568 (XML project file, not code; was 570), `app.config` 23, `dependabot-repair.yml` 173, `ConsistencyVerifier.psm1` 499, `ConsistencyVerifier.Tests.ps1` 337, `RepositoryTreeConsistency.Tests.ps1` 152 (Read shows 153 with the trailing newline). Test files count toward the limit and both are under it. | +| Error handling / logging | PASS | No production logic changed. | +| Naming | PASS | `Get-TokenStepBlock`, `Get-DependentAssemblyBlock` use approved verbs and descriptive nouns; PoshQC analyze reported ok (P2-T2 iter2). | +| Public API compatibility | PASS | No exported function signature changed; `Find-PackageAbsentFromManifest` parameters unchanged (lines 229-234). | +| Dependencies | PASS | No library added. | +| Toolchain loop restart rule | PASS | Iteration 1 P2-T7 failure restarted the loop at P2-T1 (iter2 artifacts for all seven steps). | +| Supporting documents updated | PASS | Runbook (steps 10, 22, YAML sample), workflows README line 116, workflow header comment lines 13-14, verifier comment lines 221-223, fixture comments in the test file. | + +## 3. Language-Specific Code Change Policy Compliance + +### 3.1 PowerShell (`.claude/rules/powershell.md`) + +| Requirement | Verdict | Evidence | +|---|---|---| +| Format via PoshQC MCP | PASS | P2-T1 iter2: 14 hashes identical before and after; rewrite count 0. | +| Analyze via PoshQC MCP | PASS | P2-T2 iter2: `PoshQC analyze: pass (0 findings); tool reports no count` (the ruling's required wording). | +| Test via PoshQC MCP | PASS | P2-T3 iter2: JUnit root tests=137 failures=0. | +| PowerShell 7+ compatibility | PASS | No PS5-only construct; `[System.Collections.Generic.List[object]]::new()` and `-LiteralPath` are 7-safe. | +| Advanced-function conventions in production code | PASS | No production function changed. | +| Change budget (2 production files direct-mode) | PASS | One production file, comment-only. | +| Coverage regression on changed lines | PASS | Zero executable lines changed (Section 1.2.1). | + +### 3.2 C# build configuration (CLAUDE.md C# Code Change Policy) + +| Requirement | Verdict | Evidence | +|---|---|---| +| CSharpier check via `dotnet tool run` | PASS | P2-T4 iter2: `Checked 1625 files`, exit 0, no findings, equal to P0-T9. `.csproj` and `app.config` are excluded by `.csharpierignore` and were not touched by the formatter. | +| Analyzer rebuild (`/t:Rebuild`, `EnableNETAnalyzers`, `EnforceCodeStyleInBuild`) | PASS | P2-T5 iter2: `Build succeeded.`, 0 warnings, 0 errors, MSBUILD_EXIT=0, CS0006_LINES=0, OUT_LINES 36 equal to P0-T10. | +| Nullable rebuild (`/t:Rebuild`, `TreatWarningsAsErrors`, no `/p:Nullable=enable`) | PASS | P2-T6 iter2: `Build succeeded.`, 0 warnings, 0 errors, MSBUILD_EXIT=0, OUT_LINES 36 equal to P0-T11. Command text matches CLAUDE.md character-for-character. | +| MSTest with coverage via `Invoke-MSTestWithCoverage.ps1` | PASS | P2-T7 iter2: 7346 of 7346 passed; first-party 85.92% lines / 80.08% branches. | +| No `dotnet format`, no `Invoke-VSBuild.ps1` wrapper | PASS | Command records in P2-T4 to P2-T6 name the literal commands (plan convention 7). | + +### 3.3 CI workflow authoring (`.claude/rules/ci-workflows.md`) + +| Requirement | Verdict | Evidence | +|---|---|---| +| Deliberately-failing nested command pattern | PASS (no `run:` block changed, so the pattern is not engaged) | The change replaces `app-id:` with `client-id:` at line 51 inside a `uses:` step; no `run:` block changed. | +| actionlint | PASS | P1-T7: actionlint 1.7.7, scoped run and repository-wide run both exit 0 with no output; CI `actionlint` job on run 36722780748 succeeded. | +| Modified workflow needs a green run | PARTIAL, non-blocking (Finding NB-3) | `dependabot-repair.yml` is `workflow_run`-triggered and its first step mints an App token from secrets the maintainer has not yet provisioned (issue Summary item 4, deliberately not a merge gate). No run of this workflow can be green on any branch until then; the static lint and the Pester static test cover the changed line. | + +## 4. Language-Specific Unit Test Policy Compliance + +### 4.1 PowerShell / Pester + +| Requirement | Verdict | Evidence | +|---|---|---| +| Pester v5 `Describe`/`Context`/`It` | PASS | `Describe 'Repository tree consistency (issue 929)'` with four `It`; two `It` added under `Context 'Package absent from the manifest'`. | +| One behavior per `It` | PASS with a note (NB-7) | Test 2 iterates two assemblies inside one `It`; a Fizzler failure would mask the Unsafe assertion. Test 1 is a deliberate census and reports every offending Import in one message. | +| `*.Tests.ps1` naming and mirrored layout | PASS | `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1`. | +| Mock sparingly, no executable mocks | PASS | No `Mock` in either file. | +| No PATH / cwd / profile reliance | PASS | Paths resolve from `$PSScriptRoot`; `Set-StrictMode -Version Latest` at the top of both files. | +| Line coverage at or above 85% | PASS | 94.51% aggregate; 98.75% for the modified module. | + +### 4.2 C# / MSTest + +No C# test source changed. The existing suite (MSTest, Moq, FluentAssertions) ran 7346 of 7346 green on the final local iteration (P2-T7 iter2), equal to the Phase 0 baseline (P0-T12). **PASS** + +## 5. Test Coverage Detail + +| File | Kind | Baseline | Post-change | Threshold | Verdict | +|---|---|---|---|---|---| +| `scripts/dependencies/ConsistencyVerifier.psm1` | modified production (comment lines 221-223 only) | 158/160 lines (98.75%), uncovered source lines 430 and 475 | 158/160 lines (98.75%), uncovered source lines 430 and 475 | 85% line; no changed-line regression | PASS | +| `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1` | modified test | outside denominator | outside denominator | none | PASS | +| `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | new test | outside denominator | outside denominator | none | PASS | +| `QuickFiler.Test/QuickFiler.Test.csproj` | modified build configuration | no executable lines | no executable lines | none | PASS | +| `SVGControl/app.config` | modified runtime configuration | no executable lines | no executable lines | none | PASS | +| `.github/workflows/dependabot-repair.yml` | modified workflow | no coverage tooling | no coverage tooling | actionlint + green run (Section 3.3) | PASS / PARTIAL non-blocking | + +The two uncovered lines in `ConsistencyVerifier.psm1` are line 430 (`else { @() }`, the empty-manifest arm of `$package`) and line 475 (the `ResidualVersionDisagreement` failure construction), both pre-existing and unchanged. The `dependencies` package-level LINE counter reads missed 16 covered 777 in both CI documents. + +Repo-wide C# by package (post-change projection): QuickFiler 10461/12754 lines, UtilitiesCS 39210/43423, TaskVisualization 1426/1569, SVGControl 877/1854, ToDoModel 1061/1823, Tags 702/758, TaskMaster 2443/3245, TaskTree 295/306, VBFunctions 4/4. SVGControl (the project whose `app.config` changed) is unchanged at 877/1854 lines and 300/638 branches between the two projections, which is consistent with a configuration-only change to that project. + +## 6. Test Execution Metrics + +| Run | Scope | Result | Source | +|---|---|---|---| +| P0-T12 baseline MSTest | 7346 | 7346 passed, 0 failed | `evidence/baseline/p0-t12-test-results.2026-09-28T20-01.summary.txt` | +| P2-T7 iteration 1 MSTest | 7346 | 7345 passed, 1 failed (`RemainingLoadActive_AcrossAsyncVoidFirstAwait_StaysTrueWhileLoaderProduces`, `QuickFiler.Test/Controllers/QfcDatamodelLivenessTests.cs` line 189; a five-second `Task.Wait` that did not complete) | `evidence/qa-gates/p2-t7-mstest-coverage.iter1.2026-09-28T20-01.md` | +| P2-T7 iteration 2 MSTest | 7346 | 7346 passed, 0 failed | `evidence/qa-gates/p2-t7-test-results.2026-09-28T20-01.summary.txt` | +| P0-T15 baseline PoshQC test | `tests/scripts/dependencies` | 131 passed, 0 failed | `evidence/baseline/p0-t15-poshqc-test-mcp.2026-09-28T20-01.md` | +| P1-T2 fail-before | same | 135 tests, 4 failed (all four tree tests) | `evidence/regression-testing/p1-t2-tree-test-fail-before.2026-09-28T20-01.md` | +| P1-T3 after adding the two Import tests | same | 137 tests, 4 failed (tree tests; the two new verifier tests green) | `evidence/regression-testing/p1-t3-verifier-import-tests.2026-09-28T20-01.md` | +| P1-T7 intermediate | same | 137 tests, 1 failed (runbook test, before P1-T8) | `evidence/qa-gates/p1-t7-actionlint.2026-09-28T20-01.md` | +| P1-T11 pass-after and P2-T3 iter2 | same | 137 passed, 0 failed | `evidence/regression-testing/p1-t11-tree-test-pass-after.2026-09-28T20-01.md`, `evidence/qa-gates/p2-t3-pester.iter2.2026-09-28T20-01.md` | +| CI run 36666302259 (main, `231e1c0b5`) Pester job | 373 | 373 passed, 0 failed; 94.51% | P0-T16 | +| CI run 36722780748 (branch, `b96926588`) Pester job | 379 | 379 passed, 0 failed; 94.51% (373 + 6 new tests) | P2-T3 iter2 | +| CI run 36722780748 other jobs | build-analyzers, build-nullable, format-check, actionlint, hygiene | success | P2-T3 iter2 | +| CI run 36722780748 mstest-coverage | 7346 | 1 failed: `Transaction_SecondCallerCannotInstallUntilTheFirstRestores` (`QuickFiler.Test/Controllers/QfcItemController.UiThreadDispatcherFixtureTests.cs` line 206) | P2-T3 iter2 | + +Attribution of the two C# test failures: this change edits no `.cs` file. The only edit to the QuickFiler.Test project removes two `` elements guarded by `Exists()` on a package folder that a restore never creates (P0-T5 `ALTCOVER-RESTORED: False`; no manifest declares altcover, and CI carries no `restore-keys` cache fallback since issue 936), so the imports were inert and the compiled assembly is unchanged. Both tests passed in the local baseline and in local iteration 2 on the same tree; the two failures are on different tests on different hosts. Both are pre-existing timing-dependent tests outside the Write Set; the local one relies on a real five-second wall-clock wait, which the determinism rule bans in test code. The failures are assessed as not attributable to this change. The orchestrator's PR-time CI re-run remains the gate on the branch head, which CI has not yet built (Finding NB-11). + +## 7. Code Quality Checks + +| Check | Command / method | Result | +|---|---|---| +| Confidentiality masking scan | Grep over the feature folder and `tests/scripts/dependencies` for drive-letter paths, `Users` segments and the developer account name | Feature folder: 1 hit, plan line 209, which is the plan's own hygiene-pattern definition and not a path; tests: only the pre-existing synthetic fixture path literals (a fictitious drive letter and a `fixture` folder, no user or host segment) at lines 82-84 of `Repair-PackageManifestConsistency.Tests.ps1` (outside the diff). Executor CMD-HYGIENE: HITS=0 (P2-T11, P2-T21); CI hygiene guard local run: Findings=0, GUARD_EXIT=0 (P2-T21). PASS | +| Suppression scan (added lines) | Read of every added line in the diff | No `[SuppressMessage]`, `#pragma`, `[Diagnostics.CodeAnalysis.SuppressMessageAttribute]` or analyzer-disable comment added. PASS | +| Workflow change scan | Read of `.github/workflows/dependabot-repair.yml` in full and Grep for `app-id` under `.github/workflows` | One input rename at line 51 plus header comment lines 13-14; `app-id` absent from every workflow. Trigger, permissions, concurrency and `run:` blocks unchanged. PASS | +| actionlint | P1-T7 (local 1.7.7, exit 0 scoped and repository-wide); CI actionlint job success | PASS | +| PoshQC analyze | P2-T2 iter2 | pass (0 findings); tool reports no count. PASS | +| CSharpier check | P2-T4 iter2 | exit 0, 1625 files, no findings. PASS | +| Analyzer and nullable rebuilds | P2-T5 and P2-T6 iter2 | 0 warnings, 0 errors each. PASS | +| Hygiene of committed XML evidence | Read of both projections | root `report`, 9 `package` elements, no raw element. PASS | +| Coverage exclusion policy | Grep of the diff for `exclude` entries | No coverage configuration changed. PASS | + +## 8. Gaps and Exceptions + +All findings are non-blocking. Total blocking findings: 0. + +| ID | Class | Finding | Disposition | +|---|---|---|---| +| NB-1 | Evidence hygiene | Executor `Timestamp:` labels are not clock readings. Each local test artifact embeds the run's UTC clock: P1-T2 label `10-02` versus RUN-START `13:24:02Z` (09:24 local at UTC-4); P1-T11 label `10-17` versus `13:29:57Z`; P2-T3 iter2 label `10-58` versus `13:46:37Z`, corroborated by the bundled PoshQC coverage document's own report name `Pester (09/30/2026 09:47:03)`. The labels lead the clock by 38 to 72 minutes and drift monotonically. The gates demonstrably ran (JUNIT-WRITTEN follows RUN-START in every artifact; the CI run ids and head SHAs are third-party facts). | Non-blocking. The labels cannot be used to establish inter-gate ordering; ordering was taken from the plan's task sequence and the embedded clocks instead. | +| NB-2 | Pre-existing flaky tests | One local iteration-1 failure and one CI failure on two different QuickFiler.Test timing tests (Section 6). Not attributable to this change. | Non-blocking. Follow-up recommended: promote the wall-clock `Task.Wait(TimeSpan.FromSeconds(5))` pattern in `QfcDatamodelLivenessTests.cs` and the dispatcher-fixture concurrency test to an issue under the determinism rule. | +| NB-3 | Workflow green-run gate | `dependabot-repair.yml` cannot produce a green run until the maintainer provisions the App credential (issue Summary item 4, not a merge gate). actionlint and the static Pester test cover the changed line; the runtime token step is unexercised. | Non-blocking, procedural. The maintainer follow-up (P2-T19) already records that `DEPENDABOT_REPAIR_APP_ID` must hold the Client ID once provisioned. | +| NB-4 | Residue outside the AC pathspec | Eight tracked `*.csproj.bak` copies exist (P0-T1 BAK-TRACKED); `QuickFiler.Test/QuickFiler.Test.csproj.bak` and `QuickFiler/QuickFiler.csproj.bak` still carry the altcover token. MSBuild does not read `.bak` files, so AC1's project-file scope is satisfied. | Non-blocking. Follow-up recommended: delete the eight tracked `.bak` copies. | +| NB-5 | Stale citation wording | Runbook line 301 still reads "Private key generation and App ID location (steps 10-12)" although step 10 now records the Client ID. The instruction text (steps 10 and 22) and the YAML sample are correct. | Non-blocking, cosmetic. | +| NB-6 | Comment wrap | `dependabot-repair.yml` line 14 runs to roughly 150 characters; the surrounding header comment wraps near 100. | Non-blocking, cosmetic. | +| NB-7 | Test granularity | `RepositoryTreeConsistency.Tests.ps1` test 2 asserts two assemblies inside one `It`. | Non-blocking, style. | +| NB-8 | Documentation conflict | CLAUDE.md 80%/90% versus rules 85%/75% coverage floors. Both are met by every figure in this audit. Tracked as issue 668. | Recorded, not re-raised. | +| NB-9 | Canonical PowerShell artifact | `artifacts/pester/powershell-coverage.xml` from the bundled PoshQC route instruments only `.claude/hooks` and reads 0 of 9294 lines; it is not a measurement of `scripts/`. The CI JaCoCo document is the measurement of record. `artifacts/csharp/coverage.xml` is absent; the committed projection and `coverage/coverage.cobertura.xml` stand in. | Non-blocking, pre-existing tool limitation (issue 928 P-4). | +| NB-10 | Out-of-scope residual | Eleven other `app.config` files redirect Fizzler to 1.3.0.0 without a Fizzler `` to compare against (P0-T18). | Already recorded in `docs/features/potential/2026-08-04-stale-fizzler-and-unsafe-binding-redirects.md`; not widened here. | +| NB-11 | CI head lag | CI run 36722780748 built `b96926588` (the implementation commit). The branch head `5ce3c8c3b` adds the evidence commits `9e41ffbcf` and `d9f50955d` and the second origin/main merge. The source diff is unchanged between the two heads (caller statement; P2-T10 footprint shows only feature-folder paths after `b96926588`). | Non-blocking, procedural. The PR-time CI run will build the head. | +| NB-12 | PR context artifacts | Not present in the review worktree and not regenerable under the tool constraint (Template Resolution Deviation item 3). Scope was triangulated from three agreeing sources. | Non-blocking, procedural. | + +Exceptions claimed by the executor and accepted: `GATE-SUBSTITUTION` lines (PoshQC ok flag for the analyzer count; JUnit per-file counts for a direct Pester run; CI Pester job for a local coverage run) follow the coordinator's LOCAL POWERSHELL GATES ruling verbatim. + +## 9. Summary of Changes + +Source diff (`231e1c0b5` to `d9f50955d`), verified on disk: + +| Path | Change | Verified by | +|---|---|---| +| `QuickFiler.Test/QuickFiler.Test.csproj` | two `altcover` `` lines deleted (570 to 568) | Grep `altcover` over `*.csproj,*.config,*.props,*.targets`: 0 matches | +| `SVGControl/app.config` | lines 15 and 19: Fizzler 1.3.0.0 to 1.3.1.0; Unsafe 6.0.2.0 to 6.0.3.0 | Read; `SVGControl.csproj` lines 58 and 82 declare 1.3.1.0 and 6.0.3.0 | +| `.github/workflows/dependabot-repair.yml` | line 51 `app-id` to `client-id`; header comment lines 13-14 | Read in full | +| `.github/workflows/README.md` | line 116 secret description | Grep | +| `docs/features/active/2026-09-19-.../runbooks/github-app-installation-token.runbook.md` | Part B heading, steps 10 and 22, YAML sample line 154 | Read lines 96-159 | +| `scripts/dependencies/ConsistencyVerifier.psm1` | comment lines 221-223 (499 lines unchanged) | Read | +| `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1` | fixture comments; two `It` blocks (lines 240-263); 337 lines | Read | +| `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | new, 4 tests, 152 lines | Read in full | +| `docs/features/potential/promoted/2026-09-28-package-manifest-consistency-residuals.md` | promoted record (promotion commit) | present on disk | +| `docs/features/active/2026-09-28-package-manifest-consistency-residuals-929/` | issue.md (7 check-offs), plan (56 of 56 checked), 61 evidence `.md`, 2 projections, 2 summaries | Glob (69 files) | + +## 10. Compliance Verdict + +**PASS.** Zero blocking findings. Twelve non-blocking findings recorded in Section 8; none is a remediation trigger. No `remediation-inputs` artifact is produced. All seven acceptance criteria evaluate PASS in `feature-audit.2026-09-30T10-30.md`; the executor's check-offs stand. + +Assumptions made under the tool constraint: the branch head SHA was read from `/.git/refs/heads/bug/package-manifest-consistency-residuals-929`; commit contents and the second merge's footprint were not re-derived with git and are taken from the caller's statement and the P2-T10 footprint. + +## Appendix A: Test Inventory + +New and modified tests on this branch (6): + +| File | Test | Purpose | +|---|---|---| +| `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1` | `reports an Import whose package the manifest does not declare, with Kind Import` | AC4 positive: two guarded Imports of `altcover.8.6.45` against a manifest declaring only `Contoso.Widgets`; FindingCount 2, all Kind `Import` | +| `tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1` | `reports no Import finding when the manifest declares the imported package` | AC4 negative: agreeing project; Import-kind subset empty; ExaminedCount greater than 0 | +| `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | `reports no Import element whose package the sibling manifest omits, for every project directory that carries a manifest` | AC1 and AC4 tree census (more than 9 project directories; examined count guards the zero) | +| `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | `names in the SVGControl binding redirects the assembly version the SVGControl project reference declares` | AC2 and AC3 | +| `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | `passes client-id and not app-id to the create-github-app-token step of the repair workflow` | AC5 static | +| `tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1` | `instructs the maintainer to store the Client ID in the secret the repair workflow reads by name` | AC6; the secret name is extracted from the workflow and asserted in the runbook | + +Existing suites exercised: MSTest 7346 (unchanged); Pester CI population 379 (`tests/scripts/dependencies` 137, `tests/scripts/hygiene` 31, `tests/scripts/vscode` 211). + +## Appendix B: Toolchain Commands Reference + +Commands as recorded by the executor (not re-run by the reviewer): + +1. `dotnet tool run csharpier check .` (P0-T9, P2-T4 iter1/iter2) +2. `msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true` with a file logger under `coverage/` (P0-T10, P2-T5) +3. `msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true` with a file logger under `coverage/` (P0-T11, P2-T6) +4. `scripts/vscode/Invoke-MSTestWithCoverage.ps1 -SearchRoot .` (P0-T12, P2-T7) +5. `mcp__drm-copilot__run_poshqc_format` / `run_poshqc_analyze` with `scan_folders ["scripts/dependencies","tests/scripts/dependencies"]` (P0-T13/14, P2-T1/2) +6. `mcp__drm-copilot__run_poshqc_test` with `scan_folders ["tests/scripts/dependencies"]`, counts read from `artifacts/pester/pester-junit.xml` (P0-T15, P1-T2, P1-T3, P1-T7, P1-T11, P2-T3) +7. `gh run view --log` and `gh run download --name pester-coverage` for coverage (P0-T16 run 36666302259; P2-T3 run 36722780748) +8. `scripts/dev-tools/run-actionlint.ps1` and a scoped `actionlint-bin/actionlint.exe` invocation (P0-T19, P1-T7) +9. `scripts/dependencies/Repair-PackageManifestConsistency.ps1 -WhatIf` (P0-T17, P1-T12) +10. `scripts/vscode/Invoke-Restore.ps1` for the cold restore (P0-T5) +11. `scripts/hygiene/Test-RepositoryHygiene.ps1` (P2-T21) + +Reviewer's own verification method: Read, Grep and Glob only (caller constraint); no command executed. diff --git a/docs/features/potential/promoted/2026-09-28-package-manifest-consistency-residuals.md b/docs/features/potential/promoted/2026-09-28-package-manifest-consistency-residuals.md new file mode 100644 index 000000000..087e979ab --- /dev/null +++ b/docs/features/potential/promoted/2026-09-28-package-manifest-consistency-residuals.md @@ -0,0 +1,67 @@ +# package-manifest-consistency-residuals (Issue #929) + +- Date captured: 2026-09-28 +- Author: Dan Moisan +- Status: Promoted -> docs/features/active/package-manifest-consistency-residuals/ (Issue #929) + +> Automation note: Keep the section headings below unchanged; the promotion tooling maps each of them into the GitHub bug issue template. + +- Issue: #929 +- Issue URL: https://github.com/drmoisan/TaskMaster/issues/929 +- Last Updated: 2026-09-28 +## Summary +Consolidates #912 with the remaining parts of #914. PRs #920 and #921 fixed 8 of the 10 stale binding redirects and the `Invoke-ProjectConsistencyRepair` fallback defect. All remaining items break one invariant: a project's files and its own `packages.config` must agree, and the repair workflow that maintains them must be runnable. + +1. **#912:** `QuickFiler.Test/QuickFiler.Test.csproj` lines 8 and 535 import `altcover.8.6.45` build assets. No `packages.config` declares `altcover`, so the imports are silently skipped by their `Exists()` guard. +2. **#914 sub-item 3 residual:** two binding redirects in `SVGControl/app.config` are still stale: + - `Fizzler` redirects to 1.3.0.0, but the reference and the restored package are 1.3.1.0. + - `System.Runtime.CompilerServices.Unsafe` redirects to 6.0.2.0, but the reference and the restored package are 6.0.3.0. +3. **#914 comment item 1:** `.github/workflows/dependabot-repair.yml:51` passes the deprecated `app-id` input to `actions/create-github-app-token@v3`. It should pass `client-id`, and the runbook should say to store the App's Client ID. +4. **#914 sub-item 1 (verification only, requires the maintainer):** AC18, AC19 and AC20 of #911 can only be exercised after a GitHub App credential is provisioned. The runbook is at `docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md`. The secret store is also unconfirmed: a Dependabot-triggered `workflow_run` may read only Dependabot secrets. None of this is a merge gate for items 1 to 3. + +## Environment +- OS/version: Windows 11 Pro 10.0.26200 +- Python version: not applicable (.NET Framework 4.8.1 packages.config projects, GitHub Actions) +- Command/flags used: `nuget restore TaskMaster.sln` from cold; static inspection on `main` at `177b6d78e` +- Data source or fixture: `QuickFiler.Test/QuickFiler.Test.csproj`, `QuickFiler.Test/packages.config`, `SVGControl/app.config`, `SVGControl/packages.config`, `.github/workflows/dependabot-repair.yml` + +## Steps to Reproduce +1. `git grep -n altcover -- "*.csproj" "*packages.config"` finds two imports and no manifest entry. +2. Compare the `SVGControl/app.config` `bindingRedirect newVersion` values for `Fizzler` and `System.Runtime.CompilerServices.Unsafe` with the referenced assembly versions. +3. Read `dependabot-repair.yml:51`. + +## Expected Behavior +- Every `..\packages\` import corresponds to a manifest entry. +- Every binding redirect names the assembly version that actually ships. +- The repair workflow uses the non-deprecated input. + +## Actual Behavior +As listed in the Summary. + +## Logs / Screenshots +- [x] Attached minimal logs or snippet +- Snippet: run https://github.com/drmoisan/TaskMaster/actions/runs/36281113978 fails at `Mint an installation token` with the deprecation warning for `app-id` (see the #914 comment of 2026-09-26). + +## Impact / Severity +- [ ] Blocker +- [ ] High +- [x] Medium +- [ ] Low + +## Suspected Cause / Notes +- The altcover imports are left over from an evaluation whose manifest entry was removed. +- The #911 repair pass reconciles redirects only for packages it upgraded, so the pre-existing drift in `SVGControl` was left in place. + +## Proposed Fix / Validation Ideas +- [ ] Delete both altcover `` elements. AltCover is not used by the coverage route, which is `dotnet-coverage`. +- [ ] Correct the two `SVGControl/app.config` redirects, preferably by running `scripts/dependencies/Repair-PackageManifestConsistency.ps1` rather than editing by hand. +- [ ] Switch `app-id` to `client-id` in the workflow, update the runbook, and confirm with actionlint. +- [ ] Add a verifier test case to the #911 consistency verifier that detects "an import whose package is absent from the manifest". Use the altcover case as the fixture shape, held in memory without temporary files. +- [ ] Rebuild the solution after a cold restore to confirm it still succeeds. +- [ ] Record AC18 to AC20 as deferred to the maintainer and cite the runbook. Do not mark them passed. + +## Next Step +- [x] Promote to GitHub issue (bug-report template) +- [ ] Move to active fix folder / branch + +Consolidates: #912, #914 (sub-items 1, 3 residual, and the `client-id` comment). #914 sub-item 2 moved to the coverage-runner item. #914 sub-item 4 is fixed by PR #920. \ No newline at end of file diff --git a/scripts/dependencies/ConsistencyVerifier.psm1 b/scripts/dependencies/ConsistencyVerifier.psm1 index 09365f7fc..a3d71fac2 100644 --- a/scripts/dependencies/ConsistencyVerifier.psm1 +++ b/scripts/dependencies/ConsistencyVerifier.psm1 @@ -218,9 +218,9 @@ function Find-PackageAbsentFromManifest { Detects dependent elements whose package is absent from the sibling manifest. .DESCRIPTION The class is non-fatal: counted and named in the report, never a failure result. - QuickFiler.Test carries a live instance in two Exists() guarded elements - naming an altcover package no manifest declares. No exception is hard-coded for any - package identifier. + Issue 929 removed the last live instance, two Exists() guarded elements in + QuickFiler.Test naming an altcover package no manifest declared; the shape survives as + an in-memory test fixture. No exception is hard-coded for any package identifier. .PARAMETER ProjectText The project file text. .PARAMETER ManifestText diff --git a/tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 b/tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 index 41efc9b40..26e5d3e8b 100644 --- a/tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 +++ b/tests/scripts/dependencies/ConsistencyVerifier.Tests.ps1 @@ -54,9 +54,9 @@ BeforeAll { '@ - # Reproduces QuickFiler.Test/QuickFiler.Test.csproj lines 8 and 514: two Exists() guarded - # Import elements naming a package no manifest declares, with no matching Error guard, so - # the build is unaffected. Tracked separately; no exception is hard-coded for it here. + # Reproduces the shape QuickFiler.Test/QuickFiler.Test.csproj carried at lines 8 and 537 until + # issue 929 removed both imports: two Exists() guarded Import elements naming a package no + # manifest declares, with no matching Error guard. No exception is hard-coded for it here. $script:GuardedUnmanifestedProject = @' @@ -236,6 +236,31 @@ Describe 'ConsistencyVerifier detection surfaces' { $detection.FindingCount | Should -Be 1 $detection.Finding[0].PackageFolder | Should -BeExactly 'Fabrikam.Core.3.1.0' } + + It 'reports an Import whose package the manifest does not declare, with Kind Import' { + # Arrange: two guarded Import elements name a package the manifest omits. + $project = $script:GuardedUnmanifestedProject + + # Act + $detection = Find-PackageAbsentFromManifest -ProjectText $project -ManifestText $script:Manifest + + # Assert: both imports are reported, each as an Import naming the altcover folder. + $detection.FindingCount | Should -Be 2 -Because 'both guarded imports name the unmanifested package' + @($detection.Finding | Where-Object { $_.Kind -ne 'Import' }).Count | Should -Be 0 -Because 'every finding is an Import element' + @($detection.Finding | Where-Object { $_.PackageFolder -ne 'altcover.8.6.45' }).Count | Should -Be 0 -Because 'every finding names the altcover package folder' + } + + It 'reports no Import finding when the manifest declares the imported package' { + # Arrange: the agreeing project imports a package its own manifest declares. + $project = $script:AgreeingProject + + # Act + $detection = Find-PackageAbsentFromManifest -ProjectText $project -ManifestText $script:Manifest + + # Assert: the examined count guards the empty Import-kind subset. + @($detection.Finding | Where-Object { $_.Kind -eq 'Import' }).Count | Should -Be 0 -Because 'the manifest declares the imported package' + $detection.ExaminedCount | Should -BeGreaterThan 0 -Because 'a zero examined count would mean the detector never fired' + } } Context 'Missing Roslyn segment aggregation' { @@ -272,7 +297,7 @@ Describe 'ConsistencyVerifier detection surfaces' { Context 'Guarded import of a package no manifest declares' { It 'reports exactly 2 guarded imports of an unmanifested package and still succeeds' { - # Arrange: the live shape from QuickFiler.Test, reproduced in memory. Both imports + # Arrange: the shape QuickFiler.Test carried before issue 929, reproduced in memory. Both imports # are Exists() guarded and carry no matching Error element, so the build is # unaffected, but the invariant this tooling enforces is still violated. $project = $script:GuardedUnmanifestedProject diff --git a/tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 b/tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 new file mode 100644 index 000000000..4fbea957f --- /dev/null +++ b/tests/scripts/dependencies/RepositoryTreeConsistency.Tests.ps1 @@ -0,0 +1,152 @@ +Set-StrictMode -Version Latest + +BeforeAll { + $script:RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '../../..')).Path + Import-Module (Join-Path $script:RepoRoot 'scripts/dependencies/ConsistencyVerifier.psm1') -Force + + # These tests read tracked repository files resolved from $PSScriptRoot and hold every + # other value in memory. Nothing is written to disk. No block or test name in this file + # matches the regex AC followed by a digit. + $script:WorkflowPath = Join-Path $script:RepoRoot '.github/workflows/dependabot-repair.yml' + $script:RunbookPath = Join-Path $script:RepoRoot 'docs/features/active/2026-09-19-dependabot-fanout-and-ci-failing-nuget-upgrades-911/runbooks/github-app-installation-token.runbook.md' + $script:ClientIdPattern = '^\s+client-id:\s*\$\{\{\s*secrets\.([A-Z0-9_]+)\s*\}\}\s*$' + + function Get-TokenStepBlock { + <# + .SYNOPSIS + Returns the lines of the workflow step whose uses line contains the given token. + .DESCRIPTION + Re-implements the step-parsing approach of Get-WorkflowStepBlock in + DependabotConfig.Tests.ps1: a step runs from its name line to the next name line. + #> + param( + [Parameter(Mandatory = $true)][AllowEmptyString()][string[]]$Line, + [Parameter(Mandatory = $true)][string]$UsesToken + ) + + $steps = [System.Collections.Generic.List[object]]::new() + $current = $null + foreach ($text in $Line) { + if ($text -match '^\s+-\s+name:\s*(.+?)\s*$') { + $current = [System.Collections.Generic.List[string]]::new() + $steps.Add($current) + } + if ($null -ne $current) { $current.Add($text) } + } + + foreach ($step in $steps) { + if (@($step | Where-Object { $_ -match '^\s+uses:' -and $_.Contains($UsesToken) }).Count -gt 0) { + return , $step.ToArray() + } + } + return , [string[]]@() + } + + function Get-DependentAssemblyBlock { + <# + .SYNOPSIS + Returns the dependentAssembly element text whose assemblyIdentity names the assembly. + #> + param( + [Parameter(Mandatory = $true)][string]$ConfigText, + [Parameter(Mandatory = $true)][string]$AssemblyName + ) + + $blocks = [regex]::Matches($ConfigText, '(?s).*?') + foreach ($block in $blocks) { + if ($block.Value -match ('name="' + [regex]::Escape($AssemblyName) + '"')) { return $block.Value } + } + return '' + } +} + +Describe 'Repository tree consistency (issue 929)' { + + It 'reports no Import element whose package the sibling manifest omits, for every project directory that carries a manifest' { + # Arrange: every top-level directory holding a packages.config and exactly one project file. + $pair = @(Get-ChildItem -LiteralPath $script:RepoRoot -Directory | ForEach-Object { + $manifest = Join-Path $_.FullName 'packages.config' + $project = @(Get-ChildItem -LiteralPath $_.FullName -File | Where-Object { $_.Extension -eq '.csproj' }) + if ((Test-Path -LiteralPath $manifest) -and $project.Count -eq 1) { + [pscustomobject]@{ Project = $project[0].FullName; Manifest = $manifest } + } + }) + $pair.Count | Should -BeGreaterThan 9 -Because 'the repository carries more than nine project directories with a manifest' + + # Act + $examined = 0 + $finding = [System.Collections.Generic.List[string]]::new() + foreach ($entry in $pair) { + $detection = Find-PackageAbsentFromManifest -ProjectText ([System.IO.File]::ReadAllText($entry.Project)) -ManifestText ([System.IO.File]::ReadAllText($entry.Manifest)) + $examined += $detection.ExaminedCount + foreach ($item in @($detection.Finding | Where-Object { $_.Kind -eq 'Import' })) { + $finding.Add(('{0}: line {1} {2}' -f (Split-Path -Leaf $entry.Project), $item.LineNumber, $item.PackageFolder)) + } + } + + # Assert: the examined count guards the zero finding count. + $examined | Should -BeGreaterThan 0 -Because 'a zero examined count would mean the detector never fired' + $finding.Count | Should -Be 0 -Because ('these Import elements name a package the sibling manifest omits: ' + ($finding -join '; ')) + } + + It 'names in the SVGControl binding redirects the assembly version the SVGControl project reference declares' { + # Arrange + $projectText = [System.IO.File]::ReadAllText((Join-Path $script:RepoRoot 'SVGControl/SVGControl.csproj')) + $configText = [System.IO.File]::ReadAllText((Join-Path $script:RepoRoot 'SVGControl/app.config')) + + foreach ($name in @('Fizzler', 'System.Runtime.CompilerServices.Unsafe')) { + # Act + $referenceMatch = [regex]::Match($projectText, ('Include="' + [regex]::Escape($name) + ', Version=([^,"]+)')) + $referenceVersion = if ($referenceMatch.Success) { $referenceMatch.Groups[1].Value } else { '' } + $block = Get-DependentAssemblyBlock -ConfigText $configText -AssemblyName $name + $newVersion = [regex]::Match($block, 'newVersion="([^"]+)"').Groups[1].Value + $oldVersion = [regex]::Match($block, 'oldVersion="([^"]+)"').Groups[1].Value + + # Assert + $referenceVersion | Should -Not -BeNullOrEmpty -Because "the SVGControl project must declare a $name reference version" + $newVersion | Should -Be $referenceVersion -Because "the $name redirect must name the referenced assembly version" + $oldVersion.EndsWith('-' + $referenceVersion) | Should -BeTrue -Because "the $name oldVersion range '$oldVersion' must end at $referenceVersion" + } + } + + It 'passes client-id and not app-id to the create-github-app-token step of the repair workflow' { + # Arrange + $line = [System.IO.File]::ReadAllLines($script:WorkflowPath) + + # Act + $block = Get-TokenStepBlock -Line $line -UsesToken 'actions/create-github-app-token@' + $clientId = @($block | Where-Object { $_ -match $script:ClientIdPattern }) + $appId = @($block | Where-Object { $_ -match '^\s+app-id:' }) + + # Assert + $block.Count | Should -BeGreaterThan 0 -Because 'the repair workflow must carry a create-github-app-token step' + $clientId.Count | Should -Be 1 -Because 'the token step must pass exactly one client-id input read from a secret' + $appId.Count | Should -Be 0 -Because 'the token step must no longer pass the deprecated app-id input' + } + + It 'instructs the maintainer to store the Client ID in the secret the repair workflow reads by name' { + # Arrange + $workflowLine = [System.IO.File]::ReadAllLines($script:WorkflowPath) + $runbookLine = [System.IO.File]::ReadAllLines($script:RunbookPath) + + # Act: the secret name comes from the workflow, so the runbook is held to what it reads. + $secretName = '' + foreach ($text in $workflowLine) { + if ($text -match $script:ClientIdPattern) { $secretName = $Matches[1]; break } + } + $runbookClientId = @($runbookLine | Where-Object { $_ -match ('^\s*client-id:\s*\$\{\{\s*secrets\.' + [regex]::Escape($secretName) + '\s*\}\}') }) + $runbookAppId = @($runbookLine | Where-Object { $_ -match '^\s*app-id:' }) + $partD = [array]::IndexOf(@($runbookLine | ForEach-Object { $_.StartsWith('### Part D') }), $true) + $partE = [array]::IndexOf(@($runbookLine | ForEach-Object { $_.StartsWith('### Part E') }), $true) + + # Assert + $secretName | Should -Not -BeNullOrEmpty -Because 'the workflow client-id line must name the secret name the runbook has to match' + $runbookClientId.Count | Should -Be 1 -Because "the runbook sample must pass client-id from secrets.$secretName" + $runbookAppId.Count | Should -Be 0 -Because 'the runbook sample must not pass the deprecated app-id input' + $partD | Should -BeGreaterThan -1 -Because 'the runbook must carry a Part D heading' + $partE | Should -BeGreaterThan $partD -Because 'the runbook Part E heading must follow Part D' + $partDText = ($runbookLine[$partD..$partE]) -join "`n" + $partDText.Contains('Client ID') | Should -BeTrue -Because 'Part D must instruct the maintainer to store the Client ID' + $partDText.Contains($secretName) | Should -BeTrue -Because "Part D must name the secret name $secretName exactly as the workflow reads it" + } +}