Skip to content

Add dependabot-consolidation skill - #1060

Merged
jasonleenaylor merged 8 commits into
mainfrom
claude/dependabot-consolidation-skill-f98aba
Aug 14, 2026
Merged

Add dependabot-consolidation skill#1060
jasonleenaylor merged 8 commits into
mainfrom
claude/dependabot-consolidation-skill-f98aba

Conversation

@jasonleenaylor

@jasonleenaylor jasonleenaylor commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Quick Summary

Adds .claude/skills/dependabot-consolidation/SKILL.md, a skill that combines
several open Dependabot pull requests into one branch and one pull request.

Dependabot opens a PR per ecosystem group, and each one triggers a full
Build Debug and run tests cycle. This month that was three PRs for fifteen
dependency bumps. The skill folds them into a single reviewable PR that costs
one CI cycle.

It also fixes a problem that has nothing to do with volume: Dependabot PRs in
this repository cannot go green.
CI.yml passes secrets.CODECOV_TOKEN to
the coverage upload, Dependabot-triggered PRs do not receive repository
secrets, and Verify Codecov upload succeeded fails even when every test
passes. A combined PR runs from a repository-owned branch and can actually
report green.

What it does

  1. Enumerates open PRs authored by app/dependabot, reads their commit
    trailers to count dependencies and flag major bumps, and presents a plan.
  2. Creates a dedicated worktree under .claude/worktrees/ and branches off
    fresh origin/main, so stale Dependabot branches are rebased by
    construction.
  3. Cherry-picks each source commit, preserving Dependabot as author along with
    the original author date.
  4. Trims commit bodies to satisfy .github/commit-guidelines.md. Dependabot's
    markdown link lines exceed the 80-column body limit and fail the
    Check commit messages job. Bodies that are already compliant are left
    byte-identical.
  5. Checks every changed package version line against the comment above it, and
    stops rather than silently reverting a deliberate pin (see below).
  6. Verifies locally: git log --check, the commit-message rules, and
    build.ps1 -BuildTests when the batch touches package manifests.
  7. Pushes, opens the combined PR, waits for CI, and closes the superseded PRs
    once it is green.

Three confirmation gates: the plan, the push, and the closes. A cherry-pick
conflict aborts the whole run and reports the retry command. A red CI reports
and stops without closing anything.

The pin guard

Dependabot cannot tell a dependency from a pin. Directory.Packages.props has
a Transitive Pins block whose entries exist specifically to hold a version,
each documented by a comment, and Dependabot bumps them and leaves the comment
behind saying the opposite.

This was not hypothetical during validation. #1059 initially carried a bump of
Microsoft.Extensions.DependencyModel from 9.0.16 to 9.0.18, reverting a pin
that #1000 established after reproducing a TypeInitializationException on
Icu.NativeMethods in the .NET Framework test host — and CI went green anyway,
because the documented retest procedure requires a full test.ps1 while
CI.yml runs with TestCategory!=LongRunning&TestCategory!=ByHand&....

The skill now reads the comment block above every changed version line and
stops when it names a version, explains why the current one was chosen, or
gives a retest procedure. It distinguishes a comment that forbids the bump
(drop that line, keep the rest of the batch) from one that merely names the
old version (take the bump, refresh the comment).

Two further checks cover central package management structure that Dependabot
does not model:

  • A version property must not become a literal. 31 of the 89 root entries
    read Version="$(SilLcmVersion)" or Version="$(SilLibPalasoVersion)", with
    the value in Build/SilVersions.props. Literalizing one silently breaks the
    single source of truth for every package sharing it.
  • The Build/Src layering invariant must survive. Build/Src/Directory.Packages.props
    imports the root and layers Include for build-only packages and Update to
    override a root pin, so a package can be declared twice with different
    versions on purpose — Microsoft.Extensions.DependencyModel is 9.0.16 at the
    root and 2.1.0 in Build/Src. Bumping one site and not the other widens a
    deliberate split.

Verified on this batch: no .csproj declares a version for any pinned package
(NativeBuild.csproj is the only central-package-management opt-out, and its
entries are property-driven), the Include/Update invariant holds, and no
property reference was rewritten.

Scope

The skill only combines pull requests that already exist. If the goal is fewer
PRs each month, the fix is the groups: blocks in .github/dependabot.yml,
and the skill says so rather than pretending to solve it.

Validation

Executed end to end against the three real Dependabot PRs that were open,
producing #1059:

The conflict/abort path is the one branch not exercised, since none of the
three PRs conflicted.

Notes for reviewers

Documentation only; no product code changes and nothing in Src/**.

Two follow-ups this surfaced, both out of scope here:

  • Microsoft.Extensions.DependencyModel will be proposed again every month
    until it is added to the ignore: block in .github/dependabot.yml.
  • Docs/workflows/pull-request-workflow.md lists feature/, bugfix/,
    hotfix/, and docs/ branch prefixes but not chore/, which is in live use
    on the remote and is what this skill generates.

🤖 Generated with Claude Code


This change is Reviewable

jasonleenaylor and others added 2 commits August 12, 2026 16:42
Adds a skill that combines several open Dependabot pull requests into one
branch and one pull request. It enumerates the open Dependabot PRs,
cherry-picks them onto fresh main in a dedicated worktree, trims the commit
bodies so they satisfy the commit-message guidelines, verifies locally, then
pushes and opens the combined PR behind three confirmation gates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dependabot cannot tell a dependency from a deliberate pin. The skill now
reads the comment block above every changed package version line and
stops when it names a version, explains why the current one was chosen,
or gives a retest procedure. It also separates the two outcomes: drop
the bump when a comment forbids it, or refresh the comment when it
merely names the old version.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@codecov-commenter

codecov-commenter commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 38.04%. Comparing base (b857373) to head (da83958).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1060   +/-   ##
=======================================
  Coverage   38.04%   38.04%           
=======================================
  Files        1499     1499           
  Lines      350117   350108    -9     
  Branches    40233    40231    -2     
=======================================
+ Hits       133196   133204    +8     
+ Misses     187634   187619   -15     
+ Partials    29287    29285    -2     

see 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

NUnit Tests

    1 files  ±0      1 suites  ±0   11m 39s ⏱️ +11s
5 760 tests  - 1  5 679 ✅  - 1  81 💤 ±0  0 ❌ ±0 
5 769 runs   - 1  5 688 ✅  - 1  81 💤 ±0  0 ❌ ±0 

Results for commit da83958. ± Comparison against base commit 1674067.

This pull request removes 10 and adds 9 tests. Note that renamed tests count towards both.
LexEdDllTests.EntrySequenceChooserCommandKeepOwnerActiveWhenHidingTests ‑ AddComplexFormChooserCommand_OptsIn
LexEdDllTests.EntrySequenceChooserCommandKeepOwnerActiveWhenHidingTests ‑ AddPrimaryLexemeChooserCommand_OptsIn
SIL.FieldWorks.Common.Framework.DetailControls.ChooserCommandKeepOwnerActiveWhenHidingTests ‑ MakeInflAffixEntryChooserCommand_OptsIn
SIL.FieldWorks.Common.Framework.DetailControls.ChooserCommandKeepOwnerActiveWhenHidingTests ‑ MakeInflAffixSlotChooserCommand_DoesNotOptIn
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayNeedsReconstructTests ‑ NotifyDataAccessSemanticsChanged_DefersUntilVisible
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayNeedsReconstructTests ‑ NotifyDataAccessSemanticsChanged_Reconstructs_WhenRootBoxDoesNotNeedReconstruct
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayNeedsReconstructTests ‑ RefreshDisplay_Reconstructs_WhenRootBoxNeedsReconstruct
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayNeedsReconstructTests ‑ RefreshDisplay_SkipsReconstruct_WhenRootBoxDoesNotNeedReconstruct
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayNeedsReconstructTests ‑ SetRootBoxDataAccessAndRefresh_Reconstructs_WhenSwapChangesDisplaySemantics
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayNeedsReconstructTests ‑ SetRootBoxDataAccess_DoesNotReconstruct_WhenSwapIsCheap
LexEdDllTests.EntrySequenceChooserCommandKeepOwnerActiveWhenHidingTests ‑ AddComplexFormChooserCommand_KeepsOwnerActive
LexEdDllTests.EntrySequenceChooserCommandKeepOwnerActiveWhenHidingTests ‑ AddPrimaryLexemeChooserCommand_KeepsOwnerActive
SIL.FieldWorks.Common.Framework.DetailControls.ChooserCommandKeepOwnerActiveWhenHidingTests ‑ MakeInflAffixEntryChooserCommand_KeepsOwnerActive
SIL.FieldWorks.Common.Framework.DetailControls.ChooserCommandKeepOwnerActiveWhenHidingTests ‑ MakeInflAffixSlotChooserCommand_KeepsOwnerActive
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayReconstructTests ‑ NotifyDataAccessSemanticsChanged_DefersUntilVisible
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayReconstructTests ‑ NotifyDataAccessSemanticsChanged_Reconstructs
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayReconstructTests ‑ RefreshDisplay_AlwaysReconstructs
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayReconstructTests ‑ SetRootBoxDataAccessAndRefresh_Reconstructs_WhenSwapChangesDisplaySemantics
SIL.FieldWorks.Common.RootSites.SimpleRootSiteTests.RefreshDisplayReconstructTests ‑ SetRootBoxDataAccess_DoesNotReconstruct_WhenSwapIsCheap

♻️ This comment has been updated with latest results.

jasonleenaylor and others added 5 commits August 12, 2026 17:14
Adds two package-manifest checks the pin guard did not cover: a version
property must not be rewritten into a literal, since a third of the root
entries resolve through Build/SilVersions.props, and the Build/Src
Include/Update layering over the root file must survive a bump. Notes
NativeBuild.csproj as the only project that opts out of central package
management.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The guard stopped on any comment mentioning a version, which over-triggers:
most pin comments cite a floor, and NuGet floors cannot be violated by
bumping up. The skill now resolves the depending package's nuspec, reads
whether the range is a floor or a bracketed exact/capped range, and only
treats the bracketed kind as blocking.

This splits pins into constraint-driven, which the package graph can settle,
and empirically-driven, which no manifest expresses and which therefore need
a dependabot ignore entry. Also covers the case where the external package
is bumped in the same batch, moving the floors the comments quote.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR #984 proposed the DependencyModel version documented as breaking ICU
initialization and its build-and-test job passed, so CI cannot detect this
class of failure at all. The guard said a green CI was insufficient because
of the category filter; the stronger and correct statement is that a green
CI is not evidence either way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A retest procedure written into a comment is not self-validating. Running
the DependencyModel procedure against 9.0.17, the version it was written to
catch, produced zero Icu.NativeMethods hits, so a pass on a newer version
proves nothing. The guard now requires running the procedure against the
known-bad version first, and warns that flaky failures can look like signal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Restoring the PR #1000 tree with its own SIL.LCModel and LibPalaso versions
and forcing DependencyModel to 9.0.17 still produces zero Icu.NativeMethods
hits, so the failure is unreproducible rather than hidden by newer packages.
States the rule that an unreproducible justification keeps a pin and stops
bumps against it, rather than clearing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Halves the skill to its decision rules: drops the wrong-tool section and
compresses the investigation narratives into the rules they produced.
Adds an anticipate-only Paratext section: a watchlist of packages whose
bumps can affect the merged lexicon plugin that Paratext loads into its
own process, an AssemblyRef diff of the merged plugin between base and
branch builds, and instructions to hand any contract change to the user
as deliberate follow-up work rather than fixing it mid-run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jasonleenaylor
jasonleenaylor merged commit 99858db into main Aug 14, 2026
6 checks passed
@jasonleenaylor
jasonleenaylor deleted the claude/dependabot-consolidation-skill-f98aba branch August 14, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants