carlos / platform Public
Reviewed 56f9ecfa. All plan line references refer to that commit.
- P1 — Task 7, Step 3: manual purge omits settlement.
docs/superpowers/plans/2026-09-26-temporary-static-sites.md:3327adds onlylockApptohandlePurgeApp. If trash wrote its marker but failed its row update, manual purge deletes the objects whilePurgeAppRowsilently preserves the live row (internal/console/ownership.go:472,internal/console/store.go:1491). Subsequent settlement leaves a live row without a marker untouched (plan:1811). This violates the settle-first requirement in spec:65–73. Fix: settle under the mutex, re-read the row, and validate purge prerequisites before destructive teardown. Test manual purge immediately after a failed trash row update.
- P1 — Task 7, Step 3: destructive handlers retain protection decisions made before acquiring the lock. Plan:3312–3331 places locks after the existing control-plane checks (
internal/console/apicli.go:1209,internal/console/appsettings.go:991,internal/console/ownership.go:335). Meanwhile, Task 6 gives the control-plane setter the same mutex (plan:2859). A delete request can pass its protection check, wait while the setter marks the app protected, then acquire the lock and trash it anyway. The missing row re-read also allows a delayed trash request to recreate a marker after its row has been purged. Fix: re-check existence and control-plane protection after locking and settling. Add deterministic tests that change these preconditions while a destructive request waits.
- P2 — Task 8, Step 1: the
ErrNotTrashedtests bypass the branch they claim to exercise.TestEarlyPurgeNotTrashedBranchesremoves the marker before invoking the pass (plan:3502–3525). The settle sweep repairs or removes the row first (plan:3722), sopurgeOnereturns at plan:3816 without reaching the recovery branch at plan:3844. Deleting that branch would leave these tests passing. Fix: use a store hook to remove the marker after initial settlement but before the purge precondition reads it. Assert thatErrNotTrashedoccurs and that both recovery outcomes work.
- P2 — Task 6, Step 1: the allowed static-instance test accepts unrelated failures. At plan:2579,
TestTemporaryInstanceCreateIsStaticAtThePlatformHostdiscards the HTTP status and checks only that the error lacks the keep hint. A 400 or 500 therefore passes, despite further validation before creation (internal/console/apiinstances.go:972). Fix: require the successful status and read back the instance record, checking its account, app, platform hostname and static kind.
- P2 — Task 11, Step 3: an explicitly empty
--ttlsilently selects ordinary deployment.temporaryDeployFlagsdetects--ttlthrough its nonblank value (plan:5020–5029); its caller supplies no flag-presence information (plan:5357). Consequently,carlos deploy --ttl "" ./distfollows ordinary app resolution instead of refusing an invalid TTL or creating a temporary app. This contradicts spec:442, where--ttlimplies temporary creation. Fix: passflagWasSet(fs, "ttl"), validate every explicitly supplied value, and test empty and whitespace-only values through the CLI entry point.
Verdict: revise.