A maintenance sweep is a periodic, whole-repo tidy that gets the project back to a clean,
consistent, shipped baseline: no stray branches, nothing waiting in PR limbo, docs/notes/README that
match the code, and a green release on main. It is the "close the books" pass you run after a burst of
feature work has left branches, PRs, and current-state docs drifting from reality.
This is a project runbook — it is the local, random-ai-prompt-specific record of a procedure this
node also proposed to the fairyfox hub for cross-project adoption
(see ../fairyfox-reports/2026-07-09-propose-maintenance-sweep-standard.md).
It composes existing standards rather than inventing new rules: it leans on
git-workflow.md (branch model + ship path), repo-hygiene.md
(tidy/doc guards), versioning.md, and the "Maintaining the Notes" +
"Keep the Legal Docs Accurate" standing instructions in CLAUDE.md.
When to run it
- On request ("full maintenance / clean things up / full sweep").
- After merging several feature branches, when the branch list and current-state docs have drifted.
- Before or right after a release, to make sure
devandmainare in sync and nothing is orphaned. - On a cadence (e.g. monthly) as a standing hygiene pass.
It is not a substitute for the per-change discipline (each change still updates its own docs, notes, and tests). The sweep catches what slipped through and reconciles the whole tree at once.
The procedure
Run everything from the repo root. On this Windows machine, use PowerShell (not the Cowork bash
sandbox — it has reported false file truncations; see fix-patterns.md).
1. Audit the git + GitHub state (read-only first)
git fetch --all --prune
git branch -vv # local branches + tracking
git branch -r # remote branches
git branch --no-merged dev # LOCAL branches with unmerged work
git branch -r --no-merged origin/dev # REMOTE branches with unmerged work
gh pr list --state open
gh issue list --state open
gh run list --branch dev -L 3 # CI health
The goal is a complete picture before touching anything: which branches are fully merged (safe to delete), which carry unmerged work (must be surfaced, never silently dropped), and what is open on GitHub.
2. Triage open PRs and issues — surface, don't auto-act
Per the "GitHub Is Part of Default Management" standing instruction, never merge, close, or push to a PR without an explicit go-ahead. For each open PR/issue, summarize it and ask what to do (merge / close / leave). A Dependabot PR is still a decision: merging adopts new dependency versions; closing discards them. Get the owner's call, then act on the answer. If unattended, report and wait.
3. Close merged feature branches (local + remote)
Only after confirming they are fully merged (step 1). Deleting a branch with unmerged commits loses work.
git branch -d <merged-branch> ... # -d refuses an unmerged branch (safety)
git push origin --delete <merged-remote> ... # remote
Target end state: only main and dev on both the local checkout and GitHub (plus any branch the
owner explicitly wants to keep, and short-lived release/*/hotfix/* in flight).
4. Ship dev → main (if the owner wants a release)
Follow git-workflow.md exactly — this runbook does not replace it:
- Confirm
devis green (gh run list --branch dev -L 1). - Keep
VERSION+package.jsonin sync; bump per SemVer level only if the change warrants it. Docs/notes/test/CI-only changes (including a dev-dependency-only bump) do not move the number — in that casemainsimply advances with no new tag, which is correct. - PATCH: PR
dev → main; MINOR/MAJOR: via arelease/X.Y.0branch. Merge withgh pr merge <#> --merge(a merge commit — never squash/rebase). Do not hand-tag;release.ymlderives and applies the tag. - After the merge, back-merge so
devcontainsmain:git fetch origin && git switch dev && git merge --ff-only origin/main && git push origin dev. Skipping this is what once leftdevmany commits behindmain.
5. Doc / notes / README consistency sweep
Reconcile every current-state surface with the code as it actually is now:
notes/status.md— the biggest drift magnet. Fix theVERSIONline, retire "pending review/release" phrasing for branches that have shipped, and refresh the Build/run-health and Open-issues tables with real, just-run numbers (don't copy stale ones).README.md— features, editions, install paths, and version-driven badges accurate.- Changelog / sessions — confirm the feature history the sweep is trimming from
status.mdis preserved innotes/version/YYYY-MM.md; append a session entry for the sweep itself. list-credits.mdand the three legal pages (targets/web/public/legal/) — per their standing instructions, update if any data practice or credited contribution changed (a pure cleanup usually touches neither — confirm rather than assume).- Renamed/removed refs —
git grep -n "<old-name>" -- "*.md"for stale prose;npm run check:docsfor broken links.
6. Verify — before and after
npm test # check:docs · lint · smoke · test:unit · test:web (the headless gate)
npm run check:tidy # no untracked, non-ignored files left behind
For deeper changes also run npm run test:all (adds Playwright E2E/visual/perf). Record the actual pass
numbers in status.md. Only claim a check passed if you ran it this sweep; mark CI-only checks as such.
7. Commit + record
- Stage explicit paths (never
git add -A), focusedtype: summarycommits, changelog entry in the same commit (per "Maintaining the Notes"). - Append a
notes/sessions/YYYY-MM/YYYY-MM-DD.mdentry for the sweep. - If the sweep was run as a fairyfox procedure, write the process report
(
notes/fairyfox-reports/, perprocess-reports.md).
Safety rules (absolute)
- Never delete a branch with unmerged commits.
git branch -d(not-D) is the guard; verify with--no-mergedfirst. - Never auto-act on a PR/issue (merge/close/push) without an explicit go-ahead.
- Never
push --force, rewrite pushed history,reset --hard, or deletemain/dev. - Inspect
git statusbefore and after. Full standards:git-workflow.md.
Verify
git branch -randgit branchshow onlymain,dev(+ any deliberately-kept branch).gh pr list --state openis empty or every entry is one the owner chose to keep.devcontainsmain(git merge --ff-only origin/mainondevis a no-op).npm testandnpm run check:tidyare green;status.mdnumbers match the run.notes/status.mdVERSIONline equals the repo-rootVERSION.