From Mind-Vault
Triage and batch-merge accumulated Dependabot PRs in multi-requirements-file Python repos (web + lsp + dev + per-workspace) — diff-based duplicate detection across the root vs per-workspace ecosystems, risk-tier batching for git-bisect cleanliness, worktree-isolated verification, live-staging smoke, post-merge forward-sync of remaining branches. TRIGGER when the user says "review dependabot PRs", "merge dependabot batch", "dependabot sweep", "what to do with these dep PRs", "clean up the dep updates", or asks for a roadmap merging multiple `chore(deps)` PRs.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mv:dependabot-triageThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A workflow for processing 5–20 accumulated Dependabot PRs as one coherent sweep instead of one-PR-at-a-time fatigue. The non-obvious pieces are (1) **two PRs touching the same package are not necessarily duplicates** when the repo has multiple requirements files served by separate dependabot ecosystems, and (2) **risk-tier batching with one commit per dep** preserves `git bisect` even when the ...
A workflow for processing 5–20 accumulated Dependabot PRs as one coherent sweep instead of one-PR-at-a-time fatigue. The non-obvious pieces are (1) two PRs touching the same package are not necessarily duplicates when the repo has multiple requirements files served by separate dependabot ecosystems, and (2) risk-tier batching with one commit per dep preserves git bisect even when the PR ships a bundle.
TRIGGER when:
0.0.x → 1.x.x) is mixed in with low-risk patch bumps and the user wants to know how to split them.SKIP when:
gh pr list --author "app/dependabot" --state open --limit 100 \
--json number,title,headRefName,mergeable,labels
For each PR, capture: number, title, branch path (dependabot/pip/<pkg>... vs dependabot/pip/<workspace>/<pkg>...), files touched, diff size. The branch path tells you which dependabot ecosystem opened it.
Multi-requirements-file repos typically configure two or more pip ecosystems in .github/dependabot.yml:
- package-ecosystem: "pip"
directory: "/" # → root: requirements-web.txt, requirements-lsp.txt, …
- package-ecosystem: "pip"
directory: "/<workspace>" # → workspace: <workspace>/requirements-*.txt
When both ecosystems see the same package needing a bump, you get two PRs that look identical by title but are produced by independent ecosystems. Sometimes they're true duplicates (same diff, same file). Sometimes they're not (root PR bumps web + lsp + workspace; workspace-PR bumps only the workspace file).
The hard rule: never close a duplicate by title alone. Diff every candidate pair:
gh pr diff <PR_A> > /tmp/A.diff
gh pr diff <PR_B> > /tmp/B.diff
diff /tmp/A.diff /tmp/B.diff
Close only when one diff is byte-identical to the other, or a strict superset (the larger diff includes every line of the smaller diff and nothing the smaller PR uniquely contributes is omitted).
The closing comment should cite the canonical PR carrying the change forward: Closing as duplicate of #X — both update <pkg> to <ver> in <file> with identical diffs.
For each unique PR, record the files it touches. Build a per-file table:
| File | PRs touching it | Lines collide? |
|---|---|---|
requirements-web.txt | #A, #B, #C | No (different deps) |
<workspace>/requirements.txt | #A, #D, #E | No |
If no two PRs touch the same line of the same file, a bundled merge is conflict-free. Almost always the case for Dependabot — each PR floor-bumps one package on its own line.
Slot each unique bump into one of four tiers:
| Tier | What | Treatment |
|---|---|---|
| 🟢 Patch | 2.0.1 → 2.0.2, security-floor patch | Bundle freely. |
| 🟢 Minor | >=0.45 → >=0.46 | Bundle freely. |
| 🟡 Moderate | Many minor versions (e.g. >=0.100 → >=0.136), but pre-1.0 still pre-1.0 | Bundle if surface area is small; isolate if the package is load-bearing. |
| 🔴 High | Version-scheme jump (pre-1.0 → 1.x), API-breaking range, library actively used in subtle code paths (SDKs, parsers, embedders) | Isolate into its own PR. |
The dividing line for isolation is bisectability: if a regression appears post-merge, can git bisect point at the responsible commit (or PR) without ambiguity? If the high-risk bump is bundled with five low-risk ones in a single squash-merge, bisect resolves to the bundle and the operator has to manually un-bundle.
Even when bundling 5 deps into a single PR, use 5 separate commits (one per dep):
chore(deps): bump xlrd 2.0.1 → 2.0.2
chore(deps): bump uvicorn[standard] >=0.45.0 → >=0.46.0
chore(deps): bump requests >=2.32.5 → >=2.33.1
chore(deps): bump markdown >=3.7 → >=3.10.2
chore(deps): bump fastapi >=0.100 → >=0.136.1
Order low-to-high risk so the riskiest commit is on top — if a regression surfaces post-merge, git revert HEAD~N..HEAD peels off the riskier ones first. Every commit message mentions Closes #<original-PR> so the bundle PR auto-closes the dependabot PRs on merge.
The PR description lists every closed PR — gh pr merge honours Closes lines from any commit message in the PR.
Merge-strategy gotcha — non-negotiable. Per-dep commits only preserve git bisect resolution if the merge into main keeps them as separate commits. GitHub's default Squash and merge collapses every commit in the PR into a single squash-commit, defeating the entire bisect benefit. For a bundled dep PR specifically, the operator must:
main verbatim, plus a merge commit), ORmain linearly, no merge commit).gh pr merge --merge (merge commit) or gh pr merge --rebase (rebase) — never gh pr merge --squash for dep-bundle PRs. If the repo is configured to allow only squash-merge, change the per-PR setting via the GitHub web UI dropdown before clicking merge, or escalate to a maintainer who can. The bisect benefit and the per-dep commit discipline are coupled; if the merge strategy can't be controlled, the per-dep commits are theatre — fall back to a single squashed commit and accept the loss of post-merge bisect.
Each PR (bundle and isolated-high-risk) gets its own worktree:
git worktree add ../<repo>-deps-<slug> -b chore/dependabot-<slug>-YYYY-MM origin/main
Per-worktree:
.env (never copy real secrets except where targeted smoke needs them — for SDK floor bumps that exercise real APIs, copy the credentials file bytewise without reading: cp credentials.json <worktree>/path/credentials.json).docker-compose.override.yml with port offset (+30000 / +50000 etc.) and non-overlapping subnet (172.30.0.0/16 etc.).make build (cache-aware — pip layer is invalidated automatically because requirements file content hash changed; --no-cache only needed if a prior build with the same hash got a silent skip).make migrate and make test.embedContent round-trip for google-genai; real PDF extraction for pymupdf4llm).Resource ceiling: two parallel test stacks on a 16 GB box hits CPU contention with each running pytest -n 8. Sequential is faster end-to-end. Cooperative-pause technique: kill the lower-priority stack's pytest mid-flight (docker compose stop web celery on the worktree releases its CPU), let the higher-priority finish uncontended, then resume.
After the bundle PR merges, switch staging to the next isolated-high-risk PR's branch:
make stop # avoid migration drift on branch switch
git fetch origin <pr-branch>
git checkout <pr-branch>
make build # pip layer rebuilds since deps changed
make start
make migrate # idempotent
Hand back to the user for live verification. Per RULE_git-safety the human reviews + merges; the agent never does.
When the first PR merges, the remaining isolated PRs are now behind. Forward-sync each:
git fetch origin main # critical — without this, origin/main is stale and the merge silently misses the just-landed merge commit (or rebased / squashed lineage, depending on which strategy the bundle PR used)
git checkout <next-pr-branch>
git merge --no-edit origin/main
git push origin <next-pr-branch> # regular push, no force — additive merge commit
The git fetch origin main step is non-optional. The remote ref origin/main is local cache that only updates on fetch; web-UI merges on GitHub do not propagate to your local view automatically. Skip the fetch and the merge becomes a no-op (or worse: a partial sync against a stale snapshot that masks a real conflict you'll only discover at merge time).
Forward-sync is always allowed by RULE_git-safety (the feature branch's tip moves; main's doesn't). A regular git push keeps PR review threads intact; only --force-with-lease would invalidate them.
Open a small docs PR (or fold into the still-open dep PR) covering:
docs/archive/YYYY-MM-DEVELOPMENT_LOG.md — what merged, what shipped isolated, operational lessons.If only one isolated PR remains and its review window is short, fold the docs commit into that PR; otherwise a standalone chore/docs-dep-updates-YYYY-MM branch off main keeps it independently mergeable.
git bisect resolution post-merge — but only if the operator picks merge-commit or rebase-merge as the merge strategy. GitHub's default Squash and merge collapses per-dep commits into one squash-commit and silently negates the entire bisect benefit (see step 5's merge-strategy gotcha). The two pieces — per-dep commits and non-squash merge — are coupled; doing one without the other is theatre..env copy into a worktree. Worktree must use sentinels (per RULE_parallel-worktree-docker); only the credentials file backing a specific SDK smoke gets copied bytewise — and only into the worktree where that smoke runs.git merge origin/main + regular push, not rebase + force-push. Review threads survive.../sprint-auto/references/PARALLEL_WORKTREE_DOCKER.md — the worktree + override-file + sentinel-env mechanics this skill leans on for verification isolation.rules/RULE_git-safety.md — forward-sync is allowed; merge-into-main is HITL.skills/wrap/SKILL.md — for the docs sweep at step 9 when the dep sweep was non-trivial enough to deserve a devlog entry.skills/review-loop/SKILL.md — when a bundle PR's review surfaces issues (rare for dep bumps, but the review-fix loop applies if invoked, on whichever engine the project has opted into).Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub infohata/mind-vault --plugin mv