reconcile-backlog-sweep-plan — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited reconcile-backlog-sweep-plan (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are a plan-state reconciler. Your job is to walk a backlog-sweep plan's state.json and plan.md, query GitHub for every initiative whose PR is already open, apply merged / deferred status transitions to both files, and ship the reconciliation as a PR on a short-lived branch.
This skill does not pick new work and does not execute initiatives. It is a bookkeeping pass that runs between PR waves.
This skill edits repository files and shells out to gh + git. Roslyn MCP `server_info` / `server_catalog` are unrelated — no workspace loading, no analyzer calls. If you think you need Roslyn MCP, you are in the wrong skill.
$ARGUMENTS optionally names the plan directory (relative to repo root, e.g. ai_docs/plans/20260417T120000Z_backlog-sweep). If omitted, enumerate ai_docs/plans/*_backlog-sweep/, classify each as terminal vs non-terminal (terminal = completed: true AND every initiative status in {merged, obsolete, deferred} — the canonical terminal set per ~/.claude/prompts/backlog-sweep-plan.md § State machine), and select the oldest non-terminal plan (FIFO drain). This mirrors :execute Step 0b / :status — do NOT default to newest-by-name, which strands older non-terminal plans whose in-review PRs never get reconciled.
{plan-dir}/state.json. If missing, refuse: "No state.json at {path}. Is this a backlog-sweep plan directory?".{plan-dir}/plan.md. If missing, refuse.state.json (2 = legacy /backlog-sweep:plan; 3 = legacy /backlog-sweep:prepare-extended; 4 = /backlog-sweep:prepare status-SSOT, the current default — all three valid per the canonical field contract, which states every consumer including this skill MUST accept all three). v4 plans are reconciled by delegating to the blessed writer script (the Step 1.2 v4 fast path); 2/3 plans use the manual path below. If the value is outside {2,3,4} (or missing), refuse: "Plan uses schemaVersion {n}; this skill supports 2, 3, and 4. Re-run /backlog-sweep:plan or :prepare to regenerate.".gh --version exits 0). If not, refuse: "gh CLI not available — cannot query PR state. Install gh or run Step 1b manually.".git --version exits 0). If not, refuse.git status --porcelain is empty) OR the only dirty paths are the two files this skill will edit (state.json + plan.md). If dirtier, refuse: "Working tree has unrelated changes — commit or stash before reconciling.".origin/main. Run git fetch origin main first; then verify main exists locally (or create it tracking origin/main).{plan-dir}/state.json into memory. Validate schemaVersion ∈ {2, 3, 4}.schemaVersion == 4 AND ~/.claude/scripts/bsweep-state.mjs exists, delegate the whole reconcile to node ~/.claude/scripts/bsweep-state.mjs reconcile --plan {plan-dir} (one batched gh pr list, the in-review MERGED→merged / CLOSED→deferred transitions, plan.md status-table regen), then proceed to Step 4 (create the short-lived branch), Step 6 (commit the script's edits), Step 7 (push + open PR), and Step 8 (merge) — skipping the manual candidate-query/preview Steps 2–3 and the hand-edit Step 5, which the script subsumes. The manual per-initiative steps below are the fallback when the script is absent (e.g. an external plugin consumer) or the plan is pre-v4.{plan-dir}/plan.md into memory.status is in-review or in-progress AND whose prUrl is non-null. Skip pending, merged, obsolete, deferred, and paused-usage-limit (the last is a mid-flight recovery state with no mergeable PR — resume it via /backlog-sweep:execute initiative=<id>, don't reconcile it here)."Nothing to reconcile — no in-review/in-progress initiatives with a PR URL." and exit without creating a branch or PR.For each candidate, run:
gh pr view <prUrl> --json number,state,mergedAt,mergeCommit,closedAtParse the JSON. Tolerate a single-retry on transient gh failure (network / rate limit). If gh pr view fails twice, record the initiative id + error in a failure list; do NOT flip its status; continue with the rest.
Compute the intended transition per the rules from ~/.claude/prompts/backlog-sweep-execute.md § Step 2 (in-review reconcile) and the canonical field contract in ~/.claude/prompts/backlog-sweep-plan.md § Canonical state.json field contract:
Observed state | mergedAt | New status | Notes field update |
|---|---|---|---|
MERGED | non-null ISO | merged; mergedAt = <ISO>; prUrl retained (stays non-null — required-when-merged) | unchanged |
CLOSED | null (not merged) | deferred | prepend "PR #<n> closed without merge — manual triage required" |
OPEN | null | no change — leave in-review / in-progress | unchanged |
Record every transition you plan to make in a structured diff report (initiative id, old status → new status, PR number, merged/closed timestamp). Do not apply yet.
Print the full transition plan to the user:
Reconciliation plan for {plan-dir}:
{initiative-id-1}: in-review → merged (PR #{n}, merged {ISO})
{initiative-id-2}: in-progress → deferred (PR #{n} closed without merge)
{initiative-id-3}: in-review → (no change, PR still OPEN)
...
Skipped / errored:
{initiative-id-X}: gh pr view failed — {error}
Total transitions: {k} of {candidate-count} candidates.If k == 0 after filtering no-change + errored rows, report "No status transitions needed — every queried PR is still OPEN." and exit without creating a branch or PR.
main is branch-protected in this repo; commits must land via PR. Pick a branch name:
chore/reconcile-{plan-timestamp}-{YYYYMMDDHHMMSS}where {plan-timestamp} is the 20260417T120000Z-style prefix of the plan directory name and {YYYYMMDDHHMMSS} is UTC now. Example: chore/reconcile-20260417T120000Z-20260417163015.
git switch -c {branch-name} mainFor each in-flight transition:
initiatives[i].status to the new value.merged: set mergedAt to the GitHub-reported ISO string (not "now"). Confirm prUrl is non-null — it must be (the Step 1.4 candidate filter requires it; per the canonical required-when-merged contract a merged record MUST carry both prUrl and mergedAt). If prUrl is somehow null, fetch it via gh pr view <n> --json url and set it before writing.deferred: append the "PR #<n> closed without merge — manual triage required" note to notes (separator " | " if notes already non-empty).prUrl on a merged record.plan.md is a markdown table under its ### {order}. \{initiative-id}\ — {title} heading (canonical shape: ~/.claude/prompts/backlog-sweep-plan.md Step 8), with a | Status | {value} | row. Rewrite ONLY that row's value cell:merged → | Status | merged (PR #{n}, {YYYY-MM-DD from mergedAt}) |deferred → | Status | deferred (PR #{n} closed; see notes) |Write both files back. Keep JSON formatting stable (2-space indent, trailing newline if the original had one).
Stage the two files explicitly (never git add . or git add -A):
git add {plan-dir}/state.json {plan-dir}/plan.mdCommit with a descriptive message citing the transitions. Template:
chore(plan): reconcile {plan-timestamp} state — {merged-count} merged, {deferred-count} deferred
In-review reconciliation for backlog-sweep plan {plan-timestamp}.
Transitions:
- {id}: in-review → merged (PR #{n})
- {id}: in-progress → deferred (PR #{n} closed)
...
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>Use a HEREDOC for the -m payload so multi-line formatting survives.
git push -u origin {branch-name}
gh pr create --title "chore(plan): reconcile {plan-timestamp} state" \
--body "$(cat <<'EOF'
## Summary
- In-review reconciliation for `ai_docs/plans/{plan-dir}/`.
- {merged-count} initiatives transitioned to `merged`, {deferred-count} to `deferred`.
- Source of truth: `gh pr view` per PR at reconciliation time.
## Transitions
{bulleted list of id: old → new (PR #n, timestamp)}
## Test plan
- [x] `state.json` `schemaVersion` unchanged (2, 3, or 4)
- [x] Only status / mergedAt / notes fields changed per initiative
- [x] `plan.md` Status rows mirror state.json
- [x] No unrelated files modified
EOF
)"Default: squash-merge with branch deletion.
gh pr merge <num> --squash --delete-branchIf the merge is rejected (most likely: branch needs rebase onto newer main because another PR landed during the window):
git fetch origin maingit rebase origin/mainstate.json / plan.md — prefer last-writer-wins on the same initiative row, keep both when rows differ.git push --force-with-lease (NOT plain --force).gh pr merge <num> --squash --delete-branch.Emit a final structured summary:
Reconciliation complete.
Plan: {plan-dir}
Branch: {branch-name} (deleted)
PR: {url} (merged as <sha>)
Transitions applied:
merged: {k}
deferred: {j}
Skipped (still OPEN): {o}
Errored (gh pr view failed): {e} — {ids}
Post-reconciliation status buckets: {pending-count} pending, {in-review-count} in-review, {merged-count} merged, {obsolete-count} obsolete, {deferred-count} deferred.If all initiatives are now terminal (merged / obsolete / deferred), additionally note: "Plan fully shipped — run /backlog-sweep:execute Step 2 completion (marks completed: true + adds Refs entry) or prompt the user." — do NOT do that completion step yourself; that is the executor's job.
Worktree teardown discipline (Windows). After this skill completes, the orchestrator typically removes worktrees for merged initiatives via git worktree remove --force .worktrees/<id>. On Windows, VBCSCompiler.exe and MSBuild.exe build-server processes hold file-system locks on the worktree's bin/obj directories — git worktree remove will fail with Permission denied until those locks are released. The fix: call workspace_close(workspaceId: <id>, drainProcesses: true) for each loaded workspace BEFORE calling git worktree remove. The drainProcesses: true flag runs dotnet build-server shutdown after session disposal, which releases all out-of-process build-server locks. This step is a no-op when no build-server is running, so it is always safe to prepend.
{2,3,4} are refused.)state.json / plan.md → stop and hand off to the user; do not force-push away another contributor's edits.Input: /reconcile-backlog-sweep-plan ai_docs/plans/20260417T120000Z_backlog-sweep
Reconciliation plan for ai_docs/plans/20260417T120000Z_backlog-sweep:
mcp-connection-session-resilience: in-review → merged (PR #218, merged 2026-04-17T13:05:19Z)
mcp-server-surface-catalog-parity-generator: in-review → merged (PR #220, merged 2026-04-17T13:50:00Z)
observation-rows-obsoletion-sweep: in-review → merged (PR #221, merged 2026-04-17T15:35:00Z)
Total transitions: 3 of 3 candidates.
Proceeding to Step 4 (branch) → Step 8 (merge).
Branch: chore/reconcile-20260417T120000Z-20260417163015
Commit: a1b2c3d chore(plan): reconcile 20260417T120000Z state — 3 merged, 0 deferred
PR #223 opened, merged as f9e8d7c6.
Reconciliation complete.
Post-reconciliation status buckets: 34 pending, 0 in-review, 3 merged, 0 obsolete, 0 deferred.The executor prompt historically said "commit both edits on main". This repo has main branch protection enabled (see repo settings + recent PR history showing every merge goes through PR review). A direct push to main will be rejected at the server with remote rejected … protected branch hook declined. The short-lived branch + squash-merge pattern preserves the executor's intent (reconciliation lands on main) while respecting the branch-protection gate. When squash-merge lands, the commit message on main is identical to a direct commit would have been.
/ship-style PRs have merged, to mirror GitHub-observed state back into the plan files. Do not confuse: /ship runs per initiative; /reconcile-backlog-sweep-plan runs between initiative waves.ai_docs/backlog.md's Refs table, which is an executor concern, not a reconciliation concern.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.