Temporary static sites: self-expiring tmp- apps, trashed at expiry, purged 3 days later
Adds a "temporary" static app for LLM scratchpads and one-shot customer pages: `carlos deploy --temporary [--ttl 3d] ./dir` creates an app named tmp-<label> that moves to the Trash when its TTL runs out (default 7d, 1h..30d) and is purged 3 days after that instead of 30. `carlos apps ttl|keep|list` move the expiry, make an app permanent, and show every app with its expiry or purge date. Spec: docs/superpowers/specs/2026-09-25-temporary-static-sites-design.md (rev 9; rulings 1-8 are Paul's). How it holds together: - All lifecycle state lives in four new console `apps` columns (expires_at, restoring, purge_after, purge_for). Nothing new is written to the bucket and box code is unchanged, so bucket write access cannot make an app temporary and an old box keeps its 30-day behaviour. - Every transition (expire, trash, restore, keep, ttl, purge) runs under a per-app mutex (account lock first where both are taken), settles the row against the trash marker, and re-checks before acting. - A 5-minute console pass expires due apps through the ordinary trash path and early-purges through release.PurgeAppIfTrashedAt, which acts only if the marker's clock matches the row's purge_for. The empty-bucket tripwire (now ignoring trash markers) holds every absence-based action. - The tmp- namespace is reserved at every door that can create a name (claims, rename, grants, backfill, carlos add), so an expiry can only drop routes a temporary app created. Temporary apps stay static and platform-hosted: domains (incl. the instance catch-all), binaries, stores, private storage, email, relay, sidecars, fleet placement, production and control plane are refused until `carlos apps keep`. - Creation is off until CARLOS_TEMPORARY_APPS=1, and temporary creates have their own 50/day budget. Cap: 20 live temporary apps per account. - Every displayed purge date (Trash page, trash API, CLI, delete confirmation) comes from one effectivePurgeAt. Reviewed: spec through 9 Astra rounds, plan through 7, each of 12 tasks by a separate reviewer (4 needed one fix round), a Fable whole-branch review, and an Opus review of the origin/main merge resolution. All user- facing copy (105 strings) approved by Paul in copy review. Gate: build, vet, gofmt, go test ./..., darwin and windows builds. Rollout (needs approval, not done here): roll every box first, scan box registries and the console's apps/owners tables for tmp- names, then set CARLOS_TEMPORARY_APPS=1 on the console.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
apimode.go+160 −0apps.go+83 −28apps_test.go+74 −19cli.go+15 −0cli_test.go+36 −0cmd/console/main.go+7 −0deploy.go+32 −2docs/site/cli.md+29 −4docs/superpowers/plans/2026-09-26-temporary-static-sites-copy.md+113 −0docs/superpowers/plans/2026-09-26-temporary-static-sites.md+6342 −0docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R1.md+23 −0docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R2.md+23 −0docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R3.md+42 −0docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R4.md+41 −0docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R5.md+42 −0docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R6.md+43 −0docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R7.md+39 −0docs/superpowers/plans/CODEX-REVIEW-BRIEF-TEMPORARY-SITES-PLAN.md+45 −0docs/superpowers/specs/2026-09-25-temporary-static-sites-design.md+619 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R1.md+21 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R2.md+38 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R3.md+40 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R4.md+42 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R5.md+48 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R6.md+24 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R7.md+40 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R8.md+30 −0docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R9.md+18 −0docs/superpowers/specs/CODEX-REVIEW-BRIEF-TEMPORARY-SITES.md+60 −0internal/console/apicli.go+119 −51internal/console/apidomains.go+3 −0internal/console/apiinstances.go+12 −0internal/console/apimail.go+12 −0internal/console/apipipeline.go+8 −0internal/console/apirelay.go+3 −0internal/console/apisidecars.go+6 −0internal/console/apistore.go+6 −0internal/console/apistore_provision.go+3 −0internal/console/apitemporary.go+431 −0internal/console/apitemporary_test.go+462 −0internal/console/applocks.go+59 −0internal/console/appsettings.go+48 −3internal/console/authcli.go+25 −0internal/console/controlplane.go+14 −0internal/console/deletion_test.go+53 −0internal/console/domainattach.go+3 −0internal/console/domaincatchall.go+12 −0internal/console/expirypass.go+253 −0internal/console/expirypass_test.go+339 −0internal/console/fleets.go+8 −0internal/console/instanceprivatestore.go+3 −0internal/console/materialize.go+22 −6internal/console/ownership.go+44 −5internal/console/restore.go+192 −0internal/console/restore_test.go+445 −0internal/console/server.go+78 −11internal/console/settle.go+127 −0internal/console/settle_test.go+245 −0internal/console/store.go+151 −39internal/console/svcprincipal.go+7 −0internal/console/temphook_test.go+66 −0internal/console/templates/app_settings.html+3 −2internal/console/templates/appnav.html+7 −0internal/console/templates/apps.html+2 −2internal/console/templates/trash.html+11 −8internal/console/tempnames_test.go+95 −0internal/console/temprefusal.go+51 −0internal/console/temprefusal_test.go+343 −0internal/console/tempregion_test.go+68 −0internal/console/tempstore.go+219 −0internal/console/tempstore_test.go+233 −0internal/console/view.go+4 −1internal/release/temporary.go+51 −0internal/release/temporary_test.go+86 −0internal/release/trash.go+21 −2temporary.go+306 −0temporary_test.go+350 −0
CI passed — run details
apimode.goLoading diff…
apps.goLoading diff…
apps_test.goLoading diff…
cli.goLoading diff…
cli_test.goLoading diff…
cmd/console/main.goLoading diff…
deploy.goLoading diff…
docs/site/cli.mdLoading diff…
docs/superpowers/plans/2026-09-26-temporary-static-sites-copy.mdLoading diff…
docs/superpowers/plans/2026-09-26-temporary-static-sites.mdLoading diff…
docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R1.mdLoading diff…
docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R2.mdLoading diff…
docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R3.mdLoading diff…
docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R4.mdLoading diff…
docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R5.mdLoading diff…
docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R6.mdLoading diff…
docs/superpowers/plans/CODEX-FINDINGS-TEMPORARY-SITES-PLAN-R7.mdLoading diff…
docs/superpowers/plans/CODEX-REVIEW-BRIEF-TEMPORARY-SITES-PLAN.mdLoading diff…
docs/superpowers/specs/2026-09-25-temporary-static-sites-design.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R1.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R2.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R3.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R4.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R5.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R6.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R7.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R8.mdLoading diff…
docs/superpowers/specs/CODEX-FINDINGS-TEMPORARY-SITES-R9.mdLoading diff…
docs/superpowers/specs/CODEX-REVIEW-BRIEF-TEMPORARY-SITES.mdLoading diff…
internal/console/apicli.goLoading diff…
internal/console/apidomains.goLoading diff…
internal/console/apiinstances.goLoading diff…
internal/console/apimail.goLoading diff…
internal/console/apipipeline.goLoading diff…
internal/console/apirelay.goLoading diff…
internal/console/apisidecars.goLoading diff…
internal/console/apistore.goLoading diff…
internal/console/apistore_provision.goLoading diff…
internal/console/apitemporary.goLoading diff…
internal/console/apitemporary_test.goLoading diff…
internal/console/applocks.goLoading diff…
internal/console/appsettings.goLoading diff…
internal/console/authcli.goLoading diff…
internal/console/controlplane.goLoading diff…
internal/console/deletion_test.goLoading diff…
internal/console/domainattach.goLoading diff…
internal/console/domaincatchall.goLoading diff…
internal/console/expirypass.goLoading diff…
internal/console/expirypass_test.goLoading diff…
internal/console/fleets.goLoading diff…
internal/console/instanceprivatestore.goLoading diff…
internal/console/materialize.goLoading diff…
internal/console/ownership.goLoading diff…
internal/console/restore.goLoading diff…
internal/console/restore_test.goLoading diff…
internal/console/server.goLoading diff…
internal/console/settle.goLoading diff…
internal/console/settle_test.goLoading diff…
internal/console/store.goLoading diff…
internal/console/svcprincipal.goLoading diff…
internal/console/temphook_test.goLoading diff…
internal/console/templates/app_settings.htmlLoading diff…
internal/console/templates/appnav.htmlLoading diff…
internal/console/templates/apps.htmlLoading diff…
internal/console/templates/trash.htmlLoading diff…
internal/console/tempnames_test.goLoading diff…
internal/console/temprefusal.goLoading diff…
internal/console/temprefusal_test.goLoading diff…
internal/console/tempregion_test.goLoading diff…
internal/console/tempstore.goLoading diff…
internal/console/tempstore_test.goLoading diff…
internal/console/view.goLoading diff…
internal/release/temporary.goLoading diff…
internal/release/temporary_test.goLoading diff…
internal/release/trash.goLoading diff…
temporary.goLoading diff…
temporary_test.goLoading diff…