Skill: Maintenance Architect — Dependency Health & Rot Control
Apply Guidelines Skill — load the guidelines-meta skill before proceeding.
Profile section owned: §Guardrails → do-not-touch and pinned-dependency rationale (Guidelines §5). Every deliberate non-upgrade gets recorded with its reason, so nobody re-litigates it in six months.
Why this skill exists: maintenance is the work that is never urgent until it is catastrophic. It falls between building and shipping, so it belongs to nobody and happens never — until a security advisory lands on a dependency four majors behind, and the upgrade that should have taken an afternoon takes a week. This skill makes it a routine with a defined scope instead of an emergency.
Operational Constraints (Strict)
- Never bundle an upgrade with a refactor. The single most valuable rule here. If an upgrade needs code changes, the upgrade is one change and the adaptation is a separate one where possible. Mixed diffs make
git bisect useless and turn a five-minute revert into an archaeology session.
- One batch, one class, one revert. Each batch must be revertible on its own (§Batching). A batch you cannot undo in one step is too big.
- Green before, green after — with the same gates. Establish a passing baseline first. Upgrading on top of an already-failing suite means you cannot attribute the failure, and you will blame the upgrade.
- Never upgrade to silence a warning you haven't read. Deprecation warnings name a migration path. Read it. Bumping the version to make the message go away, without following the migration, defers the break to a worse moment.
- Never weaken to pass. Not a suppression, not a skip, not a pinned-back transitive to dodge a real incompatibility (Testing Architect constraint 3). A suppression added during maintenance is rot created by rot-control.
- Git and golden-file guards are enforced by the plugin's PreToolUse hook (Guidelines §9, §10): every git write,
gh publish, --no-verify, and snapshot update is denied by the runtime; read-only inspection stays open. Lockfile changes stay unstaged. The lockfile is the rollback — surface git checkout <lockfile> as a command per module-handover §4; the hook denies it if you run it yourself.
- An upgrade is a deploy. Anything that reaches production goes through the
deployment-architect skill. A dependency bump is a production change wearing a smaller hat.
- Bounded (Guidelines §16). One inventory pass, one batch of changes, one verification round per batch. Not an open loop of nudging versions until CI turns green.
What to Read, and When
| Read |
When |
${CLAUDE_SKILL_DIR}/references/rot-sweep.md |
Phase 5 — the findings no gate reports because nothing fails. |
${CLAUDE_SKILL_DIR}/references/report-format.md |
Assembling the output. |
module-threat-model → references/triage.md |
Triaging an advisory by reachability. |
module-gate-battery |
Between batches, and for the visual-diff stop. |
module-handover |
The revert command, the lockfile rollback. |
Phase 1 — Inventory
Read, don't guess. Resolve <audit> and the rest from the profile.
| Source |
What it tells you |
<audit> output |
Known advisories, with severity and whether a fix exists |
The manifest vs. the registry (outdated equivalent) |
How far behind, and whether the gap is patch / minor / major |
| Build and test output |
Deprecation warnings — the pre-announcement of tomorrow's break |
| Lockfile |
Duplicate versions of the same package, and unexpected transitives |
| Runtime/engine constraints |
An LTS going end-of-life is a deadline with a date |
| The profile's pinned list |
What is deliberately held back, and why |
Distinguish direct from transitive. A transitive advisory is usually fixed by upgrading the parent, not by pinning the child — an override is a last resort that must be recorded with an expiry condition.
Phase 2 — Triage by Urgency, Not by Version Number
"Behind" is not a problem in itself. A stable dependency four minors behind, doing its job, is fine. Sort by consequence:
| Tier |
What qualifies |
Action |
| Now |
An advisory that is actually reachable in this codebase — the vulnerable function is called, on a path that handles untrusted input |
Fix immediately, alone, and ship it alone |
| Soon |
Advisory with no reachable path · runtime nearing end-of-life · a deprecation with an announced removal date |
Schedule it; do it while it is still cheap |
| Routine |
Patch and minor bumps, tooling, types |
Batch it (§3) |
| Deliberate hold |
Breaking major with no benefit here · a rewrite in disguise · a dependency being removed anyway |
Record the reason in the profile and stop re-examining it |
Reachability is the honest question for advisories (module-threat-model → references/triage.md), and it takes minutes to answer. "Critical" on a package used only by a build script that never sees untrusted input is not a production emergency — say so plainly rather than performing urgency. Equally, a "moderate" on a parser fed by user uploads deserves the Now tier. Never inflate a rating to look diligent, and never downgrade one to avoid work (Guidelines §15).
Phase 3 — Batch So a Break Is Attributable
Order matters — cheapest-to-verify and least-coupled first:
- Types and dev-only tooling — cannot reach production; break loudly at build time.
- Patch versions of direct dependencies — one batch, all together.
- Minor versions of direct dependencies — one batch, or split by subsystem if the surface is wide.
- Each major, individually. Never two majors in one batch. Never a major alongside anything else.
- Framework or runtime majors — their own change entirely, with their own plan via the
planning-architect skill. These are projects, not chores, and calling one a "bump" is how a week disappears.
Between every batch: run the gates (module-gate-battery). A batch that breaks something is reverted, not debugged in place — restore the lockfile, then split the batch and retry the halves. That is bisection, and it beats staring at a diff of forty version numbers.
Phase 4 — Verify Beyond Green
Gates prove the code compiles and the tests still pass. Upgrades break things gates do not watch:
- Read the changelog for anything with a behaviour change, not just a version diff. Silent behaviour changes in a patch release are common and are exactly what tests written before them will not catch.
- Bundle or artifact size — a dependency that doubled is a finding.
- The peer/engine graph — an unmet peer that resolves today but warns is tomorrow's break.
- Anything with a native or platform build step — verify on the target, not only locally.
- Visual and golden tests for anything touching rendering (
module-craft-floor, testing-architect). A styling dependency's minor bump moves pixels; that diff is surfaced and reviewed manually like any other (module-gate-battery §4).
- Lockfile churn — an unexpectedly large diff for a small bump means something transitive moved. Look before shipping.
Phase 5 — The Rot Sweep
The findings no gate reports, because nothing fails: suppressions, permanently-skipped tests masquerading as coverage, unused dependencies, dead code, stale TODOs, doc drift, config drift, duplicate transitives.
Read ${CLAUDE_SKILL_DIR}/references/rot-sweep.md. Run it periodically, report per module-findings, and fix only what the user approves — this phase generates a list, not a rewrite.
Cadence
Maintenance done on a schedule stays small; done on discovery, it is always an emergency.
- Every change set: the
<audit> gate already runs — do not ignore its output because it isn't today's task.
- Weekly-ish: patch and dev-tooling batch. Ten minutes.
- Monthly-ish: minors, deprecation warnings, and the rot sweep.
- Quarterly-ish: majors, one at a time, each with its own plan.
- Immediately: a reachable advisory. Alone, shipped alone.
(To automate the reminder rather than remember it, the /loop and /schedule commands can run this skill on an interval.)
Quality Checklist Before Claiming "Maintained"
v1.0 — version history in CHANGELOG.md
1---2name: maintenance-architect3description: Use for dependency upgrades, security advisories, deprecations, lockfile hygiene, and the rot sweep (suppressions, skipped tests, dead code, stale docs). Triages by reachability, batches upgrades so a break is attributable, records deliberate non-upgrades in the profile. Never bundles an upgrade with a refactor.4---56# Skill: Maintenance Architect — Dependency Health & Rot Control78> **Apply Guidelines Skill** — load the `guidelines-meta` skill before proceeding.9> **Profile section owned:** §Guardrails → do-not-touch and pinned-dependency rationale (Guidelines §5). Every deliberate *non*-upgrade gets recorded with its reason, so nobody re-litigates it in six months.101112**Why this skill exists:** maintenance is the work that is never urgent until it is catastrophic. It falls between building and shipping, so it belongs to nobody and happens never — until a security advisory lands on a dependency four majors behind, and the upgrade that should have taken an afternoon takes a week. This skill makes it a routine with a defined scope instead of an emergency.1314---1516## Operational Constraints (Strict)17181. **Never bundle an upgrade with a refactor.** The single most valuable rule here. If an upgrade needs code changes, the upgrade is one change and the adaptation is a *separate* one where possible. Mixed diffs make `git bisect` useless and turn a five-minute revert into an archaeology session.192. **One batch, one class, one revert.** Each batch must be revertible on its own (§Batching). A batch you cannot undo in one step is too big.203. **Green before, green after — with the same gates.** Establish a passing baseline *first*. Upgrading on top of an already-failing suite means you cannot attribute the failure, and you will blame the upgrade.214. **Never upgrade to silence a warning you haven't read.** Deprecation warnings name a migration path. Read it. Bumping the version to make the message go away, without following the migration, defers the break to a worse moment.225. **Never weaken to pass.** Not a suppression, not a skip, not a pinned-back transitive to dodge a real incompatibility (Testing Architect constraint 3). A suppression added during maintenance is rot created by rot-control.236. **Git and golden-file guards are enforced by the plugin's PreToolUse hook** (Guidelines §9, §10): every git write, `gh` publish, `--no-verify`, and snapshot update is denied by the runtime; read-only inspection stays open. Lockfile changes stay unstaged. **The lockfile is the rollback** — surface `git checkout <lockfile>` as a command per `module-handover` §4; the hook denies it if you run it yourself.247. **An upgrade is a deploy.** Anything that reaches production goes through the `deployment-architect` skill. A dependency bump is a production change wearing a smaller hat.258. **Bounded** (Guidelines §16). One inventory pass, one batch of changes, one verification round per batch. Not an open loop of nudging versions until CI turns green.2627---2829## What to Read, and When3031| Read | When |32|---|---|33| `${CLAUDE_SKILL_DIR}/references/rot-sweep.md` | Phase 5 — the findings no gate reports because nothing fails. |34| `${CLAUDE_SKILL_DIR}/references/report-format.md` | Assembling the output. |35| `module-threat-model` → `references/triage.md` | Triaging an advisory by reachability. |36| `module-gate-battery` | Between batches, and for the visual-diff stop. |37| `module-handover` | The revert command, the lockfile rollback. |3839---4041## Phase 1 — Inventory4243Read, don't guess. Resolve `<audit>` and the rest from the profile.4445| Source | What it tells you |46|---|---|47| `<audit>` output | Known advisories, with severity and whether a fix exists |48| The manifest vs. the registry (`outdated` equivalent) | How far behind, and whether the gap is patch / minor / major |49| Build and test output | Deprecation warnings — the pre-announcement of tomorrow's break |50| Lockfile | Duplicate versions of the same package, and unexpected transitives |51| Runtime/engine constraints | An LTS going end-of-life is a deadline with a date |52| The profile's pinned list | What is deliberately held back, and why |5354**Distinguish direct from transitive.** A transitive advisory is usually fixed by upgrading the parent, not by pinning the child — an override is a last resort that must be recorded with an expiry condition.5556---5758## Phase 2 — Triage by Urgency, Not by Version Number5960"Behind" is not a problem in itself. A stable dependency four minors behind, doing its job, is fine. Sort by consequence:6162| Tier | What qualifies | Action |63|---|---|---|64| **Now** | An advisory that is *actually reachable* in this codebase — the vulnerable function is called, on a path that handles untrusted input | Fix immediately, alone, and ship it alone |65| **Soon** | Advisory with no reachable path · runtime nearing end-of-life · a deprecation with an announced removal date | Schedule it; do it while it is still cheap |66| **Routine** | Patch and minor bumps, tooling, types | Batch it (§3) |67| **Deliberate hold** | Breaking major with no benefit here · a rewrite in disguise · a dependency being removed anyway | **Record the reason in the profile** and stop re-examining it |6869**Reachability is the honest question** for advisories (`module-threat-model` → `references/triage.md`), and it takes minutes to answer. "Critical" on a package used only by a build script that never sees untrusted input is not a production emergency — say so plainly rather than performing urgency. Equally, a "moderate" on a parser fed by user uploads deserves the Now tier. **Never inflate a rating to look diligent, and never downgrade one to avoid work** (Guidelines §15).7071---7273## Phase 3 — Batch So a Break Is Attributable7475Order matters — cheapest-to-verify and least-coupled first:76771. **Types and dev-only tooling** — cannot reach production; break loudly at build time.782. **Patch versions of direct dependencies** — one batch, all together.793. **Minor versions of direct dependencies** — one batch, or split by subsystem if the surface is wide.804. **Each major, individually.** Never two majors in one batch. Never a major alongside anything else.815. **Framework or runtime majors — their own change entirely**, with their own plan via the `planning-architect` skill. These are projects, not chores, and calling one a "bump" is how a week disappears.8283Between every batch: run the gates (`module-gate-battery`). A batch that breaks something is **reverted, not debugged in place** — restore the lockfile, then split the batch and retry the halves. That is bisection, and it beats staring at a diff of forty version numbers.8485---8687## Phase 4 — Verify Beyond Green8889Gates prove the code compiles and the tests still pass. Upgrades break things gates do not watch:9091- **Read the changelog for anything with a behaviour change**, not just a version diff. Silent behaviour changes in a patch release are common and are exactly what tests written before them will not catch.92- **Bundle or artifact size** — a dependency that doubled is a finding.93- **The peer/engine graph** — an unmet peer that resolves today but warns is tomorrow's break.94- **Anything with a native or platform build step** — verify on the target, not only locally.95- **Visual and golden tests** for anything touching rendering (`module-craft-floor`, `testing-architect`). A styling dependency's minor bump moves pixels; that diff is surfaced and reviewed manually like any other (`module-gate-battery` §4).96- **Lockfile churn** — an unexpectedly large diff for a small bump means something transitive moved. Look before shipping.9798---99100## Phase 5 — The Rot Sweep101102The findings no gate reports, because nothing fails: suppressions, permanently-skipped tests masquerading as coverage, unused dependencies, dead code, stale TODOs, doc drift, config drift, duplicate transitives.103104**Read `${CLAUDE_SKILL_DIR}/references/rot-sweep.md`.** Run it periodically, report per `module-findings`, and **fix only what the user approves** — this phase generates a list, not a rewrite.105106---107108## Cadence109110Maintenance done on a schedule stays small; done on discovery, it is always an emergency.111112- **Every change set:** the `<audit>` gate already runs — do not ignore its output because it isn't today's task.113- **Weekly-ish:** patch and dev-tooling batch. Ten minutes.114- **Monthly-ish:** minors, deprecation warnings, and the rot sweep.115- **Quarterly-ish:** majors, one at a time, each with its own plan.116- **Immediately:** a reachable advisory. Alone, shipped alone.117118*(To automate the reminder rather than remember it, the `/loop` and `/schedule` commands can run this skill on an interval.)*119120---121122## Quality Checklist Before Claiming "Maintained"123124- [ ] Inventory read from real output — advisory counts and versions never estimated (Guidelines §15).125- [ ] Advisories triaged by **reachability**, not by their headline severity; the reasoning is stated.126- [ ] Green baseline established **before** any change.127- [ ] Batches are single-class and independently revertible; no two majors together.128- [ ] No upgrade bundled with a refactor.129- [ ] Changelogs read for anything with a behaviour change — not just version numbers compared.130- [ ] Bundle/artifact size and lockfile churn checked.131- [ ] Visual diffs from styling dependencies surfaced for manual review, never auto-accepted.132- [ ] Nothing suppressed, skipped, or pinned back to force a pass.133- [ ] Deliberate holds recorded in the profile with a reason and a revisit condition.134- [ ] Rot sweep reported as findings; nothing deleted without approval.135- [ ] **No `git add`, `commit`, or `push`** — lockfile changes left unstaged for the user.136137---138139_v1.0 — version history in CHANGELOG.md_