plans/026-make-cache-maintenance-environment-explicit-and-safe.md
Plan 026: Make cache maintenance environment-explicit and safe
Executor instructions: Read this plan completely. Run each gate and preserve end-to-end behavior except the stated correction. Do not add unit or integration tests. Use disposable data for real-system proof. Stop rather than improvise when a STOP condition occurs. Update this plan's row in
plans/README.mdwhen done unless a reviewer owns the index.Drift check (run first):
git diff --stat 878c937..HEAD -- scripts/clear-kv-cache.ts packages/api/src/lib/cache package.json README.mdExpected: empty. If non-empty, compare every excerpt and named symbol to live code; semantic mismatch is a STOP condition.
Status
- Accepted audit ID: P-05
- Priority: P0
- Effort: M
- Risk: HIGH
- Depends on: none
- Category: security
- Suggested triage label:
needs-info - Planned at: commit
878c937c3621ab35002e453da563f6ba551d6e86, 2026-07-18
Why this matters
The cache utility defaults to all targets, mutates a tool-private local format, and can target a fixed remote environment. It must do no I/O without an explicit environment and preview, or be deleted if unowned.
Current state
Baseline source: scripts/clear-kv-cache.ts:107-114
| 1 | |
| 2 | async function main() { |
| 3 | const target = process.argv[2] || "all"; |
| 4 | |
| 5 | let keysToDelete: string[] = []; |
| 6 | |
| 7 | switch (target) { |
| 8 | case "brands": |
Domain and repository rule
Cache invalidation belongs with the code that constructs keys. Never expose fixed identifiers or operational deletion recipes, and never use production as proof.
Existing-issue coordination
Coordinate with cache ownership work in #125.
Commands you will need
| Purpose | Command | Expected on success |
|---|---|---|
| Baseline drift | git diff --stat 878c937..HEAD -- scripts/clear-kv-cache.ts packages/api/src/lib/cache package.json README.md | empty, or excerpts revalidated before work |
| Type safety | bun run check-types | exit 0, no type errors |
| Build | bun run build | exit 0 |
| Changed files | git diff --name-only | only in-scope files plus plans/README.md status update |
Package-focused commands may replace root checks only when every changed workspace is covered. Real proofs below require an operator-provided local/staging environment and configured credentials/bindings; never print them.
Scope
In scope
- cache/analytics owner decision
- delete utility if unowned, or redesign with explicit environment and non-destructive preview
- remove stale catalog modes/private storage mutation
Files/path families allowed
scripts/clear-kv-cache.tspackages/api/src/lib/cachepackage.jsonREADME.md
Out of scope
- running any baseline purge
- production/shared namespace proof
- printing identifiers/credentials
- changing application cache semantics
Git workflow
- Branch:
audit/p-05-make-cache-maintenance-environment. - Commit small logical units using the repository's conventional style, for example
fix(storev2): ...orchore(api): .... - Do not push or open a PR unless the operator explicitly instructs it.
Steps
Step 1: Owner confirms whether the utility remains needed and which cache code owns current keys
Owner confirms whether the utility remains needed and which cache code owns current keys.
Verify: git grep -n -E 'clear-kv-cache|clearLocalKV|clearRemoteKV|process.argv\[2\]|cache' -- scripts/clear-kv-cache.ts packages/api/src/lib README.md NOTES.md package.json → inventories current key owner, baseline implicit target, and documentation; record whether the utility remains owned.
Step 2: If retained, require explicit environment, derive keys from owner, and make default invocation fail with usage before I/O; add preview/confirmation before remote action
If retained, require explicit environment, derive keys from owner, and make default invocation fail with usage before I/O; add preview/confirmation before remote action. Otherwise remove utility/docs.
Verify: bun scripts/clear-kv-cache.ts > /tmp/cache-maintenance-default.out 2>&1; test $? -ne 0; ! git grep -n -E 'process.argv\[2\] \|\| "all"|clearLocalKV|sqlite|namespace' scripts/clear-kv-cache.ts → command exits 0 only when default invocation fails before I/O and the scan finds no implicit-all, private-storage, or fixed-target implementation.
Step 3: Prove only against a disposable local namespace after implementation approval
Prove only against a disposable local namespace after implementation approval. Never invoke the baseline script.
Verify: Prerequisites/setup: Cache owner decision and disposable local namespace; baseline script must never be run against remote/shared state.
Bounded procedure: Run retained command with no args, preview explicit local scope, confirm, and inspect only disposable keys before/after.
Machine-observable expected result: No-arg exits before I/O; preview is non-destructive; confirmed local run changes only selected disposable keys; no fixed remote target is exposed.
Cleanup: Delete disposable namespace/keys through the same local owner API; never use production for proof.
No unit or integration tests are requested. Do not use production Customer data, destructive operations, or remote writes as proof.
Done criteria
- The path-scoped drift check was empty or every changed excerpt was revalidated.
- All ordered steps completed without crossing scope.
P-05correction is observed through the real boundary described above.- Applicable existing static/build commands exit 0.
git diff --name-onlycontains only the allowed source paths and the plan status update.- No secret, Customer data, destructive command output, or unsafe operational detail appears in commits/reports.
STOP conditions
- Current code no longer matches the baseline excerpt or required behavior.
- Ownership/use is unknown.
- Environment cannot be selected unambiguously.
- Proof would touch remote/shared data or key ownership is stale.
- A verification fails twice after one reasonable correction, or implementation requires an out-of-scope file.
Maintenance notes
Operational cache tools must be environment-explicit, previewable, and owned by key-producing code.