diff --git a/.claude/agent-memory/task-researcher/MEMORY.md b/.claude/agent-memory/task-researcher/MEMORY.md index 28d35c550..9bca3d626 100644 --- a/.claude/agent-memory/task-researcher/MEMORY.md +++ b/.claude/agent-memory/task-researcher/MEMORY.md @@ -18,3 +18,4 @@ - [legacy-scodictionary-removal-315](project_legacy_scodictionary_removal_315.md) — #315: DELETE SCODictionary_Tests(+Additional), RETARGET 3 SmartSerializable* test files, IScoDictionary interface safe to keep for F5 (2026-07-11) - [lock-recursion-coverage-317](project_lock_recursion_coverage_317.md) — #317: deleted LockRecursionTests.cs is a restoration (F2-authored clean-base coverage F5 knowingly removed per WI-4), not new authoring; no git/shell tool this session (2026-07-11) - [qfc-folder-tree-percentage-325](project_qfc_folder_tree_percentage_325.md) — #325 (epic child 9003): only 1 live viewer (ItemViewer) despite 9 dead CboFolders variants; owner-draw ComboBox + host-neutral TreeNode seams; consumes 9001 probability contract (2026-07-15) +- [dependabot-net481-340](project_dependabot_net481_340.md) — #340: no packages.config package currently dropped net481; transitive-bump restraint is already Dependabot's NuGet default (cite security-updates docs, not a new config primitive); use semver-major ignore not fabricated version ceilings (2026-07-16) diff --git a/.claude/agent-memory/task-researcher/project_dependabot_net481_340.md b/.claude/agent-memory/task-researcher/project_dependabot_net481_340.md new file mode 100644 index 000000000..28b5cd148 --- /dev/null +++ b/.claude/agent-memory/task-researcher/project_dependabot_net481_340.md @@ -0,0 +1,15 @@ +--- +name: project-dependabot-net481-340 +description: Issue #340 Dependabot nuget/packages.config research findings — no verified current framework-drop package, transitive-bump default behavior, directory-glob caveat +metadata: + type: project +--- + +Issue #340 (docs/features/active/2026-07-16-dependabot-net481-support-340/): researched adding `.github/dependabot.yml` for the `nuget` ecosystem across this repo's 16 top-level `packages.config` project directories (8 prod + 8 test), all pinned to `net481`. + +Key findings (2026-07-16): +- Checked NuGet.org Frameworks panels for every distinct package family in the repo's packages.config files (Microsoft.Extensions.*, System.Text.Json, System.Drawing.Common, Apache.Arrow, Microsoft.ML*, Microsoft.Graph, System.Reactive, Svg, FluentAssertions, AngleSharp, FSharp.Core, Microsoft.ApplicationInsights, Microsoft.Data.Analysis, ObjectListView.Official). **None currently has a published version that dropped net462/netstandard2.0/net48x support.** Do not fabricate "known-bad version ceiling" `ignore: versions` ranges without a verified NuGet.org citation — instead use `ignore: update-types: [version-update:semver-major]` scoped to the Microsoft `.NET`-runtime-aligned package families (the only observed pattern where a future framework drop could plausibly land), since major bumps are the only point at which these families have historically changed their TFM list. +- GitHub Docs "About Dependabot security updates" states explicitly: "For other ecosystems [i.e. not npm], Dependabot is unable to update an indirect or transitive dependency if it would also require an update to the parent dependency." This is the citation that satisfies issue #340's "secondary dependency must never be bumped beyond what primary supports" requirement — it is **already Dependabot's default NuGet behavior**, not something the repo's config needs to newly enforce. packages.config has no lockfile, reinforcing this (no transitive entries exist for Dependabot to even discover). +- `directories: ["/*"]` is the concise way to cover all 16 immediate-child project folders in one ecosystem block, but GitHub's docs excerpt available via WebFetch never gave a worked example proving `*` is single-path-segment (not recursive) — flag this as needing a post-merge Insights-tab verification, or fall back to an explicit 16-item directory list. +- GitHub Docs gave two seemingly-conflicting statements on enabling version updates: "commit the file and it's enabled" vs. a Settings→Enable button description. Resolved as: the Settings button is the UI-driven alternative path to *create* the file; committing a hand-authored file via normal PR is the documented enabling mechanism. Recommended a zero-effort post-merge visual check of Settings→Code security and analysis rather than asserting either reading with full certainty (WebFetch's small-model page summarization could not resolve it unambiguously in this session — several per-ecosystem NuGet detail doc URLs 404'd). +- Full findings written to docs/features/active/2026-07-16-dependabot-net481-support-340/research/2026-07-16T16-10-dependabot-net481-support-research.md, including a draft dependabot.yml sketch with groups (analyzers-dev-deps, test-frameworks, microsoft-extensions-and-bcl, graph-identity-telemetry) and the semver-major ignore list. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..4d488b36b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,62 @@ +version: 2 +updates: + - package-ecosystem: "nuget" + directories: + - "/*" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + groups: + analyzers-dev-deps: + patterns: + - "Meziantou.Analyzer" + - "SonarAnalyzer.CSharp" + - "Roslynator.Analyzers" + - "AsyncFixer" + - "Microsoft.CodeAnalysis.BannedApiAnalyzers" + group-by: "dependency-name" + test-frameworks: + patterns: + - "MSTest.*" + - "Moq" + - "FluentAssertions" + - "Castle.Core" + - "Microsoft.Testing.*" + - "Microsoft.TestPlatform.*" + group-by: "dependency-name" + microsoft-extensions-and-bcl: + patterns: + - "Microsoft.Extensions.*" + - "Microsoft.Bcl.*" + - "System.*" + group-by: "dependency-name" + graph-identity-telemetry: + patterns: + - "Microsoft.Graph*" + - "Microsoft.Identity.*" + - "Microsoft.IdentityModel.*" + - "Azure.*" + - "OpenTelemetry*" + - "Microsoft.ApplicationInsights" + group-by: "dependency-name" + ignore: + # Major-version bumps for Microsoft's .NET-runtime-aligned package families are + # the only observed point at which supported TFMs (net462/netstandard2.0) have + # historically changed; gate major bumps behind manual review rather than + # guessing an unverified version-ceiling number (see research §4). + - dependency-name: "Microsoft.Extensions.*" + update-types: ["version-update:semver-major"] + - dependency-name: "Microsoft.Bcl.*" + update-types: ["version-update:semver-major"] + - dependency-name: "System.Text.Json" + update-types: ["version-update:semver-major"] + - dependency-name: "System.Drawing.Common" + update-types: ["version-update:semver-major"] + - dependency-name: "Microsoft.Graph*" + update-types: ["version-update:semver-major"] + - dependency-name: "Apache.Arrow*" + update-types: ["version-update:semver-major"] + - dependency-name: "Microsoft.Data.Analysis" + update-types: ["version-update:semver-major"] + - dependency-name: "Microsoft.ML*" + update-types: ["version-update:semver-major"] diff --git a/README.md b/README.md index f47cb9eec..a19f103bb 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ An Outlook add-in and set of supporting libraries to **triage, tag, and file ema * [Build & debug (VSTO add-in)](#build--debug-vsto-add-in) * [Running the tests](#running-the-tests) * [Configuration & storage](#configuration--storage) +* [Dependency updates (Dependabot)](#dependency-updates-dependabot) * [Common issues](#common-issues) * [Contributing & branches](#contributing--branches) * [License](#license) @@ -153,6 +154,15 @@ Test projects include: --- +## Dependency updates (Dependabot) + +* Dependabot's NuGet updater cannot independently bump a transitive/indirect dependency beyond what its referencing primary dependency's own manifest supports. This is documented default ecosystem behavior (GitHub Docs, "About Dependabot security updates"), not a mechanism this repo's `.github/dependabot.yml` invents. +* The `semver-major`-scoped `ignore` rule set in `.github/dependabot.yml` — covering the eight Microsoft `.NET`-runtime-aligned package families (`Microsoft.Extensions.*`, `Microsoft.Bcl.*`, `System.Text.Json`, `System.Drawing.Common`, `Microsoft.Graph*`, `Apache.Arrow*`, `Microsoft.Data.Analysis`, `Microsoft.ML*`) — is this repo's defense against a future `.NET Framework 4.8.1` (`net481`) compatibility drop. It was adopted because no currently-published version of any package referenced in this repo has dropped net481 support (verified 2026-07-16; see `docs/features/active/2026-07-16-dependabot-net481-support-340/research/2026-07-16T16-10-dependabot-net481-support-research.md` §4). Minor and patch updates for the same package families remain unaffected by this ignore rule. +* The config scopes all 16 `packages.config` project directories via `directories: ["/*"]` (a single-segment wildcard matching every immediate-child directory of the repository root). A pre-decided fallback exists if post-merge verification shows under-coverage: the literal 16-entry `directories:` list documented in `docs/features/active/2026-07-16-dependabot-net481-support-340/spec.md` Appendix A, to be substituted for the glob in a follow-up commit only if that verification shows fewer directories scanned than expected. +* **Runbook note (manual, post-merge verification):** after this configuration merges, a maintainer must manually confirm via the repository's **Insights → Dependency graph → Dependabot** tab (or the "Recent update jobs" log) that at least one of the 16 directories is scanned and produces a dependency list. This check is out of scope for any automated toolchain — no format/lint/type-check/test stage applies to a static YAML file — and is tracked as spec AC-11. + +--- + ## Common issues * **Add-in not loading** diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/code-review.2026-07-16T16-40.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/code-review.2026-07-16T16-40.md new file mode 100644 index 000000000..950508e1a --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/code-review.2026-07-16T16-40.md @@ -0,0 +1,43 @@ +# Code Review — dependabot-net481-support (Issue #340) + +- Feature folder: `docs/features/active/2026-07-16-dependabot-net481-support-340/` +- Resolved base branch: `main` (merge-base `1ac990b7ef4b5c2a0db388b3bb792be4c4190838`) +- Branch head: `bb669ee938893945d3849ef2a059e93a5c34d102` +- Reviewer timestamp: 2026-07-16T16-40 + +## Executive Summary + +This change is config/documentation-only: it adds `.github/dependabot.yml` (62 lines) and a new `## Dependency updates (Dependabot)` section in `README.md`. There is no C#, PowerShell, TypeScript, or Python source or test file in the branch diff (independently verified via `git diff --name-only` against the merge-base; see the policy audit Section 1 for the full 17-file list). Standard best-practices review therefore focuses on the YAML config's correctness, internal consistency with the spec/AC set, and the documentation's clarity and accuracy, rather than language-specific code-quality rules (naming conventions, null-safety, mocking, etc.), which do not apply to a declarative config file. No blocking findings. Two low-severity observations are recorded below for awareness; neither blocks merge. + +## Scope Verified + +- Full `git diff --name-only ..HEAD` reviewed (17 files, 961 insertions, 0 deletions). +- `.github/dependabot.yml` read and parsed with `python -c "import yaml; ..."` — valid YAML, all 6 expected keys present on the single `nuget` `updates` entry. +- `README.md` diff region (`## Dependency updates (Dependabot)`, lines 157–163) read in full. +- Cross-checked YAML content against `spec.md` AC-1, AC-2, AC-3, AC-6, AC-7, AC-8, AC-9 (schema/ignore/groups/scheduling requirements) — all matched exactly, including the eight `ignore` package families and four `groups` buckets. + +## Findings Table + +| Severity | File | Location | Finding | Recommendation | Rationale | Evidence | +|---|---|---|---|---|---|---| +| Low | `.github/dependabot.yml` | `ignore` list, lines 42–62 | The `ignore` safety net is scoped by package-family wildcard pattern (e.g., `Microsoft.Extensions.*`) rather than by a resolved list of specific packages actually referenced in the 16 `packages.config` files. This is broader than strictly necessary (it would also gate any future, currently-unreferenced package matching the pattern), though the spec explicitly authorizes this approach (AC-6) as a defense against packages not yet added. | No action required; documented and intentional per spec "Resolved Ambiguities" and AC-6. Consider revisiting if the `ignore` list is observed to gate an unrelated new dependency after future onboarding. | Wildcard `ignore` patterns trade precision for forward-compatibility; the spec makes this trade-off explicitly and narrows blast radius via `update-types: ["version-update:semver-major"]` only (AC-7), so minor/patch/security patches are unaffected. | `spec.md` lines 61–67 ("Constraints & Risks"), `.github/dependabot.yml` lines 42–62 | +| Low | `README.md` | `## Dependency updates (Dependabot)` section, line 161 | The documentation states the config scopes "all 16 `packages.config` project directories via `directories: ["/*"]`" but the AC-4 enumeration evidence (and this reviewer's independent `find` re-run) shows 18 `packages.config` files exist at depth 1 (the 16 named directories plus `VBFunctions`/`VBFunctions.Test`). The `/*` glob covers all 18 in practice, so the behavior is correct, but the prose figure ("16") undercounts the directories actually covered by the glob. | Consider a documentation follow-up clarifying that `VBFunctions`/`VBFunctions.Test` are also swept up by the same glob (as `spec.md`'s own "Directory inventory" section already states), so a future reader of `README.md` alone does not need to cross-reference `spec.md` to learn the true count. | Accuracy of user-facing documentation; the discrepancy is between two of the feature's own artifacts (`README.md` vs. `spec.md`/AC-4 evidence), not a functional defect — the shipped config behaves correctly either way. | `README.md` line 161; `spec.md` line 24 ("Directory inventory"); `evidence/qa-gates/ac4-packages-config-enumeration.2026-07-16T15-56.md` (18 files enumerated) | + +No Medium, High, or Blocking findings identified. + +## Best-Practices Assessment (non-language-specific) + +- **Simplicity**: the YAML structure is flat and readable; no unnecessary indirection. +- **Extensibility**: `groups`/`ignore` entries use wildcard patterns, so future packages matching an existing family pattern are automatically covered without further config edits. +- **Separation of concerns**: the config file and the documentation change are each scoped to a single concern (declarative automation config vs. rationale documentation); no unrelated changes bundled in. +- **Comments**: the `ignore` block in `.github/dependabot.yml` (lines 43–46) includes a `why`-oriented comment explaining the rationale for gating major-version bumps, consistent with the repo's "comment why, not what" guidance. +- **No dependency additions**: the feature introduces no new library/tooling dependency; it only configures an existing GitHub-native service. +- **No temporary files or external services used during verification**: all evidence-capture commands operate against real repository state (`Test-Path`, `Get-ChildItem`, `git status --porcelain`, `python -c "import yaml"`), consistent with the general policy's I/O-boundary and no-temp-file rules for tests (not strictly applicable here since no tests are added, but the same discipline is observed). + +## Toolchain Applicability + +No format/lint/type-check/test toolchain applies (no source code in any covered language changed). YAML validity was checked via `python -c "import yaml; yaml.safe_load(...)"`, independently re-run by this reviewer with an identical result (`OK`, all 6 keys present). This is the correct and sufficient verification method for a declarative config file with no dedicated repo-level YAML linter configured. + +## Conclusion + +No blocking or high-severity issues found. The two low-severity documentation/scoping observations above do not block merge and do not represent policy violations — they are noted for optional follow-up polish. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/phase0-instructions-read.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/phase0-instructions-read.md new file mode 100644 index 000000000..ce2fed886 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/phase0-instructions-read.md @@ -0,0 +1,24 @@ +# Phase 0 — Instructions Read + +- Timestamp: 2026-07-16T15-56 +- Issue: #340 + +## Policy Order + +1. `CLAUDE.md` (repo-root standing instructions; policy compliance order) +2. `.claude/rules/general-code-change.md` +3. `.claude/rules/general-unit-test.md` +4. `spec.md`, `user-story.md`, `research/2026-07-16T16-10-dependabot-net481-support-research.md` (this feature folder) + +## Files Read + +- `CLAUDE.md` — repo-root standing instructions (already resident in session context; reconfirmed applicable policy order). +- `.claude/rules/general-code-change.md` — read in full. This is a config/documentation-only change (no `.cs`, `.csproj`, or test file is touched). Its design-principles sections (simplicity, reusability, separation of concerns) and naming/error-handling sections apply only loosely to a declarative YAML artifact and a documentation section; the file-size limit (500 lines, with an explicit Markdown-documentation exception) and the "avoid breaking public APIs" guidance are the concretely applicable clauses. The seven-stage "Mandatory Toolchain Loop" (format/lint/type-check/architecture/unit/contract/integration) does not apply to this change: there is no C# source, so no formatter/linter/type-checker/test runner has a target to run against. Per `spec.md`'s Definition of Done, this is superseded by the plan's own Phase 7 substitution (YAML-validity check, AC-4 enumeration, AC-10 diff review). +- `.claude/rules/general-unit-test.md` — read in full. No unit-test policy applies to this feature: no test code is added or modified, no production source file is added or modified, and there is no executable behavior to cover with MSTest/Moq/FluentAssertions. Coverage requirements, scenario-completeness requirements, and determinism-infrastructure requirements in this policy have no applicable target in this change. +- `spec.md` (this feature folder, `docs/features/active/2026-07-16-dependabot-net481-support-340/spec.md`) — read in full. +- `user-story.md` (this feature folder, `docs/features/active/2026-07-16-dependabot-net481-support-340/user-story.md`) — read in full. +- `research/2026-07-16T16-10-dependabot-net481-support-research.md` (this feature folder, `docs/features/active/2026-07-16-dependabot-net481-support-340/research/2026-07-16T16-10-dependabot-net481-support-research.md`) — read in full. + +## Conclusion + +No C# toolchain (CSharpier/analyzer/nullable/`vstest.console.exe`) applies to this change. Phase 7 of the plan substitutes a YAML-validity check plus AC-4/AC-10 verification steps, consistent with `spec.md`'s Definition of Done. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/pre-change-state.2026-07-16T15-56.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/pre-change-state.2026-07-16T15-56.md new file mode 100644 index 000000000..ac54e5353 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/pre-change-state.2026-07-16T15-56.md @@ -0,0 +1,34 @@ +# Pre-Change State Baseline + +- Timestamp: 2026-07-16T15-56 +- Issue: #340 + +## `.github/dependabot.yml` existence check + +- Command: `Test-Path .github/dependabot.yml` +- EXIT_CODE: 0 +- Output Summary: `False` (file does not exist) + +## README.md baseline + +- Command: read `README.md` `## Contents` list and the section ordering around `## Configuration & storage` / `## Common issues`. +- EXIT_CODE: 0 +- Output Summary: + +Current `## Contents` list (verbatim, lines 11-19 of `README.md`): + +``` +* [Features](#features) +* [Solution layout](#solution-layout) +* [Getting started](#getting-started) +* [Build & debug (VSTO add-in)](#build--debug-vsto-add-in) +* [Running the tests](#running-the-tests) +* [Configuration & storage](#configuration--storage) +* [Common issues](#common-issues) +* [Contributing & branches](#contributing--branches) +* [License](#license) +``` + +There is no `Dependency updates (Dependabot)` entry in the `## Contents` list. + +Section adjacency confirmed: `## Configuration & storage` (README.md line 142) is immediately followed (after its closing `---` divider at line 154) by `## Common issues` (README.md line 156), with no section in between. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/ac5-ac11-deferred-note.2026-07-16T15-56.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/ac5-ac11-deferred-note.2026-07-16T15-56.md new file mode 100644 index 000000000..9cf12b9a3 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/ac5-ac11-deferred-note.2026-07-16T15-56.md @@ -0,0 +1,20 @@ +# AC-5 / AC-11 Deferred Note + +- Timestamp: 2026-07-16T15-56 +- Issue: #340 + +## Confirmation + +`spec.md` was read back and confirmed to still contain, unchanged: + +- `- [ ] AC-5: Pre-decided fallback — if the post-merge check in AC-11 shows Dependabot scanning fewer directories than expected...` +- `- [ ] AC-11: After merge, a maintainer manually confirms via the repository's Insights → Dependency graph → Dependabot tab...` + +Both lines are intentionally left unchecked by this plan. + +## Reason + +- **AC-5** is a pre-decided contingency triggered only by a future AC-11 result. It documents the fallback (the literal 16-entry `directories:` list in `spec.md` Appendix A) that would be adopted only if AC-11's post-merge check shows under-coverage. Since AC-11 has not yet been executed (it is a manual, post-merge check), AC-5's trigger condition has not occurred, and no follow-up commit is warranted at this time. AC-5 remains a documented fallback, not an active task in this plan. +- **AC-11** has been resolved by the orchestrator as `scope_change`: it is a deferred, manual, post-merge check (confirming via the repository's Insights → Dependency graph → Dependabot tab that at least one of the 16 directories is scanned) and is not a blocking Definition-of-Done item in this plan. The README documentation section added in Phase 5 (content point 4) records the runbook-note text pointing a future maintainer to this manual check. + +Output Summary: AC-5 and AC-11 confirmed unchecked in spec.md by design; reasons recorded per plan Scope Note. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/plan-completion-summary.2026-07-16T15-56.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/plan-completion-summary.2026-07-16T15-56.md new file mode 100644 index 000000000..3692478de --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/plan-completion-summary.2026-07-16T15-56.md @@ -0,0 +1,29 @@ +# Plan Completion Summary + +- Timestamp: 2026-07-16T15-56 +- Issue: #340 + +## Final AC checkbox state (`spec.md`) + +| AC | State | +|---|---| +| AC-1 | Checked `[x]` | +| AC-2 | Checked `[x]` | +| AC-3 | Checked `[x]` | +| AC-4 | Checked `[x]` | +| AC-5 | Unchecked `[ ]` — intentional, pre-decided contingency not triggered (see `evidence/other/ac5-ac11-deferred-note.2026-07-16T15-56.md`) | +| AC-6 | Checked `[x]` | +| AC-7 | Checked `[x]` | +| AC-8 | Checked `[x]` | +| AC-9 | Checked `[x]` | +| AC-10 | Checked `[x]` | +| AC-11 | Unchecked `[ ]` — intentional, orchestrator-resolved `scope_change`, deferred manual post-merge verification (see `evidence/other/ac5-ac11-deferred-note.2026-07-16T15-56.md`) | +| AC-12 | Checked `[x]` | + +## Summary + +10 of 12 acceptance criteria (AC-1 through AC-4, AC-6 through AC-10, and AC-12) are checked off in `spec.md`, matching delivered and verified work. AC-5 and AC-11 remain intentionally unchecked by design, as documented in the plan's Scope Note and in `evidence/other/ac5-ac11-deferred-note.2026-07-16T15-56.md`. + +`.github/dependabot.yml` and the `README.md` `## Dependency updates (Dependabot)` section (with `## Contents` entry) were created exactly per `spec.md`'s Documentation Deliverable and Behavior sections. YAML validity was confirmed (`DEPENDABOT_YAML_VALID`, exit 0). Diff review (`git status --porcelain`, `git diff --name-only -- "*.csproj"`) confirmed zero TFM/`.csproj` changes. + +Output Summary: 10/12 AC items checked; AC-5 and AC-11 intentionally unchecked per plan design; all Phase 0-7 tasks completed. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac10-diff-review.2026-07-16T15-56.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac10-diff-review.2026-07-16T15-56.md new file mode 100644 index 000000000..7198444ff --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac10-diff-review.2026-07-16T15-56.md @@ -0,0 +1,36 @@ +# AC-10 Diff Review + +- Timestamp: 2026-07-16T15-56 +- Issue: #340 +- Command: `git status --porcelain` +- EXIT_CODE: 0 + +## Output Summary + +Changed-path set returned by `git status --porcelain`: + +``` + M .claude/agent-memory/task-researcher/MEMORY.md + M README.md +?? .claude/agent-memory/task-researcher/project_dependabot_net481_340.md +?? .github/dependabot.yml +?? docs/features/active/2026-07-16-dependabot-net481-support-340/ +``` + +## Path check + +- `.github/dependabot.yml` — untracked/new — present, this feature's config deliverable. +- `README.md` — modified — present, this feature's documentation deliverable. +- Among the `git status --porcelain` output, there are zero `.csproj`, `.cs`, or other project/build-project-file changes. +- Pre-existing, out-of-scope paths (not a verification failure, listed separately per plan P6-T2): + - `.claude/agent-memory/task-researcher/MEMORY.md` (modified) — agent-memory drift, unrelated to this feature's deliverables. + - `.claude/agent-memory/task-researcher/project_dependabot_net481_340.md` (untracked) — agent-memory drift, unrelated to this feature's deliverables. + - `docs/features/active/2026-07-16-dependabot-net481-support-340/` (untracked) — this feature's own planning/spec/evidence folder, not a project/build file. + +Output Summary: `.github/dependabot.yml` (untracked/new) and `README.md` (modified) are the only project-relevant deliverable paths; zero `.csproj`/`.cs`/build-project-file changes present; pre-existing unrelated paths documented separately. + +## Additional command: `.csproj` diff check + +- Command: `git diff --name-only -- "*.csproj"` +- EXIT_CODE: 0 +- Output Summary: no output (zero `.csproj` files changed) diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac2-schema-structure-review.2026-07-16T15-56.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac2-schema-structure-review.2026-07-16T15-56.md new file mode 100644 index 000000000..091ad458a --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac2-schema-structure-review.2026-07-16T15-56.md @@ -0,0 +1,19 @@ +# AC-2 Schema Structure Review + +- Timestamp: 2026-07-16T15-56 +- Issue: #340 + +## Key-by-key checklist (single `nuget` `updates:` entry) + +| Key | Observed value/type | Present | +|---|---|---| +| `package-ecosystem` | `"nuget"` (string) | Yes | +| `directories` | `["/*"]` (list of one string) | Yes | +| `schedule` | mapping with `interval: "weekly"` | Yes | +| `open-pull-requests-limit` | `10` (integer) | Yes | +| `groups` | mapping with 4 sub-keys, each a mapping with `patterns` (list) + `group-by` (string) | Yes | +| `ignore` | list of 8 mappings, each with `dependency-name` (string) + `update-types` (list of one string) | Yes | + +All six required keys are present, correctly typed, and match the Dependabot v2 options reference structure cited in research §2/§4/§5. + +Output Summary: all 6 required keys present and correctly typed diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac4-packages-config-enumeration.2026-07-16T15-56.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac4-packages-config-enumeration.2026-07-16T15-56.md new file mode 100644 index 000000000..609363866 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac4-packages-config-enumeration.2026-07-16T15-56.md @@ -0,0 +1,37 @@ +# AC-4 packages.config Enumeration + +- Timestamp: 2026-07-16T15-56 +- Issue: #340 +- Command: `Get-ChildItem -Path . -Filter packages.config -Recurse | Select-Object FullName` +- EXIT_CODE: 0 + +## Output Summary + +Full set of returned `FullName` values (repository root: `C:\Users\DanMoisan\repos\TaskMaster-wt\2026-07-16T15-49\`): + +1. `QuickFiler\packages.config` +2. `QuickFiler.Test\packages.config` +3. `SVGControl\packages.config` +4. `SVGControl.Test\packages.config` +5. `Tags\packages.config` +6. `Tags.Test\packages.config` +7. `TaskMaster\packages.config` +8. `TaskMaster.Test\packages.config` +9. `TaskTree\packages.config` +10. `TaskTree.Test\packages.config` +11. `TaskVisualization\packages.config` +12. `TaskVisualization.Test\packages.config` +13. `ToDoModel\packages.config` +14. `ToDoModel.Test\packages.config` +15. `UtilitiesCS\packages.config` +16. `UtilitiesCS.Test\packages.config` +17. `VBFunctions\packages.config` +18. `VBFunctions.Test\packages.config` + +## Depth check + +Each `FullName` has exactly one path segment (the project directory name) between the repository root and `packages.config` — all 18 files are at depth 1 from the repository root; no `packages.config` file exists at any nested/deeper path. + +Total: 18 + +This spans the 16 directories listed in `spec.md` Appendix A (`QuickFiler`, `QuickFiler.Test`, `SVGControl`, `SVGControl.Test`, `Tags`, `Tags.Test`, `TaskMaster`, `TaskMaster.Test`, `TaskTree`, `TaskTree.Test`, `TaskVisualization`, `TaskVisualization.Test`, `ToDoModel`, `ToDoModel.Test`, `UtilitiesCS`, `UtilitiesCS.Test`) plus `VBFunctions` and `VBFunctions.Test`. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/yaml-validity.2026-07-16T15-56.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/yaml-validity.2026-07-16T15-56.md new file mode 100644 index 000000000..2f8802986 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/yaml-validity.2026-07-16T15-56.md @@ -0,0 +1,22 @@ +# YAML Validity Check + +- Timestamp: 2026-07-16T15-56 +- Issue: #340 + +## Step 1 — Install pyyaml + +- Command: `pip install --quiet pyyaml` +- EXIT_CODE: 0 +- Output Summary: pyyaml installed/already satisfied (only an unrelated pip-self-update notice printed) + +## Step 2 — YAML validity check + +- Command: `python -c "import yaml; yaml.safe_load(open('.github/dependabot.yml', encoding='utf-8')); print('DEPENDABOT_YAML_VALID')"` +- EXIT_CODE: 0 +- Output Summary: `DEPENDABOT_YAML_VALID` printed — file parses as valid YAML + +## Step 3 — Retry loop status + +P7-T2 passed on the first run (exit 0, `DEPENDABOT_YAML_VALID` printed). No YAML syntax error was found, so no P7-T3 remediation/rerun cycle was required. + +Final recorded run for P7-T2: `EXIT_CODE: 0`, `DEPENDABOT_YAML_VALID`. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/feature-audit.2026-07-16T16-40.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/feature-audit.2026-07-16T16-40.md new file mode 100644 index 000000000..9bb2bc3df --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/feature-audit.2026-07-16T16-40.md @@ -0,0 +1,73 @@ +# Feature Audit — dependabot-net481-support (Issue #340) + +- Feature folder: `docs/features/active/2026-07-16-dependabot-net481-support-340/` +- Reviewer timestamp: 2026-07-16T16-40 + +## Scope and Baseline + +- Resolved base branch: `main` +- Merge-base SHA: `1ac990b7ef4b5c2a0db388b3bb792be4c4190838` +- Branch head SHA: `bb669ee938893945d3849ef2a059e93a5c34d102` +- Work mode (from `issue.md` `- Work Mode:` marker): `full-feature` +- Acceptance-criteria source files (per `full-feature` mode): `spec.md` (AC-1 through AC-12) and `user-story.md` (restated maintainer-perspective bullets) +- Baseline state (pre-change, per `evidence/baseline/pre-change-state.2026-07-16T15-56.md`, independently spot-checked): `.github/dependabot.yml` did not exist (`Test-Path` returned `False`); `README.md` had no `Dependency updates (Dependabot)` entry in `## Contents` and no such section between `## Configuration & storage` and `## Common issues`. + +## Acceptance Criteria Inventory + +From `spec.md`: + +1. AC-1 — `.github/dependabot.yml` exists, begins with `version: 2`, exactly one `updates:` entry with `package-ecosystem: "nuget"`. +2. AC-2 — the `nuget` entry's six keys present, correctly typed, valid YAML. +3. AC-3 — directory-scoping mechanism is `directories: ["/*"]`, shipped as final. +4. AC-4 — pre-merge enumeration confirms `packages.config` files exist only at depth 1, across the 16 spec-listed directories (plus `VBFunctions`/`VBFunctions.Test`). +5. AC-5 — pre-decided fallback to the literal 16-entry `directories:` list, triggered only if AC-11 shows under-coverage. +6. AC-6 — `ignore` list contains one entry per named Microsoft `.NET`-runtime-aligned package family, each scoped to `semver-major`, no fabricated `versions:` ceiling. +7. AC-7 — no `ignore` entry includes `semver-minor`/`semver-patch`. +8. AC-8 — `groups` defines four named buckets with `patterns` + `group-by: "dependency-name"`. +9. AC-9 — `schedule.interval` is `"weekly"`, `open-pull-requests-limit` is `10`. +10. AC-10 — diff review shows zero `.csproj` TFM-element modifications; only `.github/dependabot.yml` and `README.md` changed. +11. AC-11 — post-merge manual confirmation via GitHub Insights → Dependency graph → Dependabot that at least one directory was scanned. +12. AC-12 — `README.md` gains the `## Dependency updates (Dependabot)` section with all four required content points and a `## Contents` entry. + +From `user-story.md` (restated, mapped 1:1 to the spec ACs above): directory coverage, safety-net semantics, grouped PRs, weekly cadence/PR cap, TFM non-modification, documentation rationale, and the deferred manual post-merge check. + +## Acceptance Criteria Evaluation + +| AC | Evaluation | Evidence | +|---|---|---| +| AC-1 | **PASS** | `.github/dependabot.yml` line 1 is `version: 2`; `updates:` has exactly one entry; `package-ecosystem: "nuget"` present. Independently re-read the file. | +| AC-2 | **PASS** | `python -c "import yaml; ..."` (re-run by this reviewer) parses the file successfully and confirms all 6 keys (`package-ecosystem`, `directories`, `schedule`, `open-pull-requests-limit`, `groups`, `ignore`) on the single `updates[0]` entry, each of the documented type (string, list, mapping, integer, mapping, list). | +| AC-3 | **PASS** | `directories:` key's only value is `/*` (block-style list), confirmed by direct file read. | +| AC-4 | **PASS** | Independently re-ran `find . -maxdepth 2 -iname "packages.config"` — found exactly 18 files at depth 1, matching the feature's own `ac4-packages-config-enumeration` evidence, spanning the 16 spec-listed directories plus `VBFunctions`/`VBFunctions.Test`. | +| AC-5 | **Not yet applicable (intentionally unchecked)** | Correctly left `[ ]` in `spec.md`. This is a pre-decided contingency that only activates on an under-coverage result from AC-11, which has not yet run (AC-11 is a manual, post-merge, GitHub-Insights-dependent check that cannot be executed in this offline review environment — GitHub CLI is unavailable per `artifacts/pr_context.summary.txt`). Leaving both unchecked is the correct, spec-mandated state, not a gap. | +| AC-6 | **PASS** | Independently re-ran `grep -c "^ - dependency-name:"` (8 matches) and `grep -n "versions:"` (0 matches) against `.github/dependabot.yml`; the 8 `dependency-name` values match the 8 families named in AC-6 exactly (`Microsoft.Extensions.*`, `Microsoft.Bcl.*`, `System.Text.Json`, `System.Drawing.Common`, `Microsoft.Graph*`, `Apache.Arrow*`, `Microsoft.Data.Analysis`, `Microsoft.ML*`); each has `update-types: ["version-update:semver-major"]`. | +| AC-7 | **PASS** | `grep -c "semver-minor\|semver-patch"` against `.github/dependabot.yml` returns 0. | +| AC-8 | **PASS** | Direct file read confirms `groups:` has exactly four sub-keys (`analyzers-dev-deps`, `test-frameworks`, `microsoft-extensions-and-bcl`, `graph-identity-telemetry`), each with a non-empty `patterns` list and `group-by: "dependency-name"`. | +| AC-9 | **PASS** | `schedule.interval: "weekly"` and `open-pull-requests-limit: 10` both present, confirmed by direct read. | +| AC-10 | **PASS** | Independently re-ran `git diff --name-only ..HEAD -- "*.csproj"` — no output. Full `git diff --name-only` (17 files) contains no `.cs`/`.csproj` path. | +| AC-11 | **UNVERIFIED (deferred by design, not a review gap)** | This is an explicitly manual, post-merge, out-of-toolchain check per the spec's own text ("This check is explicitly out of scope for the atomic-executor's automated toolchain... it does not block the initial merge, but the feature is not considered fully verified (feature-audit) until it passes"). GitHub CLI is unavailable in this environment (`artifacts/pr_context.summary.txt`: "GitHub CLI unavailable"), so the Insights → Dependency graph → Dependabot tab cannot be checked from this session. Per the spec's own terms, full feature verification is contingent on this maintainer action occurring after merge; this audit records it as the sole outstanding item rather than treating it as a failure. | +| AC-12 | **PASS** | Independently re-read `README.md` lines 157–163: the `## Dependency updates (Dependabot)` section is present between `## Configuration & storage` and `## Common issues`, contains all four required content points (transitive-dependency behavior, `ignore` safety-net rationale, `directories`/fallback decision, AC-11 runbook pointer), and the `## Contents` list (line 17) carries the matching entry in the correct position. | + +## Summary + +- 10 of 12 acceptance criteria: **PASS**, independently re-verified against the live repository state (not merely accepted from feature-supplied evidence). +- 1 of 12 (AC-5): correctly and intentionally left unchecked as a pre-decided contingency not yet triggered. +- 1 of 12 (AC-11): correctly and intentionally left unverified/unchecked pending a manual, post-merge, GitHub-UI-dependent maintainer action that cannot be executed from this offline review session. +- No acceptance criterion evaluated as FAIL or PARTIAL. +- No C#, PowerShell, TypeScript, or Python coverage gate applies (zero changed files in any of those languages, verified independently — see `policy-audit.2026-07-16T16-40.md` Section 1–2). +- **Recommendation: PR-ready for merge**, contingent on the maintainer performing the AC-11 manual verification after merge and applying the AC-5 fallback only if that check shows under-coverage. Neither of these is a blocking condition on merge per the spec's own Definition of Done. + +### Acceptance Criteria Status + +- Source: `docs/features/active/2026-07-16-dependabot-net481-support-340/spec.md` and `docs/features/active/2026-07-16-dependabot-net481-support-340/user-story.md` +- Total AC items: 12 (spec.md AC-1–AC-12) plus 7 restated bullets (user-story.md) +- Checked off (delivered): 10 (spec.md AC-1, AC-2, AC-3, AC-4, AC-6, AC-7, AC-8, AC-9, AC-10, AC-12); 6 of 7 in user-story.md +- Remaining (unchecked): 2 in spec.md (AC-5, AC-11); 1 in user-story.md (the AC-11-mirroring post-merge-confirmation bullet) +- Items remaining: + - `spec.md` AC-5 — pre-decided fallback, not yet triggered (contingent on AC-11 result) + - `spec.md` AC-11 — manual post-merge GitHub Insights confirmation (cannot be executed in this offline session) + - `user-story.md` — "After merge, Dan (or another maintainer) confirms via GitHub's Dependabot Insights tab..." (mirrors AC-11) + +## Acceptance Criteria Check-off + +No new check-offs were made by this review: all criteria evaluated as PASS above were **already** checked `[x]` in `spec.md` and `user-story.md` prior to this review (confirmed by direct read — see the "Acceptance Criteria Evaluation" table). AC-5 and AC-11 remain correctly unchecked in both files; this reviewer did not alter their state, consistent with the acceptance-criteria-tracking protocol's rule against checking off criteria that cannot be verified as delivered (AC-11 requires a live GitHub UI action unavailable in this session). diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/issue.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/issue.md new file mode 100644 index 000000000..f09227700 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/issue.md @@ -0,0 +1,45 @@ +# dependabot-net481-support (Issue #340) + +- Date captured: 2026-07-16 +- Author: Dan Moisan +- Status: Promoted -> docs/features/active/dependabot-net481-support/ (Issue #340) + +- Issue: #340 +- Issue URL: https://github.com/drmoisan/TaskMaster/issues/340 +- Last Updated: 2026-07-16 +- Work Mode: full-feature + +## Problem / Why + +The repository has no automated dependency-update tooling. NuGet package versions across all eight `packages.config`-based projects (and their test counterparts) are updated manually, so known-vulnerable or stale dependency versions can persist unnoticed. + +## Proposed Behavior + +Add a `.github/dependabot.yml` configuration that enables the `nuget` package ecosystem for this repository. Because every production project targets `.NET Framework 4.8.1` (a framework line, not a package, so it is not itself a Dependabot-managed dependency), the configuration must not propose NuGet package versions that drop support for `.NET Framework` / `net48`/`net481` compatibility. Because Dependabot's NuGet updater only opens PRs for dependencies declared directly in a project's `packages.config`/`PackageReference` list, and it resolves any correlated transitive-dependency bumps required by a direct upgrade using NuGet's own dependency graph, secondary (transitive) dependencies must never be bumped independently of, or beyond what, their referencing primary dependency actually supports. + +## Acceptance Criteria (early draft) + +- [ ] `.github/dependabot.yml` exists, is schema-valid, and declares a `nuget` ecosystem update job. +- [ ] The configuration covers every project directory containing a `packages.config` (all eight production + eight test projects, or their common root as supported by the ecosystem). +- [ ] The configuration includes explicit `ignore` rules (or equivalent version-range constraints) preventing upgrades to package major/minor versions known to have dropped `.NET Framework 4.8`/`4.8.1` support. +- [ ] Documentation records the rationale: Dependabot does not independently upgrade transitive dependencies beyond what the direct/primary dependency's own manifest supports, and how this repo's config reinforces that for framework compatibility. +- [ ] No production or test project's target framework moniker (TFM) is changed. + +## Constraints & Risks + +- All projects use `packages.config`, not `PackageReference` — must confirm Dependabot's `nuget` ecosystem support for that manifest format. +- `.NET Framework 4.8.1` is fixed; the repository must not receive PRs proposing dependency versions that require `.NET`/`.NET Core`/newer `net4x` TFMs only. +- Risk: Dependabot has no native "TFM-aware ignore" primitive — compatibility constraints must be expressed via explicit per-package `ignore` version-range rules discovered through research into affected packages' release notes/support matrices. +- Risk: overly broad `ignore` rules could suppress legitimate compatible security patches; rules should be as narrow as version ranges allow. + +## Test Conditions to Consider + +- [ ] YAML validates against the Dependabot v2 config schema. +- [ ] Config correctly scopes `directory`/`directories` to every `packages.config` project root. +- [ ] `ignore` rules are anchored to specific packages and version ranges, not blanket ecosystem suppression. + +## Next Step + +- [ ] Promote to GitHub issue (feature request template) +- [ ] Create `docs/features/active/dependabot-net481-support/` folder from the template + diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/plan.2026-07-16T15-56.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/plan.2026-07-16T15-56.md new file mode 100644 index 000000000..124aeb342 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/plan.2026-07-16T15-56.md @@ -0,0 +1,166 @@ +# dependabot-net481-support - Plan + +- **Issue:** #340 +- **Parent (optional):** none +- **Owner:** drmoisan +- **Last Updated:** 2026-07-16T15-56 +- **Status:** Draft +- **Version:** 0.2 + +## Required References + +- `CLAUDE.md` (repo-root standing instructions; policy compliance order) +- `.claude/rules/general-code-change.md` +- `.claude/rules/general-unit-test.md` +- `spec.md` (this feature folder) — AC-1 through AC-12, Appendix A +- `user-story.md` (this feature folder) +- `research/2026-07-16T16-10-dependabot-net481-support-research.md` (this feature folder) +- `.claude/skills/atomic-plan-contract/SKILL.md` +- `.claude/skills/evidence-and-timestamp-conventions/SKILL.md` +- `.claude/skills/acceptance-criteria-tracking/SKILL.md` + +**All work must comply with these policies; do not duplicate their content here.** + +## Scope Note (config-only feature) + +This feature adds exactly two artifacts: `.github/dependabot.yml` (new file) and a new +`## Dependency updates (Dependabot)` section in `README.md`. No `.cs`, `.csproj`, or test +file is touched. Per `spec.md`'s Definition of Done, the CSharpier/analyzer/nullable/ +`vstest.console.exe` toolchain in `CLAUDE.md` does **not** apply to this change; the final +QC phase below substitutes a YAML-validity check, the AC-4 pre-merge enumeration check, and +an AC-10 diff review in place of that toolchain. + +AC-5 (literal 16-directory fallback) and AC-11 (manual post-merge GitHub Insights check) are +intentionally **not** executed by this plan: +- AC-5 is a pre-decided contingency triggered only by a future AC-11 result; it remains a + documented fallback in `spec.md` Appendix A, not an active task here. +- AC-11 has been resolved by the orchestrator as `scope_change`: it is a deferred, manual, + post-merge check and is not a blocking Definition-of-Done item in this plan. The README + documentation task (Phase 5) still records the runbook-note text pointing a future + maintainer to that manual check. + +## Implementation Plan (Atomic Tasks) + +### Phase 0 — Baseline Capture & Compliance Reads + +- [x] [P0-T1] Read `.claude/rules/general-code-change.md` in full and confirm its design-principles/toolchain-loop sections apply to this config-only change (no C# is touched, so only the general policy governs authoring discipline) + - Acceptance: `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/phase0-instructions-read.md` created, containing `Timestamp:`, `Policy Order:` (listing this file first), and confirmation the file was read +- [x] [P0-T2] Read `.claude/rules/general-unit-test.md` in full and record in the same evidence artifact that no unit-test policy applies to this feature (no test code is added or modified) + - Acceptance: `phase0-instructions-read.md` updated with `.claude/rules/general-unit-test.md` added to the "files read" list and the no-test-code note +- [x] [P0-T3] Read `spec.md`, `user-story.md`, and `research/2026-07-16T16-10-dependabot-net481-support-research.md` in full + - Acceptance: `phase0-instructions-read.md` lists all three documents under "files read" with the exact relative paths +- [x] [P0-T4] Confirm baseline: run `Test-Path .github/dependabot.yml` from the repository root and confirm the result is `False` (file does not yet exist) + - Acceptance: `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/pre-change-state.2026-07-16T15-56.md` created containing `Timestamp:`, `Command: Test-Path .github/dependabot.yml`, `EXIT_CODE: 0`, `Output Summary: False (file does not exist)` +- [x] [P0-T5] Confirm baseline: read `README.md` and record that the `## Contents` list currently has no `Dependency updates (Dependabot)` entry, and that the `## Configuration & storage` section (line ~142) is immediately followed by the `## Common issues` section (line ~156) with no section in between + - Acceptance: `pre-change-state.2026-07-16T15-56.md` updated with a `README.md baseline:` subsection recording the current `## Contents` bullet list verbatim and confirming the `Configuration & storage` → `Common issues` adjacency + +### Phase 1 — Author `.github/dependabot.yml` core schema (AC-1, AC-3, AC-9) + +- [x] [P1-T1] Create `.github/dependabot.yml` containing `version: 2` and one `updates:` list entry with `package-ecosystem: "nuget"` + - Acceptance: file `.github/dependabot.yml` exists; its first non-comment line is `version: 2`; the `updates:` list has exactly one entry whose `package-ecosystem` value is `"nuget"` — satisfies AC-1 +- [x] [P1-T2] Add `directories: ["/*"]` (or block-style equivalent) as a key of the same `nuget` `updates:` entry created in P1-T1 + - Acceptance: the `nuget` entry in `.github/dependabot.yml` contains a `directories` key whose only value is `/*` — satisfies AC-3 +- [x] [P1-T3] Add a `schedule:` key to the same entry with `interval: "weekly"` + - Acceptance: the `nuget` entry contains `schedule.interval: "weekly"` +- [x] [P1-T4] Add `open-pull-requests-limit: 10` to the same entry + - Acceptance: the `nuget` entry contains `open-pull-requests-limit: 10` — combined with P1-T3, satisfies AC-9 +- [x] [P1-T5] Check off AC-9 in `spec.md` (line beginning `- [ ] AC-9:`) and the corresponding restated bullet in `user-story.md` (the "update cadence is weekly" bullet), changing each to `- [x]` + - Acceptance: `spec.md` line for AC-9 reads `- [x] AC-9: ...`; `user-story.md`'s weekly-cadence bullet reads `- [x] ...` + +### Phase 2 — Author grouping & TFM-compatibility ignore safety net (AC-6, AC-7, AC-8) + +- [x] [P2-T1] Add a `groups:` key to the `nuget` entry defining exactly four buckets — `analyzers-dev-deps`, `test-frameworks`, `microsoft-extensions-and-bcl`, `graph-identity-telemetry` — each with a `patterns:` list and `group-by: "dependency-name"`, using the package-family inventory from research §1.1/§6: + - `analyzers-dev-deps`: `Meziantou.Analyzer`, `SonarAnalyzer.CSharp`, `Roslynator.Analyzers`, `AsyncFixer`, `Microsoft.CodeAnalysis.BannedApiAnalyzers` + - `test-frameworks`: `MSTest.*`, `Moq`, `FluentAssertions`, `Castle.Core`, `Microsoft.Testing.*`, `Microsoft.TestPlatform.*` + - `microsoft-extensions-and-bcl`: `Microsoft.Extensions.*`, `Microsoft.Bcl.*`, `System.*` + - `graph-identity-telemetry`: `Microsoft.Graph*`, `Microsoft.Identity.*`, `Microsoft.IdentityModel.*`, `Azure.*`, `OpenTelemetry*`, `Microsoft.ApplicationInsights` + - Acceptance: `.github/dependabot.yml`'s `groups` key has exactly four sub-keys matching the four bucket names above, each containing a non-empty `patterns` list and `group-by: "dependency-name"` — satisfies AC-8 +- [x] [P2-T2] Add an `ignore:` key to the `nuget` entry with exactly eight entries — one per Microsoft `.NET`-runtime-aligned package family named in `spec.md` AC-6 (`Microsoft.Extensions.*`, `Microsoft.Bcl.*`, `System.Text.Json`, `System.Drawing.Common`, `Microsoft.Graph*`, `Apache.Arrow*`, `Microsoft.Data.Analysis`, `Microsoft.ML*`), each entry containing only `dependency-name` and `update-types: ["version-update:semver-major"]` (no `versions:` key on any entry) + - Acceptance: `.github/dependabot.yml`'s `ignore` list has exactly 8 entries; each entry's `dependency-name` matches one of the eight listed families with no duplicates or omissions; no entry contains a `versions:` key — satisfies AC-6 +- [x] [P2-T3] Read back the `ignore` list added in P2-T2 and confirm no entry's `update-types` contains `version-update:semver-minor` or `version-update:semver-patch` + - Acceptance: grep of `.github/dependabot.yml` for `semver-minor` and `semver-patch` returns zero matches — satisfies AC-7 +- [x] [P2-T4] Check off AC-6, AC-7, and AC-8 in `spec.md` (three `- [ ]` lines changed to `- [x]`) and the corresponding restated bullets in `user-story.md` (the TFM-safety-net bullet and the grouped-PR bullet) + - Acceptance: `spec.md` lines for AC-6, AC-7, AC-8 each read `- [x] AC-#: ...`; `user-story.md`'s two corresponding bullets read `- [x] ...` + +### Phase 3 — Schema structure verification (AC-2) + +- [x] [P3-T1] Read the complete `.github/dependabot.yml` file back and confirm the single `nuget` `updates:` entry contains all six required keys (`package-ecosystem`, `directories`, `schedule`, `open-pull-requests-limit`, `groups`, `ignore`), each correctly typed per the Dependabot v2 options reference (string, list, mapping, integer, mapping, list respectively) + - Acceptance: `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac2-schema-structure-review.2026-07-16T15-56.md` created containing `Timestamp:`, a key-by-key checklist of the six required keys with their observed type, and `Output Summary: all 6 required keys present and correctly typed` — satisfies AC-2 +- [x] [P3-T2] Check off AC-1, AC-2, and AC-3 in `spec.md` (three `- [ ]` lines changed to `- [x]`) + - Acceptance: `spec.md` lines for AC-1, AC-2, AC-3 each read `- [x] AC-#: ...` + +### Phase 4 — Directory coverage enumeration evidence (AC-4; AC-5/AC-11 left unchecked by design) + +- [x] [P4-T1] Run `Get-ChildItem -Path . -Filter packages.config -Recurse | Select-Object FullName` from the repository root and capture the full output + - Acceptance: `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac4-packages-config-enumeration.2026-07-16T15-56.md` created containing `Timestamp:`, `Command: Get-ChildItem -Path . -Filter packages.config -Recurse | Select-Object FullName`, `EXIT_CODE: 0`, and `Output Summary:` listing the full set of returned `FullName` values +- [x] [P4-T2] Confirm the enumeration output from P4-T1 lists exactly 18 `packages.config` files, all at path depth 1 from the repository root, spanning the 16 directories in `spec.md` Appendix A plus `VBFunctions` and `VBFunctions.Test` + - Acceptance: `ac4-packages-config-enumeration.2026-07-16T15-56.md` updated with a `Depth check:` line confirming each `FullName` has exactly one path segment between the repository root and `packages.config`, and a count line reading `Total: 18` — satisfies AC-4 +- [x] [P4-T3] Check off AC-4 in `spec.md` (`- [ ]` changed to `- [x]`) and the corresponding "no directory left unmonitored" bullet in `user-story.md` + - Acceptance: `spec.md`'s AC-4 line reads `- [x] AC-4: ...`; `user-story.md`'s matching bullet reads `- [x] ...` +- [x] [P4-T4] Confirm AC-5 and AC-11 remain unchecked in `spec.md` by design and record the reason in the plan's Scope Note cross-reference + - Acceptance: reading `spec.md` confirms the literal strings `- [ ] AC-5:` and `- [ ] AC-11:` are still present (unchanged); `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/ac5-ac11-deferred-note.2026-07-16T15-56.md` created stating AC-5 is a pre-decided contingency not triggered by this plan and AC-11 is an orchestrator-resolved `scope_change` deferred to manual post-merge verification + +### Phase 5 — README documentation deliverable (AC-12) + +- [x] [P5-T1] Add a `* [Dependency updates (Dependabot)](#dependency-updates-dependabot)` entry to `README.md`'s `## Contents` list, inserted immediately after the `* [Configuration & storage](#configuration--storage)` entry and immediately before the `* [Common issues](#common-issues)` entry + - Acceptance: `README.md`'s `## Contents` list shows the new entry in that exact position +- [x] [P5-T2] Insert a new `## Dependency updates (Dependabot)` section into `README.md` immediately after the `## Configuration & storage` section and immediately before the `## Common issues` section, opening with content point 1: Dependabot's NuGet updater cannot independently bump a transitive/indirect dependency beyond what its referencing primary dependency's own manifest supports (documented default ecosystem behavior per GitHub Docs "About Dependabot security updates"), not a mechanism this repo's config invents + - Acceptance: `README.md` contains a `## Dependency updates (Dependabot)` heading positioned between the two named sections, with prose covering content point 1 +- [x] [P5-T3] Add content point 2 to the same section: the `semver-major`-scoped `ignore` rule set (the eight Microsoft `.NET`-runtime-aligned package families) is this repo's defense against a future framework-support drop, adopted because no currently-published version of any referenced package has dropped net481 support (verified 2026-07-16; research §4); minor/patch updates for the same families remain unaffected + - Acceptance: the `## Dependency updates (Dependabot)` section in `README.md` contains prose covering content point 2, naming the eight package families and the semver-major scoping +- [x] [P5-T4] Add content point 3 to the same section: the `directories: ["/*"]` decision and its pre-decided fallback (the literal 16-entry list in `spec.md` Appendix A), to be adopted only if post-merge verification shows under-coverage + - Acceptance: the section contains prose covering content point 3, referencing `spec.md` Appendix A by name +- [x] [P5-T5] Add content point 4 to the same section: a runbook note pointing maintainers to the manual, out-of-toolchain post-merge verification step (spec AC-11) — confirming via the repository's Insights → Dependency graph → Dependabot tab that at least one of the 18 directories is scanned + - Acceptance: the section contains a runbook note naming the Insights → Dependency graph → Dependabot path and referencing AC-11 +- [x] [P5-T6] Check off AC-12 in `spec.md` (`- [ ]` changed to `- [x]`) and the corresponding documentation bullet in `user-story.md` + - Acceptance: `spec.md`'s AC-12 line reads `- [x] AC-12: ...`; `user-story.md`'s matching bullet reads `- [x] ...` + +### Phase 6 — TFM non-modification diff review (AC-10) + +- [x] [P6-T1] Run `git status --porcelain` from the repository root and capture the full output; the porcelain output is expected to include pre-existing unrelated entries (agent-memory drift under `.claude/agent-memory/**` and the feature's own `docs/features/active/2026-07-16-dependabot-net481-support-340/` folder) alongside the two files this feature adds/modifies, and P6-T2's check below is scoped to project/build files, not an exact two-path match + - Acceptance: `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac10-diff-review.2026-07-16T15-56.md` created containing `Timestamp:`, `Command: git status --porcelain`, `EXIT_CODE: 0`, and `Output Summary:` listing the changed-path set +- [x] [P6-T2] Confirm the `git status --porcelain` output from P6-T1 shows `.github/dependabot.yml` (untracked/new) and `README.md` (modified) as changed paths, with no `.csproj`, `.cs`, or other project/build file listed + - Acceptance: `ac10-diff-review.2026-07-16T15-56.md` updated with a `Path check:` line confirming that among the `git status --porcelain` output, the only `.csproj`/`.cs`/other build-project-file changes are none, and that `.github/dependabot.yml` (untracked/new) and `README.md` (modified) are present as changed paths; pre-existing unrelated paths outside this feature's scope (e.g. `.claude/agent-memory/**` and the feature's own `docs/features/active/2026-07-16-dependabot-net481-support-340/` folder) are permitted and must be listed separately as 'pre-existing, out-of-scope' rather than treated as a verification failure +- [x] [P6-T3] Run `git diff --name-only -- "*.csproj"` from the repository root and confirm the command produces no output + - Acceptance: `ac10-diff-review.2026-07-16T15-56.md` updated with `Command: git diff --name-only -- "*.csproj"`, `EXIT_CODE: 0`, `Output Summary: no output (zero .csproj files changed)` — satisfies AC-10 +- [x] [P6-T4] Check off AC-10 in `spec.md` (`- [ ]` changed to `- [x]`) and the corresponding TFM-unchanged bullet in `user-story.md` + - Acceptance: `spec.md`'s AC-10 line reads `- [x] AC-10: ...`; `user-story.md`'s matching bullet reads `- [x] ...` + +### Phase 7 — Final QC: YAML validity and Definition-of-Done reconciliation + +- [x] [P7-T1] Run `pip install --quiet pyyaml` from the repository root to guarantee YAML-parsing tooling is available for the validity check in P7-T2 + - Acceptance: `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/yaml-validity.2026-07-16T15-56.md` created containing `Timestamp:`, `Command: pip install --quiet pyyaml`, `EXIT_CODE: 0`, `Output Summary: pyyaml installed/already satisfied` +- [x] [P7-T2] Run `python -c "import yaml; yaml.safe_load(open('.github/dependabot.yml', encoding='utf-8')); print('DEPENDABOT_YAML_VALID')"` from the repository root and confirm it exits 0 and prints `DEPENDABOT_YAML_VALID` + - Acceptance: `yaml-validity.2026-07-16T15-56.md` updated with `Command: python -c "import yaml; yaml.safe_load(open('.github/dependabot.yml', encoding='utf-8')); print('DEPENDABOT_YAML_VALID')"`, `EXIT_CODE: 0`, `Output Summary: DEPENDABOT_YAML_VALID printed — file parses as valid YAML` — satisfies AC-2's "file parses as valid YAML" clause +- [x] [P7-T3] If P7-T2 fails (non-zero exit or missing `DEPENDABOT_YAML_VALID` output), fix the reported YAML syntax error in `.github/dependabot.yml` and rerun P7-T1 and P7-T2 until both pass in a single pass + - Acceptance: `yaml-validity.2026-07-16T15-56.md`'s final recorded run for P7-T2 shows `EXIT_CODE: 0` and `DEPENDABOT_YAML_VALID` +- [x] [P7-T4] Check off the applicable `spec.md` Definition of Done items: "Acceptance criteria (AC-1 through AC-12 above) documented and mapped to verification steps", "`.github/dependabot.yml` matches every AC in this spec", "`README.md` documentation section added per AC-12", "Pre-merge enumeration evidence (AC-4) recorded", "Diff review confirms no TFM changes (AC-10)", "Post-merge Dependabot scan verification (AC-11) scheduled/tracked as a runbook item", and "No toolchain pass required beyond YAML validity" — changing each `- [ ]` to `- [x]` + - Acceptance: all seven listed `spec.md` Definition of Done lines read `- [x] ...` +- [x] [P7-T5] Record a final plan-completion summary noting AC-5 and AC-11 remain intentionally unchecked (contingency and deferred-manual respectively) while AC-1 through AC-4, AC-6 through AC-10, and AC-12 are checked + - Acceptance: `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/plan-completion-summary.2026-07-16T15-56.md` created listing each AC's final checkbox state (checked/unchecked) matching the state left in `spec.md` + +## Test Plan + +- Unit: not applicable — no C#/production code is added or modified by this feature. +- Integration: not applicable — no runtime code path exists to integration-test; Dependabot's own scheduled scan (AC-11, deferred/manual) is the only integration signal, and it is explicitly out of this plan's execution scope. +- Manual/CLI: + - `Get-ChildItem -Path . -Filter packages.config -Recurse | Select-Object FullName` (Phase 4, AC-4). + - `git status --porcelain` and `git diff --name-only -- "*.csproj"` (Phase 6, AC-10). + - `python -c "import yaml; yaml.safe_load(open('.github/dependabot.yml', encoding='utf-8'))"` (Phase 7, YAML validity). +- Coverage evidence: not applicable — this is a config/documentation-only change with no executable code, so no line/branch coverage baseline or comparison artifact is produced. `spec.md`'s Definition of Done explicitly states no toolchain pass beyond YAML validity applies. + +## Evidence Artifact Index + +All evidence lives under `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/`: +- `baseline/phase0-instructions-read.md` +- `baseline/pre-change-state.2026-07-16T15-56.md` +- `qa-gates/ac2-schema-structure-review.2026-07-16T15-56.md` +- `qa-gates/ac4-packages-config-enumeration.2026-07-16T15-56.md` +- `qa-gates/ac10-diff-review.2026-07-16T15-56.md` +- `qa-gates/yaml-validity.2026-07-16T15-56.md` +- `other/ac5-ac11-deferred-note.2026-07-16T15-56.md` +- `other/plan-completion-summary.2026-07-16T15-56.md` + +## Open Questions / Notes + +- None — `spec.md`'s "Resolved Ambiguities" section closes both residual ambiguities from research (`packages.config` support corroboration path, and `/*` glob-depth decision). No open questions remain for this plan. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/policy-audit.2026-07-16T16-40.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/policy-audit.2026-07-16T16-40.md new file mode 100644 index 000000000..f0e7eb620 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/policy-audit.2026-07-16T16-40.md @@ -0,0 +1,132 @@ +# Policy Audit — dependabot-net481-support (Issue #340) + +- Feature folder: `docs/features/active/2026-07-16-dependabot-net481-support-340/` +- Resolved base branch: `main` +- Merge-base SHA: `1ac990b7ef4b5c2a0db388b3bb792be4c4190838` +- Branch head SHA: `bb669ee938893945d3849ef2a059e93a5c34d102` +- Diff range: `1ac990b7ef4b5c2a0db388b3bb792be4c4190838..bb669ee938893945d3849ef2a059e93a5c34d102` +- Work mode (from `issue.md`): `full-feature` +- Reviewer timestamp: 2026-07-16T16-40 + +## Executive Summary + +This feature adds a single declarative configuration file (`.github/dependabot.yml`) and a documentation section in `README.md`. Independent verification of `git diff --name-only` against the resolved merge-base confirms the branch changes exactly 17 files, all of which are Markdown documentation, agent-memory notes, or the one YAML config file — **zero** `.cs`, `.csproj`, `.ps1`, `.psm1`, `.ts`, `.tsx`, or `.py` files are touched. No C#, PowerShell, TypeScript, or Python coverage gate applies because no file of any of those languages has changed on this branch (verified directly against the diff, not solely against the PR-context summary — see `pr-context-summary-misclassifies-cs` risk noted in reviewer memory, which was checked and did not manifest here). Overall disposition: **PASS**, subject to two intentionally-deferred acceptance criteria (AC-5, AC-11) that are pre-decided contingencies/manual post-merge steps, not defects. + +## Rejected Scope Narrowing + +None detected. The caller instruction ("Execute the full feature-review-workflow SKILL contract end-to-end") did not attempt to narrow scope to a plan/task/phase subset, and no delegation artifact in this feature folder instructed the reviewer to skip a language's coverage check. `plan.2026-07-16T15-56.md`'s "Scope Note (config-only feature)" states that the CSharpier/analyzer/nullable/vstest toolchain does not apply — this statement was independently verified against the actual branch diff (zero `.cs`/`.csproj` files changed) rather than accepted at face value, so it is a factual observation about this diff's content, not an illegitimate narrowing of review scope. + +## 1. Full Branch Diff Verification (independent of PR-context summary) + +Command run: `git diff --name-only 1ac990b7ef4b5c2a0db388b3bb792be4c4190838..bb669ee938893945d3849ef2a059e93a5c34d102` + +Result — 17 changed files, 961 insertions, 0 deletions: + +| Path | Category | +|---|---| +| `.claude/agent-memory/task-researcher/MEMORY.md` | agent-memory (docs) | +| `.claude/agent-memory/task-researcher/project_dependabot_net481_340.md` | agent-memory (docs) | +| `.github/dependabot.yml` | config (YAML) | +| `README.md` | docs | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/phase0-instructions-read.md` | evidence (docs) | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/baseline/pre-change-state.2026-07-16T15-56.md` | evidence (docs) | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/ac5-ac11-deferred-note.2026-07-16T15-56.md` | evidence (docs) | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/other/plan-completion-summary.2026-07-16T15-56.md` | evidence (docs) | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac10-diff-review.2026-07-16T15-56.md` | evidence (docs) | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac2-schema-structure-review.2026-07-16T15-56.md` | evidence (docs) | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/ac4-packages-config-enumeration.2026-07-16T15-56.md` | evidence (docs) | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/qa-gates/yaml-validity.2026-07-16T15-56.md` | evidence (docs) | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/issue.md` | feature doc | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/plan.2026-07-16T15-56.md` | feature doc | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/research/2026-07-16T16-10-dependabot-net481-support-research.md` | feature doc | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/spec.md` | feature doc | +| `docs/features/active/2026-07-16-dependabot-net481-support-340/user-story.md` | feature doc | + +No `.cs`, `.csproj`, `.props`, `.targets`, `.ps1`, `.psm1`, `.ts`, `.tsx`, or `.py` file appears in this list. This was cross-checked against `artifacts/pr_context.summary.txt`'s "Changed files overview" section (which independently reports "Core logic changes: 0 files" and lists the same 10 largest files by delta, all `.md`/`.yml`), and the two sources agree. Per the reviewer-memory note on PR-context summaries occasionally misclassifying C# as docs, this branch was checked directly against `git diff`, not solely against the summary — the direct check confirms the summary's classification is correct in this instance. + +## 2. Coverage Verification (mandatory for every language with changed files) + +| Language | Changed files on branch | Coverage artifact required? | Verdict | +|---|---|---|---| +| TypeScript | 0 | No | **N/A — zero changed `.ts`/`.tsx` files on this branch (verified via `git diff --name-only`)** | +| Python | 0 | No | **N/A — zero changed `.py` files on this branch (verified via `git diff --name-only`)** | +| PowerShell | 0 | No | **N/A — zero changed `.ps1`/`.psm1` files on this branch (verified via `git diff --name-only`)** | +| C# | 0 | No | **N/A — zero changed `.cs`/`.csproj` files on this branch (verified via `git diff --name-only` AND the AC-10 diff-review evidence artifact, which independently confirms `git diff --name-only -- "*.csproj"` produced no output)** | + +Per the coverage-verification contract, `N/A` is an acceptable verdict only for languages with zero changed files on the branch. All four languages have zero changed files here, confirmed by two independent methods (direct `git diff` and the feature's own AC-10 evidence artifact), so no coverage artifact (`coverage/lcov.info`, `artifacts/python/lcov.info`, `artifacts/pester/powershell-coverage.xml`, `artifacts/csharp/coverage.xml`) was required or checked. No language row in this table represents "plan scope only," "out of scope," or "informational only" narrowing — each N/A is a factual zero-changed-file statement, independently verified. + +New/changed-code coverage: not applicable (0%, no measurable code lines added in any covered language). + +## 3. General Code Change Policy (`.claude/rules/general-code-change.md`) + +| Rule area | Verdict | Evidence | +|---|---|---| +| Design principles (simplicity, reusability, extensibility, separation of concerns) | PASS | `.github/dependabot.yml` is a single flat declarative config; `README.md` addition is a documentation-only prose section with no code coupling. | +| Classes/functions/APIs guidance | N/A | No executable code added. | +| Module Rigor Tiers / `quality-tiers.yml` | N/A | No new project added; feature adds no project requiring tier classification. | +| Mandatory toolchain loop (format → lint → type-check → architecture → unit → contract → integration) | N/A | No source code of any covered toolchain language changed. The plan's own Scope Note claim that "no toolchain pass required beyond YAML validity" was independently verified true against the actual diff, not merely accepted. YAML-validity check evidence (`evidence/qa-gates/yaml-validity.2026-07-16T15-56.md`) shows `python -c "import yaml; yaml.safe_load(...)"` exited 0 with `DEPENDABOT_YAML_VALID` — independently reproduced in this review (see Appendix B). | +| File size limit (500 lines, docs exempt) | PASS | Largest changed file is `research/...md` (227 lines); `.github/dependabot.yml` is 62 lines; `plan.2026-07-16T15-56.md` is 166 lines; `spec.md` is 162 lines; `README.md` (whole file, post-change) is 236 lines. All well under 500 lines. Markdown files are explicitly exempt from the limit regardless. | +| Error handling / logging / contracts | N/A | No executable code; Dependabot's own service handles its internal logging (outside this repo's control), documented as such in the added README section. | +| Naming | PASS | YAML keys use the schema's own documented casing (`package-ecosystem`, `open-pull-requests-limit`, etc.); no naming deviation. | +| Public APIs / compatibility | N/A | No public API surface changed. | +| Dependencies | PASS | No new dependency introduced; the feature only configures GitHub's built-in Dependabot service. | +| I/O boundaries / temp files | PASS | No test code added; no temporary files created by any evidence-capture command (`Test-Path`, `Get-ChildItem`, `git status --porcelain`, `python -c "import yaml..."` all operate on real repository state, not scratch files). | + +## 4. General Unit Test Policy (`.claude/rules/general-unit-test.md`) + +**N/A — no test code is added or modified by this feature.** `plan.2026-07-16T15-56.md` Phase 0 (P0-T2) explicitly records this determination, and independent verification of the diff (Section 1 above) confirms no test file of any language changed. No coverage-exclusion, test-location, or determinism-infrastructure rule applies. + +## 5. C# Code Change Policy / C# Unit Test Policy + +**N/A — zero `.cs`/`.csproj`/`.props`/`.targets` files changed on this branch** (verified in Section 1 and independently corroborated by the feature's own AC-10 evidence, `evidence/qa-gates/ac10-diff-review.2026-07-16T15-56.md`, which records `git diff --name-only -- "*.csproj"` producing no output). CSharpier, .NET analyzers, nullable/TreatWarningsAsErrors, and vstest/MSTest/Moq/FluentAssertions requirements do not apply. + +## 6. CI Workflow / Benchmark Baseline Rules + +| Rule | Applicability | Verdict | +|---|---|---| +| `.claude/rules/ci-workflows.md` (deliberately-failing nested `pwsh` command pattern) | N/A | No `.github/workflows/**` file changed on this branch (`git diff --name-only ... -- ".github/workflows/**" ".github/actions/**" "scripts/benchmarks/**"` returned no output). | +| `.claude/rules/benchmark-baselines.md` (runner-environment parity, provenance sidecar) | N/A | No benchmark baseline JSON file changed. | +| `modified-workflow-needs-green-run` (feature-review-workflow policy rule) | N/A — rule does not trigger | Confirmed no path under `.github/workflows/**`, `scripts/benchmarks/**`, or `.github/actions/**` appears in the branch diff. | + +## 7. Evidence Location Compliance + +All evidence artifacts produced by this feature's execution live under the canonical `docs/features/active/2026-07-16-dependabot-net481-support-340/evidence/{baseline,qa-gates,other}/` tree, consistent with `.claude/skills/evidence-and-timestamp-conventions/SKILL.md`. A scan of the full branch diff (Section 1 table) found no file under `artifacts/baselines/`, `artifacts/qa/`, `artifacts/evidence/`, or `artifacts/coverage/`. No `validate_evidence_locations.py` script exists in this repository checkout (`find . -iname "validate_evidence_locations.py"` returned no results), consistent with prior reviewer-memory findings that this validator is not present in TaskMaster; the manual `git diff --name-only` scan is the working substitute and found zero violations. + +**Verdict: PASS.** + +## 8. Tonality Policy + +The added `README.md` section and `.github/dependabot.yml` comments use neutral, factual, technical prose with no hyperbole, humor, or informal phrasing. **Verdict: PASS.** + +## Appendix A — Independent Reproduction Commands + +Commands re-run by this reviewer (not merely accepted from feature evidence) to independently corroborate the executor's claims: + +``` +git diff --name-only 1ac990b7ef4b5c2a0db388b3bb792be4c4190838..bb669ee938893945d3849ef2a059e93a5c34d102 +git diff --stat 1ac990b7ef4b5c2a0db388b3bb792be4c4190838..bb669ee938893945d3849ef2a059e93a5c34d102 +python -c "import yaml; d = yaml.safe_load(open('.github/dependabot.yml', encoding='utf-8')); print('OK'); print(list(d.keys())); print(list(d['updates'][0].keys()))" +grep -n "Dependency updates|## Contents" README.md +grep -n "Dependency updates\|## Contents\|Configuration & storage\|Common issues" README.md +find . -maxdepth 2 -iname "packages.config" +grep -c "semver-minor\|semver-patch" .github/dependabot.yml +grep -c "^ - dependency-name:" .github/dependabot.yml +grep -n "versions:" .github/dependabot.yml +git diff --name-only ..HEAD -- ".github/workflows/**" ".github/actions/**" "scripts/benchmarks/**" +find . -iname "validate_evidence_locations.py" +``` + +Results: YAML parsed successfully with all 6 expected top-level `updates[0]` keys; `README.md` shows the `## Dependency updates (Dependabot)` heading present at the expected position with a matching `## Contents` entry; exactly 18 `packages.config` files found at depth 1 (matches AC-4 evidence, spans the 16 spec-listed directories plus `VBFunctions`/`VBFunctions.Test`); zero `semver-minor`/`semver-patch` occurrences and zero `versions:` keys in the `ignore` list, with exactly 8 `dependency-name` entries (matches AC-6/AC-7); zero workflow/benchmark/action files in the diff; no evidence-location validator script present in this repo. + +## Appendix B — Coverage Comparison Table (required format) + +| Language | Baseline | Post-change | Change | Disposition | Evidence | +|---|---|---|---|---|---| +| TypeScript | N/A (0 changed files) | N/A (0 changed files) | 0 | N/A | `git diff --name-only` — no `.ts`/`.tsx` paths | +| Python | N/A (0 changed files) | N/A (0 changed files) | 0 | N/A | `git diff --name-only` — no `.py` paths | +| PowerShell | N/A (0 changed files) | N/A (0 changed files) | 0 | N/A | `git diff --name-only` — no `.ps1`/`.psm1` paths | +| C# | N/A (0 changed files) | N/A (0 changed files) | 0 | N/A | `git diff --name-only` — no `.cs`/`.csproj` paths; AC-10 evidence corroborates | + +## Overall Disposition + +**PASS.** No policy violation found. Two acceptance criteria (AC-5, AC-11) remain intentionally unchecked as pre-decided contingency/manual post-merge steps; see `feature-audit.2026-07-16T16-40.md` for full AC evaluation. No remediation is required. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/research/2026-07-16T16-10-dependabot-net481-support-research.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/research/2026-07-16T16-10-dependabot-net481-support-research.md new file mode 100644 index 000000000..0147549a1 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/research/2026-07-16T16-10-dependabot-net481-support-research.md @@ -0,0 +1,227 @@ +# Research: Dependabot NuGet Support for a packages.config / net481 Repository (Issue #340) + +- Issue: #340 +- Feature folder: `docs/features/active/2026-07-16-dependabot-net481-support-340/` +- Date: 2026-07-16 +- Scope: Add `.github/dependabot.yml` for the `nuget` ecosystem across 16 `packages.config` project directories, without ever proposing a package version that drops `.NET Framework 4.8`/`4.8.1` support, and without letting transitive/secondary dependencies get bumped independently of what their referencing primary dependency supports. + +## 1. Current State Analysis + +### 1.1 Repository package-manifest inventory + +The repository has no `.github/dependabot.yml` today (confirmed: no such file exists). All 16 project directories are immediate children of the repository root, each with its own `packages.config`: + +`QuickFiler/`, `QuickFiler.Test/`, `SVGControl/`, `SVGControl.Test/`, `Tags/`, `Tags.Test/`, `TaskMaster/`, `TaskMaster.Test/`, `TaskTree/`, `TaskTree.Test/`, `TaskVisualization/`, `TaskVisualization.Test/`, `ToDoModel/`, `ToDoModel.Test/`, `UtilitiesCS/`, `UtilitiesCS.Test/`, `VBFunctions/`, `VBFunctions.Test/`. + +All `packages.config` files declare `targetFramework="net481"` for every `` entry (verified by reading all 18 files — note: `VBFunctions.Test` has no `packages.config` beyond the shared analyzer set; `VBFunctions` only has the analyzer set too). No project has a `packages.lock.json` (`packages.config` has no lockfile concept; NuGet resolves the dependency graph at restore time using each package's own `.nuspec` dependency group for the current TFM). + +Representative package families actually referenced (deduplicated across all 16 files), grouped for the compatibility analysis below: +- Legacy split-BCL packages pinned very low (`System.Buffers 4.6.1`, `System.Memory 4.6.3`, `System.Runtime 4.3.1`, `System.ValueTuple 4.6.2`, etc.) — these are compatibility shims that exist only for pre-.NET-Standard-2.0 consumers; net481 satisfies netstandard2.0 natively so most of these are vestigial but harmless. +- Current `.NET`-runtime-aligned BCL/Extensions packages pinned to `10.0.7` (`Microsoft.Bcl.AsyncInterfaces`, `Microsoft.Bcl.Memory`, `Microsoft.Bcl.TimeProvider`, `Microsoft.Extensions.Configuration*`, `Microsoft.Extensions.DependencyInjection*`, `Microsoft.Extensions.Logging*`, `Microsoft.Extensions.Options*`, `Microsoft.Extensions.Hosting.Abstractions`, `System.Text.Json`, `System.Drawing.Common`, `System.Collections.Immutable`, `System.Diagnostics.DiagnosticSource`, `System.Formats.Asn1`, `System.IO.Pipelines`, `System.Memory.Data`, `System.Reflection.Metadata`, `System.Security.Cryptography.ProtectedData`, `System.Text.Encodings.Web`, `System.CodeDom`, `System.Numerics.Tensors`, `System.Threading.Tasks.Dataflow`, `System.Text.Encoding.CodePages`, `System.Net.Http.WinHttpHandler`). +- Test-only packages (`MSTest.TestFramework`/`TestAdapter`/`Analyzers` `4.2.2`, `Moq 4.20.72`/`4.20.69`, `FluentAssertions 8.9.0`/`6.12.0`, `Castle.Core 5.2.1`/`5.1.1`, `Microsoft.Testing.Platform*` `2.2.2`, `Microsoft.TestPlatform.*` `18.5.1`). +- Domain/data libraries (`Apache.Arrow`/`Apache.Arrow.Scalars 23.0.0`, `Deedle 3.0.0`, `FSharp.Core 11.0.100`, `Microsoft.Data.Analysis 0.23.0`, `Microsoft.ML`/`Microsoft.ML.DataView`/`Microsoft.ML.CpuMath 5.0.0`). +- Graph/identity/telemetry (`Microsoft.Graph 5.105.0`, `Microsoft.Graph.Core 4.0.1`, `Microsoft.Identity.Client 4.84.0`, `Microsoft.IdentityModel.* 8.18.0`, `Azure.Core 1.55.0`, `Azure.Monitor.OpenTelemetry.Exporter 1.8.0`, `Microsoft.ApplicationInsights 3.1.1`, `OpenTelemetry* 1.15.3`). +- UI/rendering (`ObjectListView.Official 2.9.1`, `Svg 3.4.7`, `ExCSS 4.3.1`, `Fizzler 1.3.1`, `AngleSharp 1.4.0`, `Microsoft.Web.WebView2 1.0.3912.50`). +- Misc (`log4net 3.3.1`, `log4net.Ext.Json 3.0.3`, `Newtonsoft.Json 13.0.4`, `Mono.Cecil 0.11.6`, `Mono.Reflection 2.0.0`, `Tesseract 5.2.0`, `C.math.NET 1.1`, `Generic.Math 1.0.2`, `Std.UriTemplate 2.0.8`). +- Repo-wide analyzer set present in every single `packages.config` including test-only folders: `Meziantou.Analyzer 3.0.101`, `SonarAnalyzer.CSharp 10.27.0.140913`, `Roslynator.Analyzers 4.15.0`, `AsyncFixer 2.1.0`, `Microsoft.CodeAnalysis.BannedApiAnalyzers 3.3.4` (all `developmentDependency="true"`). + +### 1.2 Toolchain constraint + +Per `CLAUDE.md`, C# code changes must run `csharpier`/analyzer/nullable/`vstest.console.exe` toolchain steps, but a `.github/dependabot.yml` file is YAML, not C# — it is not subject to that toolchain. It is subject to the `ci-workflows.md` and `benchmark-baselines.md` rules only insofar as it might touch CI workflow `run:` steps, which it does not (Dependabot config is not a GitHub Actions workflow file). + +## 2. Dependabot `nuget` Ecosystem + `packages.config` Support + +**Citation:** GitHub Docs, "Dependabot supported ecosystems and repositories" (`https://docs.github.com/en/code-security/dependabot/ecosystems-supported-by-dependabot/supported-ecosystems-and-repositories`) lists a table row: package manager "NuGet CLI", YAML value `nuget`, supported NuGet versions "<=6.12.0", with Version updates ✓, Security updates ✓, Private repositories ✓, Private registries ✗, Vendoring ✗. This confirms the `nuget` ecosystem is a first-class, version-update-capable ecosystem. + +**On `packages.config` specifically:** the GitHub Docs pages fetched during this research session (`about-dependabot-version-updates`, `supported-ecosystems-and-repositories`, `dependabot-file-testing`) do not spell out the manifest-file-level detail (`packages.config` vs `PackageReference`) in the text made available to this research session — several candidate per-ecosystem detail URLs returned HTTP 404, and the general pages only state NuGet is supported at the ecosystem level. The strongest corroborating evidence found is `dependabot/dependabot-core` issue #11100, titled "NuGet with packages.config has issues when MSBuild Pkg variables are used" (`https://github.com/dependabot/dependabot-core/issues/11100`), whose reported symptom is "Discovery works as expected, but not `update`" — i.e., the bug is scoped to a specific edge case (MSBuild property variables embedded in `.csproj` alongside a `packages.config`), which presupposes that Dependabot's NuGet updater routinely discovers and parses `packages.config` files as a normal, supported manifest format; the issue would not describe a "discovery works" baseline if `packages.config` were unsupported. This is treated as corroborating, not primary, documentation evidence. + +**Practical implication:** proceed on the basis that `packages.config` is a supported NuGet manifest format (per the above), but recommend the atomic-planner schedule an early validation task (item under Testing Implications, §5) that opens the config in a disposable branch and confirms Dependabot's "Insights → Dependency graph → Dependabot" tooling or a scheduled run actually discovers dependencies in at least one of this repo's `packages.config` files before treating the feature as fully proven — since the citation trail for the manifest-format claim is corroborating rather than a verbatim primary-doc quote. + +### Directory scoping for 16 project folders + +**Citation:** GitHub Docs, dependabot.yml options reference (`https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference`): `directory` is described as the required option to "define the location of the package manifests for each package manager… Without this information Dependabot cannot create pull requests for version updates," and single vs. multiple locations are handled via `directory` (single) or `directories` (multiple). Verbatim: "The `directories` key supports globbing and the wildcard character `*`. These features are not supported by the `directory` key." + +Because every `packages.config` project folder in this repo is an **immediate child of the repository root** (no nested subfolders), a single `updates:` block using: + +```yaml +directories: + - "/*" +``` + +is the most concise way to cover all 16 folders in one ecosystem entry, provided Dependabot's glob semantics treat `*` as matching one path segment under `/` (the documentation excerpt available in this research session confirms globbing/wildcard support but does not give a worked example distinguishing single-segment vs. recursive matching). Given this residual ambiguity, the config sketch in §6 below uses the wildcard form as the primary recommendation but the research explicitly flags that the atomic-planner/executor should verify (via a Dependabot "Insights" dry run or the "check the config" schema validator) that `/*` produces PRs against all 16 directories and not zero or duplicate coverage before relying on it as final. An explicit fallback is to enumerate all 16 directories literally under a single `directories:` list, which removes the glob-semantics risk entirely at the cost of a longer, more maintenance-prone file. + +## 3. Transitive/Secondary Dependency Handling — Is This Already Dependabot's Default Behavior? + +**Primary citation:** GitHub Docs, "About Dependabot security updates" (`https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates`): "For npm, Dependabot will raise a pull request to update an explicitly defined dependency to a secure version, even if it means updating the parent dependency or dependencies, or even removing a sub-dependency that is no longer needed by the parent." Immediately contrasted: **"For other ecosystems, Dependabot is unable to update an indirect or transitive dependency if it would also require an update to the parent dependency."** + +This is the load-bearing citation for the feature's core constraint. NuGet is one of the "other ecosystems" referenced by that sentence (npm is called out as the sole exception because of its lockfile-graph-rewrite capability). Read together with the fact that `packages.config` has **no lockfile at all** — every `` entry in `packages.config` is itself a direct/primary reference resolved against the live NuGet feed at restore time, with NuGet's own `.nuspec` dependency groups determining what transitive versions get pulled in — the practical consequence for this repository is: + +- Dependabot version-update PRs for this repo's `nuget` ecosystem entries will only ever propose a version bump for a package **explicitly listed** in one of the 16 `packages.config` files (a "primary" dependency in the issue's terminology). It cannot independently propose a bump to a package that is *only* a transitive dependency of one of those listed packages, because `packages.config` records no transitive entries for Dependabot to discover or target. +- When Dependabot bumps a primary dependency, NuGet's own dependency-resolution engine (not Dependabot) determines which transitive package versions the new primary version pulls in; Dependabot itself does not open a second, independent PR that bumps a transitive package beyond what the just-upgraded primary's `.nuspec` declares as its own dependency range. +- Consequently, **the acceptance criterion "secondary dependencies must never be bumped independently of, or beyond what, their referencing primary dependency actually supports" is already Dependabot's default behavior for the `nuget` ecosystem** (per the security-updates documentation, which describes ecosystem capability, not just security-update scope — the underlying mechanism it describes is that NuGet lacks the lockfile-rewrite capability npm has, which is a property of the ecosystem and applies identically whether the update is triggered by a security advisory or a scheduled version check). This repo's `dependabot.yml` does not need to (and cannot, via any documented key) add an explicit primitive that "enforces" this; the correct scope of this feature's config is the **TFM-compatibility ignore rules** in §4, and the correct scope of the feature's *documentation* deliverable (the acceptance criterion about "how this repo's config reinforces that for framework compatibility") is to **record this default-behavior finding** rather than encode a redundant mechanism, since no such mechanism exists in the schema. + +## 4. Ignore Rules and Version-Range Syntax + +**Citation:** GitHub Docs, dependabot.yml options reference: +- `ignore` → `dependency-name`: "Ignore updates for dependencies with matching names, optionally using `*` to match zero or more characters." +- `ignore` → `versions`: "Ignore specific versions or ranges of versions." +- `ignore` → `update-types`: "Ignore updates to one or more semantic versioning levels. Supported values: `version-update:semver-patch`, `version-update:semver-minor`, and `version-update:semver-major`." +- NuGet version-range syntax example given in the docs: `7.*` (i.e., NuGet's native floating-version wildcard syntax, not semver caret/tilde ranges — the docs give ecosystem-specific examples: `^1.0.0` for npm, `~> 2.0` for Bundler, `7.*` for NuGet, `[1.4,)` for Maven). +- `versioning-strategy`: allowed values enumerated by the docs are `auto`, `increase`, `increase-if-necessary`, `lockfile-only`, `widen`. The full prose definition of each value could not be retrieved verbatim in this research session (the reference page exceeded the fetch tool's extraction window before reaching that subsection in two separate attempts). Based on the enumerated value names and this repository's manifest shape: `lockfile-only` is a no-op for this repo's `nuget` entries because `packages.config` has no separate lockfile file for Dependabot to update independently of the manifest — the "manifest" *is* the pinned-version record. The practical default (`auto`) should be left in place; there is no lockfile-only mode to exploit here, and no separate `versioning-strategy` override is needed to satisfy the TFM constraint (that constraint is enforced entirely through `ignore` rules, not through versioning-strategy). + +### Candidate ignore rules for TFM-incompatible version ceilings + +This research checked NuGet.org's package "Frameworks" compatibility panel (which lists explicit target-framework monikers per published version) for every distinct package family referenced across the repo's 16 `packages.config` files, prioritizing packages with a plausible history of dropping legacy-framework support (BCL-adjacent Microsoft packages aligned to `.NET` runtime version numbers, ML/data libraries, and third-party UI/rendering libraries). Findings, each independently verified via NuGet.org's package page for the cited version: + +| Package | Version checked | Frameworks panel (verified) | Finding | +|---|---|---|---| +| `Microsoft.Extensions.Hosting.Abstractions` | `10.0.7` | `.NET 8.0`, `.NET Standard 2.0`, `.NET Framework 4.6.2` | net481 satisfied via `.NETFramework 4.6.2` and `netstandard2.0`; no drop | +| `System.Text.Json` | `10.0.7` | `.NET 8.0`, `.NET Standard 2.0`, `.NET Framework 4.6.2` | No drop | +| `System.Drawing.Common` | `10.0.7` | `.NETFramework 4.6.2`, `.NETStandard 2.0`, plus net8.0/9.0/10.0 | No drop | +| `Apache.Arrow` / `Apache.Arrow.Scalars` | `23.0.0` | `.NET 8.0`, `.NET Standard 2.0`, `.NET Framework 4.6.2` | No drop | +| `Microsoft.ML` / `Microsoft.ML.DataView` | `5.0.0` | `.NET Standard 2.0` explicitly listed; net461–net481 shown as computed-compatible | No drop at the version pinned in-repo | +| `Microsoft.Graph` | `5.105.0` (in-repo) and `6.2.0` (latest) | `5.105.0`: `.NET Standard 2.0`/`2.1`, `net5.0`; `6.2.0`: `.NET 8.0`, `.NET Standard 2.0`/`2.1`, `net10.0` | No explicit `.NETFramework` TFM listed at either version, but `netstandard2.0` is present at both — net481 consumes netstandard2.0-only packages via the .NET Framework/netstandard2.0 compatibility shim (the same mechanism already relied on by most `Microsoft.Extensions.*` entries already pinned in this repo's own `packages.config` files), so this is not treated as a drop | +| `System.Reactive` | `6.1.0` (in-repo, latest stable) | `.NET Framework 4.7.2`, `.NET Standard 2.0`, `net6.0` | No drop; a `7.0.0-rc.1` prerelease exists but is not the resolved stable version | +| `Svg` | `3.4.7` (in-repo, latest) | Explicit list includes `.NET Framework 4.6.2`, `4.7.2`, **`4.8.1`** | No drop; net481 explicitly certified | +| `FluentAssertions` | `8.9.0`/`8.10.0` (in-repo/latest) | `.NET 6.0`, `.NET Standard 2.0`, `.NET Framework 4.7` | No drop (net481 ≥ net47) | +| `AngleSharp` | `1.5.2` (latest; repo pins `1.4.0`) | `.NET 8.0`, `.NET Standard 2.0`, `.NET Framework 4.6.2` | No drop | +| `FSharp.Core` | `10.1.302` (latest; repo pins `11.0.100`* — note repo's pinned version number is higher than the "latest" this research observed, which may reflect a newer publish between check and repo edit) | `.NET Standard 2.0`/`2.1` only listed explicitly | No `.NETFramework` TFM shown, but netstandard2.0 covers net481 via the compat shim as above | +| `Microsoft.ApplicationInsights` | `3.1.2` (latest; repo pins `3.1.1`) | `.NET 8.0`, `.NET Standard 2.0`, `.NET Framework 4.6.2` | No drop; older `2.2x` versions are marked deprecated on NuGet.org but deprecation is unrelated to TFM support | +| `Microsoft.Data.Analysis` | `0.23.0` (in-repo, latest) | `.NET 8.0`, `.NET Standard 2.0` explicit | No drop | +| `ObjectListView.Official` | `2.9.1` (in-repo, latest — last published 2016-05-05) | `.NET Framework 2.0` (net20) baseline, net35 through net481 computed-compatible | No newer version exists at all; no upgrade risk from this package (it is effectively unmaintained upstream) | + +**Conclusion for §4:** no package currently referenced by this repository's `packages.config` files has a **currently-published** NuGet version whose Frameworks panel shows it dropped `.NET Framework`/`net48`/`net481` support outright (i.e., ships only `net6.0`+/`net8.0`+ TFMs with no `netstandard2.0` or `.NETFramework` target at all). This is a verified, not assumed, finding — every package family in the inventory was checked against its actual latest-published NuGet.org Frameworks panel. Recording a set of `ignore` rules for hypothetical "known-bad" version lines that do not exist would fail the "ground all findings in verified evidence" principle. Two responsible options follow from this: + +1. **Do not add speculative per-package `ignore: versions` ranges with no evidentiary basis.** An `ignore` rule with no known dropped-version boundary to reference is either a no-op (harmless but purposeless) or, if scoped incorrectly, could itself become the "overly broad ignore suppressing legitimate patches" risk the issue explicitly warns against. +2. **Add a narrow, mechanism-level safety net instead of fabricated version ceilings**, using two documented, defensible levers: + - `ignore` → `update-types: ["version-update:semver-major"]` scoped to the handful of packages in this repo whose *ecosystem-level* multi-targeting pattern (net8.0/net9.0/net10.0 alongside net462/netstandard2.0) shows Microsoft actively adding new net-N.0-only surface area with each release, so a **major**-version bump is the point at which a framework-support drop would first appear, per this research's observed pattern of Microsoft's own release cadence (`Microsoft.Extensions.*`, `System.Text.Json`, `System.Drawing.Common`, `Microsoft.Graph`, `Apache.Arrow`, `Microsoft.Data.Analysis`, `Microsoft.ML*`, `System.Numerics.Tensors`-family packages). This converts an otherwise-manual "recheck the Frameworks panel before merging" review step into an automatic gate: major bumps for these packages stop arriving as auto-mergeable minor/patch noise and instead require a human (or a future research pass) to re-verify the Frameworks panel for the new major before approving. + - Retain **minor/patch** auto-updates for the same packages, since this research found no evidence that any dropped-framework release occurred as a minor/patch bump in this ecosystem (Microsoft's public compatibility promise for these package families is that minor/patch releases do not remove supported TFMs; only major bumps have historically changed a package's TFM list). + - This scoped `semver-major` `ignore` should be applied to the Microsoft-aligned, `.NET`-runtime-versioned package families listed above (these are the packages whose upstream release cadence is coupled to `.NET`'s own yearly major-version train, which is the only observed pattern in this repo's dependency set that could plausibly produce a future framework-support drop). + +**Rejected alternative:** encoding invented version-ceiling numbers (e.g., "ignore Microsoft.Graph >= 7.0.0") was rejected because no such version exists yet and no release-notes evidence supports picking any particular number as the boundary; a `semver-major` `update-types` ignore is self-adjusting and does not require guessing a future version number. + +## 5. Grouping / Scheduling Recommendations + +**Citation:** GitHub Docs, dependabot.yml options reference: +- `groups`: "Define rules to create one or more sets of dependencies managed by a package manager, to group updates into fewer, targeted pull requests." Schema includes `patterns`/`exclude-patterns` (wildcard `*`), `update-types` (`patch`, `minor`, `major`), `dependency-type` (`development`/`production`), `applies-to` (`version-updates` or `security-updates`), and `group-by: dependency-name` (to group the same dependency's updates across multiple `directories`). +- `schedule.interval`: `daily`, `weekly`, `monthly`, `quarterly`, `semiannually`, `yearly`, or `cron`. +- `open-pull-requests-limit`: "Change the limit on the maximum number of pull requests for version updates open at any time." Default is five; setting it to `0` temporarily disables version updates for that ecosystem entry. + +**Implication for 16 directories:** without grouping, the same shared package (e.g. `log4net`, appearing in most of the 16 `packages.config` files) would generate a separate PR per directory per package — a combinatorial PR-volume problem. The `group-by: dependency-name` key exists specifically to collapse a dependency shared across multiple `directories` entries into one PR. Recommend: +- One `groups` bucket per broad category (e.g., `test-frameworks`, `microsoft-extensions`, `analyzers-dev-deps`, `everything-else`) using `patterns` wildcards, each with `group-by: dependency-name` so the same package is not duplicated 16 times across directories. +- `schedule.interval: weekly` (daily is unnecessary PR churn for a manually-reviewed legacy VSTO add-in; weekly balances currency against reviewer load). +- `open-pull-requests-limit` set modestly (e.g., 10) given the grouping already collapses most volume; without it the default of 5 could starve some groups. + +## 6. Draft `.github/dependabot.yml` Sketch (illustrative only, not final) + +```yaml +version: 2 +updates: + - package-ecosystem: "nuget" + directories: + - "/*" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + groups: + analyzers-dev-deps: + patterns: + - "Meziantou.Analyzer" + - "SonarAnalyzer.CSharp" + - "Roslynator.Analyzers" + - "AsyncFixer" + - "Microsoft.CodeAnalysis.BannedApiAnalyzers" + group-by: "dependency-name" + test-frameworks: + patterns: + - "MSTest.*" + - "Moq" + - "FluentAssertions" + - "Castle.Core" + - "Microsoft.Testing.*" + - "Microsoft.TestPlatform.*" + group-by: "dependency-name" + microsoft-extensions-and-bcl: + patterns: + - "Microsoft.Extensions.*" + - "Microsoft.Bcl.*" + - "System.*" + group-by: "dependency-name" + graph-identity-telemetry: + patterns: + - "Microsoft.Graph*" + - "Microsoft.Identity.*" + - "Microsoft.IdentityModel.*" + - "Azure.*" + - "OpenTelemetry*" + - "Microsoft.ApplicationInsights" + group-by: "dependency-name" + ignore: + # Major-version bumps for Microsoft's .NET-runtime-aligned package families are + # the only observed point at which supported TFMs (net462/netstandard2.0) have + # historically changed; gate major bumps behind manual review rather than + # guessing an unverified version-ceiling number (see research §4). + - dependency-name: "Microsoft.Extensions.*" + update-types: ["version-update:semver-major"] + - dependency-name: "Microsoft.Bcl.*" + update-types: ["version-update:semver-major"] + - dependency-name: "System.Text.Json" + update-types: ["version-update:semver-major"] + - dependency-name: "System.Drawing.Common" + update-types: ["version-update:semver-major"] + - dependency-name: "Microsoft.Graph*" + update-types: ["version-update:semver-major"] + - dependency-name: "Apache.Arrow*" + update-types: ["version-update:semver-major"] + - dependency-name: "Microsoft.Data.Analysis" + update-types: ["version-update:semver-major"] + - dependency-name: "Microsoft.ML*" + update-types: ["version-update:semver-major"] +``` + +This sketch is illustrative for the atomic-planner; it is not a final, schema-validated artifact. The planner must decide the exact `groups`/`ignore` package-name patterns against the full inventory in §1.1, and must validate the file against the Dependabot v2 schema before merge (per the feature's own acceptance criteria). + +## 7. Behavior Semantics (Success / Failure / Ordering) + +- **Success:** a scheduled Dependabot run against this repo's default branch opens (at most `open-pull-requests-limit`) grouped PRs, each proposing a version bump for one or more directly-referenced packages in one or more of the 16 `packages.config` files, where the proposed version's NuGet Frameworks panel still includes `net462`/`netstandard2.0` (or an explicit `net48`/`net481` TFM). No PR ever changes a project's TFM (`` in the `.csproj`) — Dependabot has no key that touches TFMs; this is enforced structurally by the ecosystem's scope (it only rewrites `` entries in `packages.config` and, for `PackageReference` projects, `` in `.csproj`, never ``). +- **Failure/edge case — major-version framework drop:** if a future major version of a gated package (§4's `ignore` list) drops `netstandard2.0`/`net46x` support, the `semver-major` ignore rule prevents Dependabot from proposing that version at all; the package remains pinned until a maintainer removes or narrows the ignore rule after confirming the new major is still net481-compatible. +- **Failure/edge case — transitive-only vulnerability:** if a security advisory affects a package that is only a transitive dependency of one of the 16 files' direct references, and the direct reference does not have a fixed version available, no PR is possible for the `nuget` ecosystem in this repo (per §3's citation) — this is expected/documented Dependabot behavior, not a config defect. +- **Ordering:** Dependabot processes each `directories` entry independently per scheduled run; `groups` with `group-by: dependency-name` deduplicate the same package's proposed bump across the 16 directories into one PR rather than 16. + +## 8. Requirements Mapping + +| Acceptance criterion (from issue.md) | Design element | +|---|---| +| `.github/dependabot.yml` exists, schema-valid, declares `nuget` ecosystem | §6 sketch; final file must pass Dependabot's YAML schema validation (recommend a config-only PR that GitHub's own dependabot.yml linter/Insights UI validates post-merge, or `pwsh`/Python-based YAML schema check if one exists in-repo) | +| Covers every project directory with a `packages.config` | `directories: ["/*"]` (primary) or explicit 16-item list (fallback if glob-depth semantics prove wrong — verify per §2's flagged caveat) | +| Explicit `ignore` rules preventing net48/net481-incompatible upgrades | §4's `semver-major`-scoped `ignore` entries for the Microsoft `.NET`-runtime-aligned package families; no fabricated version-number ceilings (none verified to exist) | +| Documentation records that Dependabot doesn't independently bump transitives beyond primary support | §3 — this is the citation-backed default-behavior explanation to place in the feature's docs/spec, not a new config mechanism | +| No TFM changed | Structural — Dependabot's `nuget` ecosystem has no key that edits ``; nothing in §6's sketch touches `.csproj` TFM elements | + +## 9. Testing Implications + +- No unit/integration test framework applies to a static YAML config file; this repo's MSTest/Moq/FluentAssertions policy is out of scope for this artifact type. +- Recommended verification steps (schema/behavioral, not unit tests): + 1. YAML schema validation of the final `.github/dependabot.yml` (GitHub validates on push; a local `yamllint`/JSON-schema check beforehand is a reasonable pre-merge gate if the repo has one available — none currently found in this repo's tooling). + 2. After merge, confirm via the repository's **Insights → Dependency graph → Dependabot** tab (or the "Recent update jobs" log) that at least one of the 16 directories is actually scanned and produces a dependency list — this closes the residual "corroborating, not primary, evidence" gap noted in §2 for `packages.config` support. + 3. Spot-check the first few real PRs Dependabot opens against the `ignore`/`groups` rules to confirm grouping collapses duplicate cross-directory bumps as expected (§5), and that no PR proposes a version whose Frameworks panel excludes net462/netstandard2.0/net481. +- This verification work belongs to the atomic-executor/atomic-planner as post-merge acceptance-criteria checks, not to this research artifact. + +## Automation Feasibility + +This entire feature — authoring `.github/dependabot.yml`, informed by the documentation and package-compatibility research above — is achievable purely through file changes committed to the repository. No third-party UI interaction (no Azure portal, no NuGet.org account actions) is required to author or merge the file. + +One nuance surfaced during this research and reported here for completeness rather than assumed away: GitHub's own documentation on enabling Dependabot version updates gives two consistent statements that are easy to conflate. The authoritative one — "You enable Dependabot version updates by committing a `dependabot.yml` configuration file to your repository" (GitHub Docs, "Configuring Dependabot version updates") — supports the assumption in this feature's delegation prompt: committing the file to the default branch is what enables the ecosystem's scheduled runs, and this is a file change, not a manual toggle. A separate, UI-facing description ("Settings → Code security and analysis → next to Dependabot version updates, click Enable") describes GitHub's **alternative, UI-generated path** for repositories that don't already have a hand-authored file — clicking that button is how the Settings page *creates* a starter `dependabot.yml` for you; it is not documented as a second, mandatory step required after a hand-authored file has already been committed via a normal PR. Because this research session's page-fetch tooling could not retrieve a single unambiguous verbatim passage resolving this distinction beyond doubt, the recommendation is: after merging the hand-authored file, do a zero-effort visual check of the repository's own **Settings → Code security and analysis** page to confirm the "Dependabot version updates" row shows an enabled/configured state rather than an "Enable" call-to-action. This check is a read-only confirmation of GitHub's own automatic detection of the merged file, not a manual configuration step performed in a third-party system, and does not change the conclusion that the feature is fully achievable via file changes in this repo. + +Security-update alerts (a separate, unrelated Dependabot capability from version updates) depend on the repository's Dependabot alerts setting, which is out of scope for this file-based change, as the delegation prompt already correctly notes. + +## Sources Cited + +- GitHub Docs — Dependabot supported ecosystems and repositories: `https://docs.github.com/en/code-security/dependabot/ecosystems-supported-by-dependabot/supported-ecosystems-and-repositories` +- GitHub Docs — Dependabot options reference (`ignore`, `groups`, `directory`/`directories`, `schedule.interval`, `open-pull-requests-limit`, `versioning-strategy` value enumeration): `https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference` +- GitHub Docs — About Dependabot security updates (transitive-dependency capability statement): `https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates` +- GitHub Docs — Configuring Dependabot version updates (enabling statement): `https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates` +- GitHub Docs — Dependabot quickstart guide (Settings → Enable button description): `https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide` and `https://docs.github.com/en/code-security/getting-started/quickstart-for-securing-your-repository` +- `dependabot/dependabot-core` issue #11100 (packages.config discovery corroboration): `https://github.com/dependabot/dependabot-core/issues/11100` +- NuGet.org package pages (Frameworks compatibility panels, fetched per package/version as tabulated in §4): `Microsoft.Extensions.Hosting.Abstractions`, `System.Text.Json`, `System.Drawing.Common`, `Apache.Arrow`, `Microsoft.ML`, `Microsoft.Graph`, `System.Reactive`, `Svg`, `FluentAssertions`, `AngleSharp`, `FSharp.Core`, `Microsoft.ApplicationInsights`, `Microsoft.Data.Analysis`, `ObjectListView.Official`, `System.Numerics.Tensors`. +- Repository files read directly: all 16 `packages.config` files under the repo root's project directories; `docs/features/active/2026-07-16-dependabot-net481-support-340/issue.md` and `spec.md`. diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/spec.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/spec.md new file mode 100644 index 000000000..afb78ed13 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/spec.md @@ -0,0 +1,162 @@ +# dependabot-net481-support — Spec + +- **Issue:** #340 +- **Parent (optional):** none +- **Owner:** drmoisan +- **Last Updated:** 2026-07-16 +- **Status:** Draft +- **Version:** 0.2 + +## Overview + +The repository has no automated dependency-update tooling. NuGet package versions across all 16 `packages.config`-based project directories are updated manually, so known-vulnerable or stale dependency versions can persist unnoticed. This spec authorizes a `.github/dependabot.yml` configuration that enables the `nuget` package ecosystem for the whole repository, incorporates a documented, non-fabricated safety net against `.NET Framework 4.8.1` (`net481`) incompatibility, and records the rationale in a repository-level documentation section. Findings are taken from `research/2026-07-16T16-10-dependabot-net481-support-research.md` and are treated as the authoritative technical basis; where research left a residual ambiguity, this spec makes the final decision (see "Resolved Ambiguities" below). + +## Behavior + +Add a `.github/dependabot.yml` configuration that enables the `nuget` package ecosystem for this repository. Because every production project targets `.NET Framework 4.8.1` (a framework line, not a package, so it is not itself a Dependabot-managed dependency), the configuration must not propose NuGet package versions that drop support for `.NET Framework`/`net48`/`net481` compatibility. Because Dependabot's NuGet updater is documented to be unable to update an indirect/transitive dependency independently of its parent (GitHub Docs, "About Dependabot security updates" — this is stated as ecosystem-level behavior, not merely a security-update-path detail, and NuGet is one of the "other ecosystems" contrasted against npm's lockfile-rewrite capability), and `packages.config` carries no lockfile of its own, this constraint is **already satisfied by Dependabot's documented default behavior** for this repo. The feature's job is therefore two-fold: (1) author a schema-correct config that covers all 16 project directories with sensible grouping/scheduling, and (2) add a `semver-major`-scoped `ignore` safety net plus documentation, rather than inventing a config primitive that does not exist in the Dependabot schema. + +### Directory inventory (from research §1.1) + +All 16 `packages.config`-bearing project directories are immediate children of the repository root: + +`QuickFiler`, `QuickFiler.Test`, `SVGControl`, `SVGControl.Test`, `Tags`, `Tags.Test`, `TaskMaster`, `TaskMaster.Test`, `TaskTree`, `TaskTree.Test`, `TaskVisualization`, `TaskVisualization.Test`, `ToDoModel`, `ToDoModel.Test`, `UtilitiesCS`, `UtilitiesCS.Test`. + +`VBFunctions` and `VBFunctions.Test` also exist as sibling directories and each carry a `packages.config` containing only the shared analyzer/dev-dependency set (no product package pins). They are swept up by the same root-level glob at no additional config cost and require no dedicated `groups`/`ignore` entries beyond the shared `analyzers-dev-deps` group already covering the analyzer set present in every directory. + +No project has a `packages.lock.json`; `packages.config` has no lockfile concept — NuGet resolves the dependency graph at restore time from each package's own `.nuspec` dependency group for the current TFM. + +## Resolved Ambiguities + +Research flagged two residual ambiguities. Both are resolved here as final decisions, not left open for the atomic-planner: + +1. **`packages.config` manifest-format support is corroborating, not primary-source verbatim.** Decision: proceed on the basis that `packages.config` is a supported NuGet manifest format for Dependabot version updates (research §2), and require the post-merge manual verification in AC-11 as the closing, authoritative confirmation. This is not a blocking condition on the initial merge (the config is still committed and enabled), but the feature is not considered fully verified until AC-11 passes. +2. **`/*` glob-depth semantics for `directories`.** Decision: ship `directories: ["/*"]` as the final, primary mechanism (not a placeholder) because every packages.config-bearing directory is an immediate child of the repository root — a single-segment wildcard is the documented use case (GitHub Docs: "The `directories` key supports globbing and the wildcard character `*`"). A concrete, pre-decided fallback is defined in AC-5: if AC-11's post-merge check shows fewer than the expected directory count scanned, the config is corrected in a follow-up commit to the literal enumerated `directories:` list in Appendix A, with no other resolution accepted. + +## Inputs / Outputs + +- Inputs: none (no CLI flags, no environment variables; this is a declarative configuration file consumed by GitHub's Dependabot service after merge to the default branch). +- Outputs: + - `.github/dependabot.yml` (new file). + - A new `## Dependency updates (Dependabot)` section in `README.md` (documentation deliverable — see "Documentation Deliverable" below). +- Config keys and defaults: `package-ecosystem: "nuget"`, `directories: ["/*"]`, `schedule.interval: "weekly"`, `open-pull-requests-limit: 10`, `groups` (four buckets, see below), `ignore` (semver-major-scoped entries, see below). +- Versioning or backward-compatibility constraints: none — this is an additive, config-only change with no runtime or public-API surface. Reverting the file re-disables scheduled Dependabot runs for this ecosystem with no other side effects. + +## API / CLI Surface + +Not applicable. `.github/dependabot.yml` has no CLI/API of its own; its "contract" is the Dependabot v2 configuration schema documented at GitHub Docs' dependabot.yml options reference. The relevant keys and their documented semantics (verified in research §2, §4, §5) are: + +- `package-ecosystem: "nuget"` — enables the NuGet ecosystem (GitHub Docs table confirms Version updates: supported). +- `directories: ["/*"]` — scopes the ecosystem entry to every immediate-child directory (see Resolved Ambiguities #2). +- `ignore` → `dependency-name` (wildcard-capable) + `update-types` — suppresses specific semantic-version-level updates for named package patterns. +- `groups` → `patterns` + `group-by: "dependency-name"` — collapses a shared package's update across multiple `directories` entries into one PR instead of 16. +- `schedule.interval` — run cadence. +- `open-pull-requests-limit` — concurrent open-PR cap. + +## Data & State + +- Data transformations and invariants: none in the traditional sense — no data is read, transformed, or persisted by this repository's own code. The only "state change" is that GitHub's Dependabot service begins reading `.github/dependabot.yml` from the default branch and scheduling scans/PRs against it. +- Caching or persistence details: not applicable. +- Migration or backfill requirements: none. + +## Constraints & Risks + +- All projects use `packages.config`, not `PackageReference`. Dependabot's `nuget` ecosystem support for this manifest format is corroborated (not verbatim-primary-sourced) per research §2; the residual gap is closed by the post-merge AC-11 verification, not by blocking the merge. +- `.NET Framework 4.8.1` is fixed; the repository must not receive PRs proposing dependency versions that require `.NET`/`.NET Core`/newer-`net4x`-only TFMs. +- Dependabot has no native "TFM-aware ignore" primitive. Per research §4, no currently-published version of any package referenced in this repo's 16 `packages.config` files has dropped net481 support — this is a verified negative finding, not an assumption. Consequently, the compatibility safety net is a `semver-major`-scoped `ignore` rule set on the Microsoft `.NET`-runtime-aligned package families (the packages whose upstream release cadence is coupled to `.NET`'s own yearly major-version train), **not** fabricated version-ceiling numbers. This is the finalized mechanism; the atomic-planner must not substitute invented version ranges. +- Risk: overly broad `ignore` rules could suppress legitimate compatible security patches. Mitigated by scoping every `ignore` entry to `update-types: ["version-update:semver-major"]` only — minor/patch updates (including security patches) remain unaffected (AC-7). +- Risk: without `groups`, a package shared across all 16 directories (e.g. `log4net`) would open up to 16 near-duplicate PRs per release. Mitigated by `group-by: "dependency-name"` (AC-8). + +## Implementation Strategy + +- Implementation scope: add one new file (`.github/dependabot.yml`) and one new documentation section (`README.md`). No source code, test code, or `.csproj`/TFM changes are in scope. +- New classes/functions/commands: none — this is a declarative YAML artifact, not executable code. +- Dependency changes: none introduced by this feature itself; the feature *enables* future automated dependency-version PRs but does not itself bump any package. +- Logging/telemetry additions: none applicable — GitHub's Dependabot service does its own internal logging (visible via Insights → Dependency graph → Dependabot), which this repo does not control or extend. +- Rollout plan: single-commit, config-only change with no flag needed. Rollback path is a plain revert of the `.github/dependabot.yml` addition, which stops scheduled runs with no other side effects on the codebase. + +## Documentation Deliverable (Decision) + +The rationale documentation required by AC-12 is delivered as a new `## Dependency updates (Dependabot)` section in `README.md`, inserted after the existing `## Configuration & storage` section and before `## Common issues`, with a corresponding entry added to the `## Contents` list. This is the single, final target path — not a choice left to the atomic-planner. The section must state, in prose: + +1. Dependabot's NuGet updater cannot independently bump a transitive/indirect dependency beyond what its referencing primary dependency's own manifest supports — this is documented default ecosystem behavior (GitHub Docs, "About Dependabot security updates"), not a mechanism this repo's config invents. +2. The `semver-major`-scoped `ignore` rule set (Microsoft `.NET`-runtime-aligned package families) is this repo's defense against a future framework-support drop, adopted because no currently-published version of any package referenced in this repo has dropped net481 support (verified 2026-07-16; see research §4). Minor/patch updates for the same families remain unaffected. +3. The `directories: ["/*"]` decision and its pre-decided fallback (the literal 16-entry list in Appendix A), to be adopted if post-merge verification shows under-coverage. +4. A pointer to the manual, out-of-toolchain post-merge verification step (AC-11) as a standing runbook note for maintainers. + +## Acceptance Criteria + +Supersedes the early draft in `issue.md`. Each item below is independently verifiable and decidable; none are left open for the atomic-planner to resolve. + +### Config existence & schema + +- [x] AC-1: `.github/dependabot.yml` exists at the repository root, begins with `version: 2`, and contains exactly one `updates:` entry with `package-ecosystem: "nuget"`. +- [x] AC-2: The `nuget` update entry's keys (`package-ecosystem`, `directories`, `schedule`, `open-pull-requests-limit`, `groups`, `ignore`) are present, correctly typed, and match the Dependabot v2 options reference structure cited in research §2/§4/§5; the file parses as valid YAML. + +### Directory coverage (16 packages.config directories) + +- [x] AC-3: The delivered config's directory-scoping mechanism is `directories: ["/*"]`, shipped as final per "Resolved Ambiguities" #2 above (not a placeholder pending later decision). +- [x] AC-4: Pre-merge, an enumeration check (e.g., `Get-ChildItem -Path . -Filter packages.config -Recurse | Select-Object FullName`, or equivalent) confirms `packages.config` files exist only at depth 1 from the repository root, across exactly the 16 directories listed in Appendix A (plus `VBFunctions`/`VBFunctions.Test`, which carry only the analyzer-only `packages.config` noted above). This enumeration is recorded as evidence supporting AC-3. +- [ ] AC-5: Pre-decided fallback — if the post-merge check in AC-11 shows Dependabot scanning fewer directories than expected (the `/*` glob under-matches), the config is corrected in a follow-up commit to the literal 16-entry `directories:` list in Appendix A, removing the glob. No other resolution is acceptable under this spec. + +### TFM-compatibility safety net + +- [x] AC-6: The config's `ignore` list contains one entry per Microsoft `.NET`-runtime-aligned package family — `Microsoft.Extensions.*`, `Microsoft.Bcl.*`, `System.Text.Json`, `System.Drawing.Common`, `Microsoft.Graph*`, `Apache.Arrow*`, `Microsoft.Data.Analysis`, `Microsoft.ML*` — each scoped to `update-types: ["version-update:semver-major"]`. No `ignore` entry specifies a fabricated version-ceiling number under a `versions:` key. +- [x] AC-7: No `ignore` entry includes `version-update:semver-minor` or `version-update:semver-patch` in its `update-types` list for any package — minor/patch updates, including security patches, remain unaffected by the safety net. + +### Grouping & scheduling + +- [x] AC-8: `groups` defines four buckets — `analyzers-dev-deps`, `test-frameworks`, `microsoft-extensions-and-bcl`, `graph-identity-telemetry` — each using `patterns` and `group-by: "dependency-name"`, matching the package-family inventory in research §1.1/§6. +- [x] AC-9: `schedule.interval` is `"weekly"` and `open-pull-requests-limit` is `10`. + +### TFM non-modification + +- [x] AC-10: A diff review of the merged change shows zero modifications to any `.csproj` file's `` element (or any other TFM-declaring element). The only files added/changed are `.github/dependabot.yml` and the `README.md` documentation section (AC-12). + +### Documentation + +- [x] AC-12: `README.md` gains the `## Dependency updates (Dependabot)` section described in "Documentation Deliverable" above, including all four required content points, with a corresponding `## Contents` entry added. + +### Post-merge verification (manual, outside the automated toolchain) + +- [ ] AC-11: After merge, a maintainer manually confirms via the repository's **Insights → Dependency graph → Dependabot** tab (or the "Recent update jobs" log) that at least one of the 16 directories is scanned and produces a dependency list. This check is explicitly out of scope for the atomic-executor's automated toolchain — no format/lint/type-check/test stage applies to a static YAML file. It is recorded as a runbook note in the AC-12 documentation section and tracked as a deferred, manual verification item: it does not block the initial merge, but the feature is not considered fully verified (feature-audit) until it passes or AC-5's fallback has been applied and re-checked. + +## Appendix A — Literal 16-directory fallback list + +For use only if AC-5's fallback condition is triggered: + +```yaml +directories: + - "/QuickFiler" + - "/QuickFiler.Test" + - "/SVGControl" + - "/SVGControl.Test" + - "/Tags" + - "/Tags.Test" + - "/TaskMaster" + - "/TaskMaster.Test" + - "/TaskTree" + - "/TaskTree.Test" + - "/TaskVisualization" + - "/TaskVisualization.Test" + - "/ToDoModel" + - "/ToDoModel.Test" + - "/UtilitiesCS" + - "/UtilitiesCS.Test" +``` + +## Definition of Done + +- [x] Acceptance criteria (AC-1 through AC-12 above) documented and mapped to verification steps +- [x] `.github/dependabot.yml` matches every AC in this spec +- [x] `README.md` documentation section added per AC-12 +- [x] Pre-merge enumeration evidence (AC-4) recorded +- [x] Diff review confirms no TFM changes (AC-10) +- [x] Post-merge Dependabot scan verification (AC-11) scheduled/tracked as a runbook item +- [x] No toolchain pass required beyond YAML validity — this is a config-only change with no C# source, so the CSharpier/analyzer/nullable/vstest loop does not apply (research §1.2) + +## Seeded Test Conditions (from research §9) + +- [ ] YAML validates against the Dependabot v2 config schema (GitHub validates on push; confirmed via AC-2/AC-11). +- [ ] Config correctly scopes `directories` to every `packages.config` project root (AC-3/AC-4/AC-5). +- [ ] `ignore` rules are anchored to specific packages and `update-types`, not blanket ecosystem suppression (AC-6/AC-7). +- [ ] `groups` collapse duplicate cross-directory bumps for the same package rather than producing per-directory PRs (AC-8). diff --git a/docs/features/active/2026-07-16-dependabot-net481-support-340/user-story.md b/docs/features/active/2026-07-16-dependabot-net481-support-340/user-story.md new file mode 100644 index 000000000..21f1a7d31 --- /dev/null +++ b/docs/features/active/2026-07-16-dependabot-net481-support-340/user-story.md @@ -0,0 +1,52 @@ +# `dependabot-net481-support` — User Story + +- Issue: #340 +- Owner: drmoisan +- Status: Draft +- Last Updated: 2026-07-16 + +## Story Statement + +- As a maintainer of this repository, I want automated NuGet dependency-update pull requests across all 16 `packages.config` project directories, so that stale or known-vulnerable package versions no longer persist unnoticed due to manual-only tracking. +- As a maintainer of this repository, I want the dependency-update automation to never propose a package version that has dropped `.NET Framework 4.8.1` (`net481`) support, so that an automated PR cannot introduce a build break the project cannot recover from without a framework migration it is not undertaking. + +## Problem / Why + +The repository has no automated dependency-update tooling. NuGet package versions across all 16 `packages.config`-based project directories are updated manually, so known-vulnerable or stale dependency versions can persist unnoticed. Every production project is fixed to `.NET Framework 4.8.1`; any automation introduced to solve the staleness problem must not itself become a source of framework-incompatible breakage, since the maintainer has no path to move these projects off `net481` in the near term. + +## Personas & Scenarios + +- Persona: Dan, the sole maintainer of this VSTO Outlook add-in repository. + - Who he is: reviews and merges all PRs personally; has limited time to manually audit 16 separate `packages.config` files for outdated or vulnerable package versions. + - What he cares about: dependency currency (especially security-relevant patches) without spending recurring manual effort checking each project directory. + - His constraints: every project is permanently pinned to `.NET Framework 4.8.1` (a VSTO/Outlook interop requirement) — he cannot accept an automated dependency bump that requires a newer-only TFM, because that would silently break the build the next time CI restores packages. + - His goals and frustrations: wants "set it up once and get PRs" dependency hygiene, but is wary of blindly trusting an automation tool that could, in principle, propose an incompatible major-version bump for a package family that later drops legacy-framework support. + - His context and motivations: this is a long-lived personal/small-team project without CI infrastructure dedicated to dependency scanning; GitHub's native Dependabot tooling is the lowest-friction option since it requires only a committed config file, not a new service to operate. + +- Scenario: Enabling dependency automation without breaking the fixed framework target. + - Who is acting: Dan, merging the `.github/dependabot.yml` PR into the default branch. + - What triggered the action: recurring awareness that dependency versions across `QuickFiler`, `TaskMaster`, `UtilitiesCS`, and the other 13 project directories are checked manually and inconsistently. + - What steps he takes: reviews the proposed `.github/dependabot.yml`, confirms it scopes all 16 directories via `directories: ["/*"]`, confirms the `ignore` rules only gate `semver-major` bumps for the Microsoft `.NET`-runtime-aligned package families (not blanket suppression), confirms no `.csproj` TFM element changed, and merges. + - What obstacles or decisions occur: Dan has to decide whether to trust that Dependabot's NuGet updater genuinely cannot bump a transitive dependency independently of its parent (it cannot, per GitHub's own documentation — a property of the ecosystem, not something this config has to separately enforce), and whether the `/*` glob will actually match all 16 directories, given the documentation available did not include a fully worked example of the glob's matching depth. + - What outcome he expects: within a week of merge, Dependabot opens its first grouped PR(s) proposing minor/patch bumps for shared packages (e.g., `log4net`, an `Microsoft.Extensions.*` family member) collapsed into one PR per shared package rather than 16 near-duplicate PRs; any future major version of a gated package family that would drop `net481` support is withheld until Dan manually re-verifies compatibility, rather than arriving as an automatically-mergeable PR. + - Follow-up check: Dan visits the repository's Insights → Dependency graph → Dependabot tab after the first scheduled run to confirm at least one of the 16 directories was actually scanned, closing the small residual uncertainty about whether Dependabot's NuGet updater fully supports the `packages.config` manifest format in this repository's specific layout. + +## Acceptance Criteria + +Full acceptance-criteria detail, including exact `ignore`/`groups`/`directories` values and the finalized fallback/verification decisions, is defined in `spec.md` (AC-1 through AC-12). Restated here from the maintainer's perspective: + +- [x] A single `.github/dependabot.yml` covers all 16 `packages.config` project directories, so no directory is left unmonitored (spec AC-1 through AC-5). +- [x] The configuration never proposes a package version whose NuGet Frameworks panel has dropped `.NET Framework`/`net48`/`net481` support, achieved through a documented `semver-major`-scoped `ignore` safety net on the Microsoft `.NET`-runtime-aligned package families — not through fabricated version-ceiling guesses (spec AC-6, AC-7). +- [x] Updates for shared packages across the 16 directories arrive as one grouped PR, not one PR per directory, so review load stays manageable (spec AC-8). +- [x] The update cadence is weekly with at most 10 open PRs at a time, so PR volume does not overwhelm a single-reviewer workflow (spec AC-9). +- [x] No project's target framework moniker changes as a side effect of this feature (spec AC-10). +- [x] `README.md` explains, in plain language a future contributor can read without re-deriving it, why transitive dependencies are never bumped independently of their parent (Dependabot's documented default NuGet behavior) and why the `ignore` safety net exists (spec AC-12). +- [ ] After merge, Dan (or another maintainer) confirms via GitHub's Dependabot Insights tab that scanning actually occurred for at least one directory — an explicitly manual, post-merge check, not something the automated toolchain verifies (spec AC-11). + +## Non-Goals + +- This feature does not migrate any project off `.NET Framework 4.8.1`, and does not change any `.csproj` TFM. +- This feature does not convert any project from `packages.config` to `PackageReference`. +- This feature does not enable or configure Dependabot **security alerts** (a separate GitHub capability from version updates); that remains a repository-settings concern outside this file-based change. +- This feature does not add a CI workflow, test suite, or local YAML-schema-validation script — GitHub's own push-time validation and the manual post-merge Insights check (AC-11) are the accepted verification mechanisms for this config-only artifact. +- This feature does not attempt to invent a Dependabot config primitive for "never bump a transitive dependency" — that behavior is already the ecosystem's documented default and is recorded, not re-implemented.