carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1| Earlier finding | Disposition at `9a11decc` |
2|---|---|
3| R1.1 — Signature accepted as production-off | **Fixed:** no signed expiry object remains. |
4| R1.2 — Existing data passes creation checks | **Fixed at creation:** fresh row and empty-prefix checks. A separate account-move bypass remains below. |
5| R1.3 — Keep/TTL races expiry | **Not fixed:** the specified conditional update still matches after keep; finding 1. |
6| R1.4 — Purge misses the current deadline | **Declined-with-reason acceptable:** §11 explicitly defers the pre-existing box race. The unchanged [reconcile.go:228](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/domains/reconcile.go:228) remains vulnerable. |
7| R1.5 — Expiry replay after keep | **Fixed:** no bucket expiry authority remains. |
8| R1.6 — Restore bypasses cap | **Not fixed for failed console restores:** finding 4. The direct-mode exception is acceptable. |
9| R1.7 — Restrictions enforced only in CLI | **Fixed for the reported paths:** §4 requires server enforcement. |
10| R1.8 — Browser/headless restore misses renewal | **Fixed in the specified shared restore and catch-up behavior.** |
11| R1.9 — Interrupted purge loses short deadline | **Fixed:** the deadline survives in the row. |
12| R1.10 — Migration disables expiry | **Declined-with-reason acceptable:** §4 accurately describes direct migration and accepts its outcome. |
13| R2.1 — Rename brings permanent data under expiry | **Fixed:** temporary-app rename is refused. |
14| R2.2 — Early purge skips email teardown | **Fixed for the reported paths:** provisioning is refused and early purge checks for email resources. |
15| R2.3 — Failed restore cancels purge deadline | **Fixed:** the deadline remains until the row restore succeeds. |
16| R2.4 — Missing marker mistaken for restore | **Fixed for the reported completed-purge case:** an empty prefix finalizes deletion. |
17| R2.5 — Materialization omits deadline | **Fixed:** §5 explicitly reconstructs the marker-bound deadline. |
18| R2.6 — Instance provisioning bypasses store prohibition | **Fixed:** both manifest enablement and implicit provisioning are covered. |
19| R2.7 — Old console silently creates permanent app | **Fixed in §3:** distinct endpoint and response verification. §7 still contains the obsolete `/new` instruction and should agree with §3. |
20| R2.8 — Expiry bypasses control-plane protection | **Not fixed:** post-creation flag setting remains available, and the backstop covers purge only; finding 5. |
21
221. **P1 — §5: the expiry update accepts a kept, permanent app.**
23 The pass selects an expired candidate, then keep acquires the mutex and sets `expires_at = 0`. When the pass subsequently acquires it, the specified `UPDATE … WHERE expires_at <= now AND deleted_at = 0 AND expiring = 0` still matches: zero satisfies `<= now`. Step 2 then calls `TrashApp`, which writes the marker without checking lifecycle state ([trash.go:43](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/release/trash.go:43)), and step 3 assigns the three-day deadline. The mutex prevents simultaneous transitions but does not invalidate an earlier candidate listing. An in-memory SQLite check confirms the specified update affects one row after keep. **Fix:** require `expires_at > 0` in the conditional update and revalidate eligibility under the mutex. Test keep between candidate selection and lock acquisition.
24
252. **P1 — §§3–4: moving the console record can put a permanent site under expiry.**
26 Create temporary `A/site` without deploying it. Suppose account B already has permanent `site` releases and a non-platform route, but no console app row. That is an eligible account-repair target: the review groups accessible same-named routes whose account has no app row ([accountreview.go:65](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/accountreview.go:65)). The browser move calls `MoveApp` ([appsettings.go:1350](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/appsettings.go:1350)), whose update changes only `account_id`, preserving the proposed expiry fields ([store.go:1705](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/store.go:1705)). B’s existing permanent releases now fall under automatic expiry and three-day purge. This is separate from the accepted bucket-copy migration outcome. **Fix:** require keep before moving a temporary row, enforce it in the shared move operation, and serialize the check with lifecycle transitions.
27
283. **P2 — §§5–6: recovered expiry leaves `expiring = 1` across restore.**
29 Crash after writing the expiry tombstone but before completing step 3. Startup materialization can mark the row trashed ([materialize.go:367](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/materialize.go:367)); the proposed extension sets the purge fields but never clears `expiring`. Restore likewise clears only `deleted_at`, `purge_after` and `purge_for`. The existing row helper provides no additional transition handling ([store.go:1469](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/store.go:1469)). The restored app therefore retains an outstanding instruction to retry expiry from step 2, allowing it to be trashed again despite its renewed deadline; keep and TTL also remain refused. **Fix:** settle `expiring` when materialization completes the trash transition, clear it atomically during restore, and ensure retry eligibility cannot survive a completed restore.
30
314. **P2 — §§3, 5–6: failed console restore frees a capacity slot before recovery.**
32 With 19 live temporary apps, restore a twentieth. Tombstone deletion succeeds but the final row update fails—a failure explicitly handled by the existing API ([apicli.go:1338](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/apicli.go:1338)). The restored app serves again, but its row remains excluded from the cap. Create another temporary app, bringing the counted total to 20. Later, §5’s missing-marker catch-up restores the first row **without a cap check**, producing 21 live apps. No direct-mode operation or simultaneous create is required. **Fix:** reserve capacity durably before removing the marker, count incomplete restores against the cap, and retain that reservation through recovery. Merely adding a late refusal cannot undo the already-serving restore.
33
345. **P2 — §§3–5: an existing temporary app can still become the control plane.**
35 Removing `control_plane` from the create request does not close the existing owner-facing setter: `handleAppControlPlaneSet` calls `SetAppControlPlane(..., true)` on an existing app ([controlplane.go:288](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/controlplane.go:288)). §4 does not restrict that path. §5 checks the flag only before early purge, so expiry still trashes an app that ordinary deletion explicitly protects ([apicli.go:1209](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/apicli.go:1209)). **Fix:** require keep before setting the control-plane flag and recheck the flag before automatic trash as well as purge, under the lifecycle mutex.
36
376. **P3 — §7: the proposed listing assumes an API shape and command that do not exist.**
38 `carlos apps` currently has no `list` subcommand ([apps.go:129](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/apps.go:129)). The existing app enumeration returns account entries containing app-name strings ([apicli.go:548](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/apicli.go:548)), and clients decode them as `[]string` ([account_choose.go:27](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/account_choose.go:27)). Its store query excludes trashed apps ([store.go:1362](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/temporary-sites/internal/console/store.go:1362)), so it cannot supply the advertised purge countdown. **Fix:** specify the new list command and an additive metadata endpoint or response field, including trash visibility and service-principal filtering; preserve the existing string-array contract.
39
40Verdict: revise.