Remove an optional subsystem
Remove a provider or feature completely across code, configuration, tests, and claims.
Remove an optional subsystem
When to use
Use this path when a buyer does not need a distributed optional integration or subsystem and wants to remove its code, dependencies, configuration, support surface, and claims. Examples include Sentry, Slack notifications, object-storage uploads, or billing when the resulting product contract deliberately excludes that capability.
Disabling a key is not removal. Keep the subsystem when near-term use and update support justify its maintenance cost. Remove it when a smaller dependency, data-processing, security, and operational surface is the intended product outcome.
Files and boundaries
Inventory every applicable layer before editing:
- package manifests, workspace configuration, install policy, and
pnpm-lock.yaml; - application imports, initialization, providers, hooks, routes, adapters, and types;
- shared Zod contracts and generated Hono client consumers;
- environment schemas, examples, generated
.envfiles, deployment ownership, and CI secrets; - database tables, migrations, indexes, triggers, seed data, and backup assumptions;
- proxy/tunnel routes, CSP/CORS rules, PWA behavior, build plugins, and deployment configuration;
- tests, fixtures, docs, agent rules, architecture diagrams, product copy, pricing, and support claims;
packages/create-apprewrite/filter logic and the final generated buyer repository.
Historical ADRs and explicitly historical documents may retain the name with clear context. Current buyer and sales claims may not.
Procedure
-
State the capability being removed, the buyer outcome, whether stored data exists, and the supported replacement or deliberate absence. Get explicit approval before deleting live data or an external provider project.
-
Capture a pre-change inventory:
rg -n -i "subsystem|package-name|ENV_PREFIX" . \ -g '!node_modules/**' -g '!**/dist/**' -g '!docs/phase2/**' pnpm --filter <owning-workspace> why <package-name> -
Classify each hit as runtime, build, environment, persistence, test, documentation, commercial claim, generated artifact, or intentional history. Write the expected removal list before editing so an empty search is meaningful evidence.
-
Remove top-down entry points first so the compiler exposes dependents: initialization/providers, user flows, domain routes/services, provider adapters, configuration constants, then packages.
-
Remove environment variables from examples, validators, deployment maps, CI, hosting settings, and setup docs. A removed integration must not leave a secret request or silent no-op.
-
Remove provider-specific routes, tunnels, webhooks, CSP/CORS hosts, source-map upload plugins, scheduled triggers, or public callbacks that no longer have an owner.
-
If persisted data exists, design a reversible retirement migration and export/retention policy. After a release, never edit an applied migration. Before the first commercial tag, follow the documented baseline exception and prove
up → down → up. -
Remove dependencies with the package manager and regenerate—not hand-edit—the lockfile:
vp install --lockfile-only vp install --frozen-lockfile -
Repeat the inventory search. Inspect remaining lockfile/package hits with
pnpm why; a transitive occurrence is not residue when another retained package owns it. -
Run checks, tests, builds, zero-key setup, and dependency audit. Exercise the nearest affected UI and failure boundary.
-
Generate a custom-scope/custom-brand buyer app, repeat frozen install/check/test/build there, and verify the removed subsystem is absent from buyer source, environment, and direct lockfile importers.
-
Record exact changed files, commands, scan exclusions, package-count change, failures, and interventions. A same-context author rehearsal is useful engineering evidence but is not a cold-agent claim.
Verification
Minimum:
vp install --frozen-lockfile
vp check
vp run -r test
vp run -r build
pnpm audit --audit-level high
rg -n -i "subsystem|package-name|ENV_PREFIX" . \
-g '!node_modules/**' -g '!**/dist/**' -g '!docs/phase2/**'For a generated buyer, also inspect git diff --name-status, the owning package.json,
pnpm-lock.yaml importers, .env.example, initialization, build configuration, current docs, and
the production bundle. If persistence changes, run disposable-database migration reversal and domain
integration tests.
Security constraints
- Do not delete live provider projects, buckets, data, webhooks, domains, or secrets without exact target resolution and explicit authority.
- Remove public callbacks, tunnels, allowed origins, and secret inputs when their handler is gone.
- Preserve audit/export/retention obligations before dropping customer data.
- Never paste provider credentials into scans, evidence, test fixtures, git diffs, or Linear.
- Do not weaken CSP, authentication, error handling, or test coverage merely to remove an adapter.
- Verify logout/session cleanup when removing analytics or identity integrations that retain a browser identity.
- Treat package removal as supply-chain change: update the canonical lockfile and rerun the audit.
Failure modes
- Build still imports the package: an entry point, hook, provider, or lazy route remains.
- Frozen install reports lock drift: the manifest changed without regenerating
pnpm-lock.yaml. - Search finds an environment key: setup, CI, Vercel/Railway/Dokploy configuration, or docs still request it.
- A route returns 404 unexpectedly: a shared route tree was removed with the optional branch.
- Historical docs fail the residue scan: narrow the exclusion to clearly marked history; do not delete decision evidence to manufacture zero results.
- The package remains in the lockfile: use
pnpm whyto distinguish direct importer residue from a legitimate transitive owner. - A generated app still contains it: create-app copied a studio-only file, stale lock importer, generated environment, or excluded path.
- Product copy still promises the capability: engineering removal and commercial scope diverged.
Rollback and diagnosis
Restore the smallest reviewed commit or patch containing the full vertical slice, regenerate the lockfile, and rerun the same verification. Restore environment values from the deployment secret manager, never from documentation or git.
If data was retired, execute the reviewed down/restore plan only against the resolved target and confirm row/object counts before and after. If no reversible data path exists, the removal is destructive and requires explicit approval before execution.
Acceptance criteria
- The removal inventory covers source, package, environment, persistence, CI, deployment, tests, docs, generated buyers, and commercial claims.
- No orphan direct dependency, importer, initialization, route, migration assumption, environment key, deployment setting, or current claim remains.
- Remaining search/lockfile hits are classified and owned.
- No-key local setup, frozen install, audit,
vp check, tests, and builds pass. - A custom-scope/custom-brand generated buyer passes the same path without the subsystem.
- Data retention and rollback are explicit when persistence is involved.
- Evidence distinguishes author rehearsal from genuinely cold execution.
Agent prohibitions
- Do not call a feature removed merely because its key is unset.
- Do not hand-edit
pnpm-lock.yamlor generated artifacts. - Do not delete shared infrastructure based only on a matching filename.
- Do not edit a shipped migration to erase history.
- Do not delete an external resource or customer data without explicit authority.
- Do not leave compatibility stubs, dead environment variables, empty routes, or stale sales claims.
- Do not claim a cold removal when the same agent authored the runbook or knew the expected diff.