Skip to content

feat(minikube): implement deterministic resource ownership, complete destroy, doctor and garbage collection #26

Description

@artiphishle

Summary

Implement complete, deterministic local resource ownership and lifecycle management for the current Infra 1.x Minikube architecture.

The architecture baseline is now:

one app
→ one canonical app slug
→ one Minikube profile with that exact slug
   ├── namespace app
   ├── namespace supabase (when Supabase-backed runtime is enabled)
   └── provider-owned namespaces (for example cerbos)

There is no shared/default minikube profile and no host Supabase Docker Compose runtime.

This issue must make the lifecycle around that architecture complete and deterministic so that:

  • up is idempotent and interruption-safe;
  • down is non-destructive and preserves the app-owned Minikube profile/data;
  • destroy removes the entire app-owned Minikube profile plus every other app-owned host/runtime resource managed by Infra;
  • generated host files such as .env.local have explicit key ownership and safe cleanup;
  • stale Ankhorage resources can be diagnosed and safely garbage-collected without global prune commands;
  • host Docker application images, Minikube/KIC images and build cache have explicit ownership/reference rules;
  • failed or interrupted lifecycle operations remain recoverable;
  • no unrelated Docker, Minikube, Kubernetes or filesystem resource is ever deleted by fuzzy naming alone.

Deliver all Infra-repository work for this issue in one comprehensive PR, including implementation, tests, generated documentation, public contracts where required, a changeset, and complete repository validation.


Current architecture baseline

The implementation must preserve the architecture introduced by the Infra 1.0 Minikube rewrite.

Canonical identity

appManifest.metadata.slug is the sole canonical local app identity.

For app slug scanner:

app slug          scanner
Minikube profile  scanner
app namespace     app
Supabase namespace supabase
provider namespaces deterministic per provider

The generated profile name must never fall back to a shared/default minikube profile.

Supabase ownership

Self-hosted Supabase is Kubernetes-owned inside the app's own Minikube profile.

Do not introduce or restore:

  • host supabase start / supabase stop / supabase status runtime ownership;
  • host Supabase Docker Compose containers;
  • project-specific Supabase Compose networks;
  • project-specific Supabase Compose volumes;
  • hybrid host-Compose + Kubernetes lifecycle handling.

The Supabase CLI remains a migration/development tool where already used, not the runtime owner.

Current lifecycle baseline

Generated lifecycle currently follows these broad semantics:

  • up.sh: start/reconcile the app-owned Minikube profile, provider namespaces and workloads, migrations, runtime secrets, forwards and app rollout;
  • down.sh: stop slug-owned forwards and minikube stop -p <slug>; persistent data remains in the profile;
  • reset.sh: explicit destructive reset of generated namespaces/data inside the existing profile;
  • destroy.sh: stop slug-owned forwards and delete only minikube -p <slug>;
  • status.sh: inspect the generated app profile/runtime;
  • port-forward.sh: own named slug-scoped forwards with PID/command ownership checks.

This issue extends and hardens these semantics. It must not replace them with the old shared-cluster or host-Supabase model.


Relationship to completed work

Infra 1.0 Minikube rewrite

The Infra 1.0 architecture already established:

  • one Minikube profile per canonical app slug;
  • app namespace;
  • supabase namespace;
  • deterministic provider namespaces;
  • generated lifecycle scripts;
  • slug-owned named forwards;
  • no host Supabase Compose runtime;
  • safe forward PID ownership verification;
  • real two-profile Minikube/Supabase E2E coverage.

This issue must build on those guarantees, not duplicate or weaken them.

PR #36 / generated .env.local

PR #36 added the write-side environment ownership contract for local Expo/Metro development:

${APP_SOURCE_DIR}/.env.local
  EXPO_PUBLIC_SUPABASE_URL
  EXPO_PUBLIC_SUPABASE_ANON_KEY

Infra updates only those browser-safe public keys and preserves unrelated user content.

This issue must complete the cleanup-side ownership contract: destructive lifecycle/GC must remove only Infra-managed entries and must never delete unrelated .env.local content.

Historical issues

Older descriptions of project-specific Supabase Docker containers, Compose networks/volumes and one shared Minikube cluster are obsolete and must not be reintroduced.


Core design principles

1. Explicit ownership

Every resource created or adopted by Ankhorage Infra must have authoritative ownership evidence.

Use the strongest available identity mechanism for each resource type, for example:

  • canonical app slug;
  • exact Minikube profile name;
  • Ankhorage/project Docker image labels;
  • immutable image IDs/digests;
  • Kubernetes labels plus exact GVK/namespace/name/UID where useful;
  • atomically written runtime/profile ledgers;
  • PID plus verified command identity for local processes;
  • explicit managed-environment-key metadata;
  • exact paths inside the generated Infra directory for runtime state.

Do not rely only on fuzzy prefixes, suffixes or repository substring matching.

Deletion of host-side resources must require both:

  1. exact canonical app identity; and
  2. verifiable evidence that the resource belongs to that app or to Ankhorage-managed shared infrastructure.

Ambiguous resources are reported, not deleted.

2. App-owned profile versus shared host assets

Each app owns its own complete Minikube profile.

App-owned resources

Examples:

  • Minikube profile/container for the canonical app slug;
  • Minikube profile storage/volume owned by that profile;
  • all Kubernetes resources inside that app-owned profile;
  • generated provider namespaces and PVC data inside that profile;
  • generated app image tags/digests owned by the app in the host Docker engine;
  • generated app images loaded into the app's Minikube node/container runtime;
  • slug-owned port-forward/helper processes;
  • PID metadata, lifecycle locks, transaction journals and runtime ledger state;
  • Infra-managed environment entries in user-editable files;
  • Infra-generated runtime credentials/state where ownership is explicit.

Shared host assets

Examples:

  • Minikube KIC base images used by multiple app profiles;
  • pinned Supabase service images cached in the host Docker engine;
  • Minikube caches shared by multiple profiles;
  • Ankhorage-owned buildx builder/cache scope if one is introduced;
  • unrelated Docker resources;
  • unrelated Minikube profiles.

Shared assets may be removed only after authoritative reference checks.

Destroying app A must never remove a shared asset still required by app B.

3. No global pruning

Normal lifecycle and GC must never use broad destructive commands such as:

docker system prune
docker network prune
docker volume prune
docker image prune -a
docker builder prune -a
minikube delete --all
minikube delete --purge

Enumerate and remove only exact Ankhorage-owned resources whose ownership and references are proven.


Runtime/profile ledger requirements

Introduce or extend an atomically written typed runtime ledger for each generated app profile.

The exact schema should follow repository conventions, but conceptually it must record enough information to safely reconcile, diagnose, destroy and garbage-collect resources, for example:

{
  "schemaVersion": 1,
  "projectId": "scanner",
  "appSlug": "scanner",
  "minikubeProfile": "scanner",
  "namespaces": ["app", "supabase", "cerbos"],
  "kubernetesResources": [],
  "hostImages": [],
  "minikubeImages": [],
  "processes": [],
  "managedEnvironmentEntries": [],
  "sharedImageReferences": [],
  "state": "up",
  "transactionId": "..."
}

Use exact stable identifiers wherever available:

  • Minikube profile name and driver container ID;
  • Docker image IDs and repository digests;
  • Kubernetes GVK/namespace/name/UID when useful;
  • process PID plus command identity/start metadata where portable;
  • managed file path plus exact managed keys;
  • transaction/run ID.

Ledger writes must be atomic.

Interrupted writes must not produce a valid-looking partial ledger.

Do not delete the ledger before cleanup verification succeeds; failed cleanup must retain enough ownership state for safe retry.

A separate host-level index/registry may be introduced if needed for reference counting shared images/caches across app-profile ledgers.


Concurrency and interruption safety

Add project lifecycle locking so conflicting operations for the same app profile cannot overlap, including:

up + up
up + down
up + reset
up + destroy
down + destroy
reset + destroy

Handle at least:

  • normal process exit;
  • command failure;
  • SIGINT;
  • SIGTERM;
  • stale lock detection;
  • retry after partial cleanup.

The lock identity must be app/profile scoped. Operations on app A must not unnecessarily block independent lifecycle operations on app B.

doctor must remain read-only. If a lifecycle mutation is active, it may report that state rather than mutating or stealing a valid lock.


Required lifecycle model

Expose the lifecycle through the existing generated Infra architecture/scripts/API. Exact public naming may follow repository conventions.

up

Idempotently create or reconcile one app-owned profile.

Required phases:

  1. acquire the app/profile lifecycle lock;
  2. resolve the canonical app slug/profile identity;
  3. load desired state and existing runtime ledger;
  4. run a read-only preflight and detect conflicting/unowned host resources;
  5. ensure the app-owned Minikube profile exists without silently changing its base-image identity;
  6. reconcile generated namespaces/providers/Supabase/app runtime;
  7. resolve and synchronize runtime/public environment values;
  8. run migrations/reconciliation/readiness checks;
  9. start/reconcile named slug-owned forwards;
  10. verify postconditions;
  11. atomically commit the runtime ledger only after success;
  12. release the lock.

Repeated up must not create duplicate:

  • Minikube profiles;
  • app image ownership records;
  • loaded app images;
  • port-forward processes;
  • runtime ledger entries.

If first-time creation fails, roll back only resources newly created by that failed operation where safe.

If reconciliation of an existing profile fails, do not destroy pre-existing persistent database/storage state as rollback.

The existing partial-failure forward cleanup behavior must remain intact.

down

down is non-destructive.

Required result:

  • stop all slug-owned named forwards/helpers started by Infra;
  • stop the canonical app-owned Minikube profile with minikube stop -p <slug> or equivalent exact-profile operation;
  • preserve the profile and its persistent provider data;
  • preserve Auth users, database tables/data, Storage objects and Vault data;
  • preserve reusable app/provider images as cache unless another explicitly safe policy applies;
  • update runtime state/ledger to down only after the operation succeeds;
  • verify forwards are stopped and the exact app profile is not running.

Do not individually delete Supabase runtime resources or provider namespaces as part of normal down.

down A must not affect profile B or its forwards.

reset

Keep reset distinct from destroy.

Reset is explicitly destructive to generated runtime/provider state inside the existing app-owned profile.

Requirements:

  • require explicit app-slug confirmation;
  • stop slug-owned forwards before mutation;
  • operate only on generated/provider namespaces belonging to the app profile;
  • delete/recreate generated namespaces/data according to current provider contracts;
  • do not delete the Minikube profile itself;
  • do not delete host app images unless reset semantics explicitly require and document it;
  • preserve unrelated host resources and unrelated profiles;
  • leave the profile ready for a subsequent up;
  • update ledger state accurately.

Where provider-specific reset semantics differ, provider lifecycle contracts should contribute the required resources/actions rather than adding fragile hard-coded special cases.

destroy

destroy is destructive, app-scoped teardown.

Because one app owns one complete Minikube profile, the canonical Kubernetes cleanup primitive is deletion of the exact canonical app profile, not manual deletion of every namespace/resource before deleting the profile.

However, destroy must also clean every app-owned resource that exists outside the Minikube profile.

Require explicit confirmation before destructive data removal. The confirmation must be bound to the canonical app slug/profile.

Required destroy sequence

At minimum:

  1. acquire lifecycle lock;
  2. resolve canonical slug/profile and load ownership ledger;
  3. discover current owned resources independently of the ledger;
  4. stop verified slug-owned forwards/helper processes;
  5. delete the exact app-owned Minikube profile;
  6. wait for and verify profile/container/profile-storage deletion;
  7. remove app-owned generated application images from the host Docker engine using exact ownership evidence;
  8. remove app-owned/superseded generated application images from the Minikube node/runtime where still applicable and observable before/while profile deletion;
  9. clean Infra-managed host environment entries and runtime state;
  10. remove stale verified PID/lock/transaction state;
  11. perform an independent residual-resource discovery pass;
  12. only after zero owned residuals remain, remove/finalize the runtime ledger and report success.

Minikube profile

Destroy must delete only the exact canonical app profile:

minikube delete -p <app-slug>

or an equivalent exact-profile implementation.

It must never delete another profile, use --all, or assume a shared/default profile.

Verify that the profile and its driver container/storage are actually gone before success.

Kubernetes resources

All generated Kubernetes resources inside the app-owned profile are considered part of that profile's ownership boundary.

Do not reintroduce complex shared-namespace assumptions from the old architecture.

Before profile deletion, explicit Kubernetes inventory may still be recorded/used by doctor and for diagnostics, but destroy success ultimately requires the app-owned profile itself to be gone.

Local processes

Remove/stop:

  • slug-owned named forwards;
  • tunnels/proxies/helpers started by Infra;
  • stale PID files only after validating process ownership;
  • lifecycle transaction state after completion.

Never terminate a live PID solely because a stale PID file contains that number. Reuse the existing verified process-command ownership model.

Host Docker application images

Remove:

  • the current generated app image owned by the project;
  • superseded app image IDs left by repeated builds;
  • dangling image records caused when the canonical app tag moved;
  • project-specific intermediate/output images where Infra can prove ownership.

Generated app images must use deterministic tags plus Ankhorage/app ownership labels or equivalent authoritative metadata.

Removal must use exact IDs/digests and ownership records, not fuzzy repository substring matching.

Do not remove shared Supabase service images merely because one app was destroyed.

Images inside Minikube

Track and remove app-owned generated application images from the app profile's Minikube/container-runtime image store where possible before profile deletion.

Destroy verification must independently account for host image ownership and profile deletion; removing only the host image is not sufficient while a profile still exists.

Once the app profile is deleted, its internal image store disappears with the profile.

Runtime secrets and environment state

Infra writes browser-safe Supabase values to:

${APP_SOURCE_DIR}/.env.local

with currently managed keys:

EXPO_PUBLIC_SUPABASE_URL
EXPO_PUBLIC_SUPABASE_ANON_KEY

Destroy must remove only Infra-managed keys that the ledger/managed-key contract proves it owns.

It must preserve all unrelated user content in .env.local.

The same explicit ownership principle applies to generated infra/minikube/.env or any other user-editable environment/configuration file:

  • do not delete an entire user-editable file merely because Infra writes some keys into it;
  • track which entries are generated/managed runtime values;
  • remove only those managed entries that should not survive destructive teardown;
  • preserve user-authored configuration.

Do not expose or copy privileged service-role/runtime secrets into app .env.local.

Final verification and failure behavior

After cleanup, perform an independent discovery pass.

destroy succeeds only when zero app-owned resources remain across all managed resource types.

If some cleanup step fails:

  • continue best-effort cleanup of independent resources;
  • aggregate failures;
  • print the exact residual inventory;
  • exit non-zero;
  • retain enough ledger/transaction state for a safe retry.

Do not report success merely because minikube delete returned zero if app-owned host resources still remain.

destroy A must leave app B fully functional.


doctor

Add a read-only diagnostic operation for an app profile and, where appropriate, shared Ankhorage host assets.

It must detect at least:

Canonical identity/profile state

  • generated app slug and Minikube profile mismatch;
  • unexpected shared/default minikube profile assumptions;
  • expected app profile missing;
  • stale app profile for a project that no longer exists;
  • duplicate/conflicting ownership ledger for one canonical slug.

Kubernetes/provider state

  • expected generated namespaces missing;
  • unexpected/stale generated provider namespaces;
  • desired/actual Kubernetes resource drift where inventory is tracked;
  • runtime resources present but absent from the ledger;
  • ledger resources that no longer exist;
  • Supabase/provider readiness failures.

Forward/process state

  • multiple forward processes for the same named target;
  • stale PID files;
  • PID reuse/non-owned PID records;
  • expected forward missing while ledger claims up;
  • occupied forward port owned by an unrelated process.

App/public environment state

  • missing or inconsistent EXPO_PUBLIC_SUPABASE_URL;
  • missing or inconsistent EXPO_PUBLIC_SUPABASE_ANON_KEY;
  • .env.local managed values inconsistent with canonical generated Infra values;
  • Infra-managed keys recorded in the ledger but absent from the file;
  • privileged Supabase runtime secrets incorrectly present in app .env.local.

Host application images

  • expected generated app image missing;
  • multiple/superseded owned image IDs;
  • dangling owned image IDs after tag movement;
  • host/profile app image mismatch where the profile still exists;
  • image ownership labels inconsistent with ledger identity.

Minikube/KIC base image state

Each app has its own profile, but Minikube KIC base images may be shared host assets.

Doctor must detect:

  • running profile driver container image identity differing from recorded immutable identity;
  • mutable KIC tag pointing to a different image ID than the one used by an existing profile;
  • ledger/profile base-image digest drift;
  • unreferenced superseded KIC images;
  • ambiguous KIC image ownership/reference state.

Build cache/state

  • stale lifecycle locks;
  • incomplete transaction journals;
  • stale generated temporary state;
  • Ankhorage-owned build-cache accumulation where safely observable;
  • ledger entries for resources that no longer exist;
  • owned resources that exist but are absent from any ledger.

Output must clearly separate:

  • healthy;
  • repairable automatically;
  • destructive repair requiring explicit confirmation;
  • unowned/ambiguous resources Infra will not touch.

doctor must not mutate the system.


gc

Add safe garbage collection with dry-run by default.

GC must operate from authoritative ownership metadata, current project/profile ledgers and independent discovery.

Candidates may include:

  • orphaned Ankhorage-owned Minikube profiles whose owning project no longer exists;
  • orphaned generated app images on the host;
  • superseded/dangling app image IDs with proven ownership and no active references;
  • stale Ankhorage PID/lock/transaction files;
  • stale managed environment entries whose owning app/profile no longer exists, when file ownership can be proven safely;
  • unreferenced Supabase/provider dependency image versions;
  • unreferenced KIC image IDs/digests not used by any existing profile;
  • Ankhorage-owned build cache when Infra has an isolated cache namespace.

Required safety rules:

  • dry-run is the default;
  • applying deletion requires explicit confirmation or an explicit non-interactive flag;
  • every candidate displays its reason, owner, references and planned action;
  • no unrelated Docker/Minikube/filesystem resource may be touched;
  • ambiguous resources are reported, not deleted;
  • shared dependency images are reference-counted across all existing app/profile ledgers;
  • a shared Supabase/provider image remains retained while any existing app profile/ledger references it, including a currently-down profile;
  • a KIC image remains retained while any existing Minikube profile references its immutable image identity;
  • GC must never use global prune commands.

GC may optionally clean an orphaned app-owned profile only when ownership is proven and destructive confirmation is explicit.


Minikube KIC base-image ownership

The old shared-cluster model is obsolete, but reproducible KIC image identity remains relevant because multiple app-owned profiles may reference shared host KIC images.

Implement deterministic KIC image handling:

  • resolve the intended KIC base image to an immutable repository digest/image identity where supported;
  • record the exact identity used by each app profile;
  • record relevant Minikube version, Kubernetes version, driver and creation parameters;
  • do not silently mutate an existing healthy profile's base-image identity during ordinary up;
  • verify the running profile driver container's actual image identity against ledger state;
  • detect mutable-tag drift and report it rather than silently switching identities;
  • reference-count KIC images across all existing app profiles before GC removes anything.

There is no separate shared Ankhorage Minikube cluster lifecycle to implement.

Each app profile is independently destroyable.

If an explicit host-level command for unused KIC cleanup is added, it belongs under safe reference-counted GC semantics, not normal app destroy unless the image is proven unreferenced by every other profile.


Build cache ownership

Global Docker/BuildKit cache is not safely attributable to one app.

Audit the current application image build path and select one canonical ownership model:

  1. create and consistently use an Ankhorage-owned buildx builder/cache scope that can be inspected and pruned safely; or
  2. use another repository-appropriate mechanism providing exact ownership and bounded cleanup.

Do not invoke global builder pruning from app lifecycle commands.

App destroy should remove app-owned image outputs.

Host-level GC may prune only cache scopes that Infra exclusively owns and only according to explicit dry-run/apply semantics.

Document the selected cache ownership model.


Provider lifecycle integration

The current provider lifecycle contract allows providers to contribute namespace, endpoints, readiness checks, migrations, reconciliation and status checks.

Extend ownership/lifecycle integration in a provider-generic way where practical.

A future self-hosted provider should be able to contribute enough metadata for:

  • ownership inventory;
  • reset semantics;
  • doctor checks;
  • destroy diagnostics;
  • GC/reference tracking where host-level resources are involved.

Do not solve this issue by adding new hard-coded branches for each future provider when the existing provider lifecycle model can carry the information.

Supabase may retain specialized handling where its topology genuinely requires it, but host Compose concepts must not return.


Status and public lifecycle contracts

Keep existing status.sh behavior compatible with the current Infra 1.x architecture, but enrich status where useful with ledger/ownership state.

Add generated/public lifecycle entry points for doctor and gc according to repository conventions.

Any destructive command must clearly display:

  • canonical app slug/profile;
  • exact resources in scope;
  • whether data will be destroyed;
  • required confirmation mechanism.

Machine-readable output may be added if consistent with current Infra CLI/public API conventions.


Testing

Add focused unit/golden tests plus real opt-in lifecycle E2E coverage.

Unit/golden coverage

Cover at minimum:

  • canonical slug == Minikube profile identity;
  • no shared/default profile fallback;
  • no host Supabase Compose lifecycle commands/resources;
  • ledger serialization/schema validation;
  • atomic ledger writes;
  • lifecycle lock acquisition/release/stale-lock behavior;
  • managed .env.local key ownership and cleanup;
  • preservation of unrelated .env.local entries;
  • privileged runtime secrets never written to app .env.local;
  • exact host-image ownership matching;
  • no fuzzy image/resource deletion;
  • doctor classification output;
  • GC dry-run by default;
  • ambiguous/unowned resources never deleted;
  • reference counting of shared images;
  • no global prune commands generated or executed.

Real Minikube lifecycle E2E

Extend/use the existing gated real E2E infrastructure.

The acceptance scenario must use two simultaneously existing Supabase-backed apps/profiles, for example A and B.

Required scenario:

  1. start A and B;
  2. verify both canonical profiles exist;
  3. verify both have app and supabase namespaces;
  4. verify Auth/signup/signin/storage/Vault behavior remains functional according to existing Infra E2E scope;
  5. verify .env.local public Supabase values exist for both app roots;
  6. verify unrelated .env.local content survives up;
  7. down B and verify persistent data survives subsequent up B;
  8. run doctor for healthy A/B and validate healthy classification;
  9. create controlled stale/owned test artifacts and verify doctor detects them;
  10. run gc dry-run and verify it proposes only controlled owned candidates;
  11. destroy A with explicit confirmation;
  12. verify profile A is gone;
  13. verify A's owned forwards/PID/runtime ledger/managed host env entries/app images are gone according to the implemented ownership model;
  14. verify unrelated .env.local content for A is preserved if the app source still exists at that point;
  15. verify B remains running and functional;
  16. verify shared dependency/KIC images still referenced by B are not removed;
  17. verify final residual discovery reports zero A-owned resources;
  18. destroy/cleanup B in finally;
  19. verify no test-owned profiles, forwards, ledgers, images or temporary workspaces remain.

The real E2E must be repeatable after an interrupted prior test run and must never destroy non-test user profiles/resources.

Add/maintain a discoverable package script for the full real E2E and document it as a pre-release acceptance gate for lifecycle changes.


Validation

Run the complete repository validation, including all scripts applicable to the current repository, at minimum:

bun install
bun test
bun run typecheck
bun run lint
bun run format:check
bun run knip
bun run build
bun run docs
bun run changeset:status
npm pack --dry-run

Then run the gated real Minikube/Supabase lifecycle E2E.

Do not report this issue complete unless the real E2E has actually run successfully.


Documentation

Update generated and handwritten Infra documentation to describe:

  • one app slug = one Minikube profile;
  • app, supabase and provider-owned namespaces;
  • exact up / down / reset / destroy semantics;
  • app-owned versus shared host assets;
  • ledger and lock locations/contracts;
  • managed .env.local key ownership;
  • host app image ownership;
  • KIC image reference tracking;
  • build-cache ownership;
  • doctor output/semantics;
  • gc dry-run/apply semantics;
  • explicit confirmation requirements;
  • no global prune requirement.

Do not document or implement host Supabase Compose runtime ownership.


Acceptance criteria

This issue is complete when all of the following are true:

  • one canonical app slug owns exactly one Minikube profile of the same name;
  • up is idempotent and lifecycle-locked;
  • failed/interrupted operations remain safely retryable;
  • down stops forwards and the exact app profile without deleting persistent data;
  • reset destructively resets generated runtime/provider state inside the existing profile only after explicit confirmation;
  • destroy deletes only the exact app profile and all other proven app-owned host/runtime resources;
  • destroy performs independent residual verification before success;
  • destroy failure aggregates residuals and preserves retryable ownership state;
  • app A destroy cannot affect app B;
  • host Supabase Compose containers/networks/volumes are not part of the architecture;
  • generated app images have deterministic, verifiable ownership and complete cleanup;
  • shared dependency/KIC images are reference-counted across profiles before deletion;
  • .env.local cleanup removes only Infra-managed public Supabase keys and preserves unrelated user content;
  • privileged runtime secrets never appear in app .env.local;
  • runtime/profile ledgers are typed and atomically written;
  • lifecycle locks handle stale/interrupted operations;
  • doctor is read-only and detects ownership/drift/stale-resource problems;
  • gc is dry-run by default and deletes only proven unreferenced Ankhorage-owned resources after explicit apply confirmation;
  • no global Docker/Minikube/build-cache prune command is used;
  • build-cache ownership is explicit and bounded;
  • real two-profile E2E proves lifecycle isolation and complete cleanup;
  • all repository validation passes;
  • documentation and changeset are complete.

Explicitly forbidden

Do not introduce:

  • a shared/default minikube profile;
  • a shared Minikube cluster for all apps;
  • host Supabase Docker Compose runtime ownership;
  • supabase start / stop / status as runtime lifecycle;
  • hybrid host-Compose/Kubernetes Supabase lifecycle;
  • global Docker prune commands;
  • minikube delete --all or --purge lifecycle shortcuts;
  • fuzzy prefix/suffix-only deletion of images or resources;
  • deletion of ambiguous/unowned resources;
  • deletion of user-authored .env.local content;
  • service-role or privileged secrets in app .env.local;
  • compatibility shims for the pre-1.0 Minikube architecture;
  • legacy shared-cluster ledgers/contracts.

The implementation should target the current Infra 1.x architecture directly.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions