carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

| Earlier finding | Disposition at d1d9e6cf | |---|---| | R1.1 — Expiry signature accepted as production-off | Fixed: no signed expiry object. | | R1.2 — Existing permanent state passes creation checks | Not fixed: route-only apps still pass; new counterexample below. | | R1.3 — Keep/TTL races expiry | Fixed: settle, lock, and recheck positive expiry. | | R1.4 — Purge misses current deadline | Declined-with-reason acceptable: §11 explicitly defers the existing box race; console purge binds to the marker timestamp. | | R1.5 — Expiry replay after keep | Fixed: no bucket expiry authority. | | R1.6 — Restore bypasses cap | Fixed: console restores reserve capacity; direct-mode exception accepted. | | R1.7 — Restrictions enforced only in CLI | Fixed for reported paths: server enforcement specified. | | R1.8 — Browser/headless restore misses renewal | Fixed: shared restore and catch-up renewal. | | R1.9 — Interrupted purge loses short deadline | Fixed: deadline survives in the row. | | R1.10 — Migration disables expiry | Declined-with-reason acceptable: direct migration’s outcome explicitly accepted. | | R2.1 — Rename brings permanent data under expiry | Fixed: shared rename operation refuses temporary apps. | | R2.2 — Early purge skips email teardown | Fixed for reported paths: provisioning refusals and purge backstop. | | R2.3 — Failed restore cancels purge deadline | Fixed: deadline retained until row restore succeeds. | | R2.4 — Missing marker mistaken for restore | Fixed for reported case: empty prefix distinguishes completed purge. | | R2.5 — Materialization omits deadline | Fixed: marker-bound deadline reconstruction specified. | | R2.6 — Instance provisioning bypasses store prohibition | Fixed: manifest and provisioning paths covered. | | R2.7 — Old console silently creates permanent app | Fixed: distinct endpoint and response verification. | | R2.8 — Expiry bypasses control-plane protection | Fixed: creation/setter restrictions and pre-trash check. | | R3.1 — Expiry condition matches kept app | Fixed: positive-expiry check under mutex. | | R3.2 — Account move brings permanent data under expiry | Fixed: shared move operation refuses temporary apps. | | R3.3 — expiring survives restore | Fixed: flag removed; settle-first recovery specified. | | R3.4 — Failed restore frees capacity | Fixed: durable restoring reservation. | | R3.5 — Temporary app becomes control plane | Fixed: setter restriction and expiry backstop. | | R3.6 — Listing command/API shape nonexistent | Fixed: new command and additive endpoint specified. | | R4.1 — Recovery bypasses empty-bucket safeguard | Not fixed completely: expiry writes can defeat the new safeguard; counterexample below. | | R4.2 — Trash UI/API promises 30 days | Fixed: shared effective deadline and display tests specified. |

  1. P1 — §3: a permanent app represented only by routes can be claimed as temporary.

carlos add supports a named, account-qualified service backed by an existing TCP upstream, without requiring shipped releases or a console claim (cli.go:198). Such an app can have empty qualified and legacy prefixes.

The proposed “whole brand-new test” permits this state. claimApp checks console ownership and bucket prefixes (server.go:3472, server.go:3517). Its apex check explicitly permits an existing route belonging to the same account/app (apex.go:92).

Create temporary report over that permanent service. When it expires, domains reconciliation deletes every matching account/app route, including the original permanent route (reconcile.go:206). This violates the brand-new-only ruling without concurrent writes.

Fix: include existing account/app routes in temporary-creation eligibility, including the app’s own apex. Refuse when the required route inventory cannot be established. Test a serving service with no console row and empty bucket prefixes.

  1. P1 — §§2, 5: expiry can manufacture the evidence that defeats the empty-bucket safeguard.

Point the console at an incorrect empty bucket with temporary app A awaiting purge and temporary app B still marked live but already expired. Startup materialization preserves A and leaves B live (materialize.go:311, materialize.go:373).

§5 then expires B. TrashApp creates its marker without requiring existing app objects (trash.go:43). On the following pass, apps/ is nonempty solely because of that new marker. The §2 tripwire now passes, and A’s absent-marker/absent-objects recovery deletes its claim through PurgeAppRow (store.go:1491). A’s real objects remain in the correct bucket without their claim or expiry state.

Fix: when the deployment-wide listing trips the empty-bucket safeguard, suspend automatic expiry writes as well as absence-based finalization. Alternatively, verify bucket identity independently of app objects. Extend the test to mixed live-expired and awaiting-purge rows across multiple passes.

Verdict: revise.