carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1| Round-1 finding | Disposition | Why |
2|---|---|---|
3| R1-1: forged fill marker | Fixed | The separate, domain-separated signature cannot be manufactured from ordinary hop authentication. |
4| R1-2: old bytes admitted under a new generation | Fixed | Admission requires an acknowledgement bound to the expected owner and generation. |
5| R1-3: indefinitely renewed stale authority | Partly fixed | Instance convergence now controls freshness, but independently reconciled alias ownership does not; see finding 1. |
6| R1-4: lost security headers | Fixed | Entries retain end-to-end security headers, with CSP/CORP coverage required in §12. |
7| R1-5: hibernation withdraws declarations | Fixed | Including the installed build preserves declarations while the instance sleeps. |
8| R1-6: renewed lifetime at the far edge | Partly fixed | Far copies inherit the home deadline, but the new initial-expiry formula subtracts response delay twice; see finding 4. |
9| R1-7: incorrect gzip representation semantics | Fixed | The spec now requires `Vary`, weakened gzip validators and respect for `no-transform`. |
10| R1-8: concurrent fills cross the disk floor | Fixed | Outstanding reservations now account for concurrent bodies, gzip copies and metadata. |
11
121. **P1 — Alias ownership can remain stale indefinitely while its asset authority keeps renewing.**
13
14 **Claim:** A failed domain-claim listing can leave a detached or reassigned alias publishing and serving the previous owner’s cached bytes beyond the one-hour bound.
15
16 **Evidence:** [Design:229](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:229) gives aliases their primary’s block, while [design:254](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:254) derives its authority time solely from the app’s record scope. Alias claims are read separately from the bucket ([changeindex.go:302](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/internal/host/changeindex.go:302)). If that listing fails, reconciliation returns before changing existing alias rows ([aliases.go:232](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/internal/domains/aliases.go:232)); the publisher continues advertising those rows ([edgesfile.go:513](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/internal/host/edgesfile.go:513)). Successful instance reads can therefore keep renewing `at` despite never confirming that the account still owns the alias.
17
18 **Smallest fix:** Bound alias authority by the oldest successfully validated and applied dependency, including its domain claim and any parent/catch-all claims. Reuse existing reconciliation reads. Add a test that detaches an alias, fails domain listings for over an hour while instance reads and publication succeed, and requires home and far caches to stop serving it.
19
202. **P2 — The declaration union authorizes fills from builds that never declared the requested prefix.**
21
22 **Claim:** Installing a successor can cause an older serving build’s response to be cached as the successor’s asset and retained after the update completes.
23
24 **Evidence:** [Design:217](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:217) includes installed and live builds’ prefixes. However, the proxy selects the current serving generation independently ([genproxy.go:255](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/internal/edge/genproxy.go:255)). Suppose installed build B declares `/bundles/`, while current build A does not and answers that path with a cacheable `200` fallback. A request during the update satisfies every admission rule, but stores A’s fallback. When B becomes current, the entry still matches because release version is deliberately absent from the key ([design:412](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:412)). The same problem occurs when a retiring build alone declares a prefix.
25
26 **Smallest fix:** Keep the union for catching requests and serving existing entries, but admit a new response only if the build that actually answered declared that prefix. The proxy already records the answering generation ([genproxy.go:298](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/internal/edge/genproxy.go:298)). Test distinct prefixes during an update, with a cacheable fallback from the non-declaring build.
27
283. **P2 — The acknowledgement protocol has no defined billing outcome for an accepted fill that produces no cache entry.**
29
30 **Claim:** The protocol couples metering acknowledgement to an entry expiry that need not exist.
31
32 **Evidence:** [Design:356](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:356) says a recognized fill is never metered at home and its acknowledgement signs “the entry’s absolute expiry.” Yet [design:382](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:382) allows the upstream response to have no cache lifetime, be `no-store`, or otherwise produce no entry. There is no specified expiry or acknowledgement representation for that result. Omitting the acknowledgement makes the far edge skip metering too, under [design:371](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:371), although the home already skipped it.
33
34 **Smallest fix:** Separate “the home handled this as a fill and transferred billing” from “this response is eligible for storage.” Define a signed acknowledgement for uncacheable responses, with no usable expiry, and require far-edge metering. Test missing `Cache-Control`, `no-store`, non-200 responses and oversized bodies through both edges.
35
364. **P2 — The new expiry calculation counts response delay twice.**
37
38 **Claim:** Slow but still-fresh responses can be immediately discarded, defeating caching on the wake path.
39
40 **Evidence:** [Design:390](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:390) specifies `request_time + lifetime − corrected_initial_age`. Corrected initial age already includes response delay; its reference point is response receipt. The deadline should therefore use `response_time`. This follows the cited age calculation in [https://www.rfc-editor.org/rfc/rfc9111.html#section-4.2.3](https://www.rfc-editor.org/rfc/rfc9111.html#section-4.2.3).
41
42 For example, request time 0, response time 20, `Age: 0`, and lifetime 30 produce a specified expiry of 10—already expired. The correct expiry is 30, leaving ten seconds of freshness.
43
44 **Smallest fix:** Specify `response_time + lifetime − corrected_initial_age`, retaining the absolute deadline for far copies. Add a delayed-origin test where the response arrives after half its lifetime but remains fresh.
45
465. **P2 — Coalesced requests have no safe completion rule when admission fails.**
47
48 **Claim:** Sharing a rejected fill’s response can distribute one requester’s cookies or representation to other waiting clients; fallback accounting can also undercount them.
49
50 **Evidence:** [Design:331](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:331) coalesces all requests by cache key. That key excludes `Accept` and `User-Agent`, although fills forward both ([design:317](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:317)). Admission rejects `Vary: Accept`, `Set-Cookie` and private responses, but [design:403](/home/paulca/amadan.net/carlos/platform-edge-asset-cache/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md:403) only says to serve the rejected response to “the requester.” It never defines what happens to the other waiters. Broadcasting that result bypasses the admission protections. Broadcasting an unacknowledged ordinary-hop response also bills one home exchange for multiple client deliveries.
51
52 **Smallest fix:** Coalesce only the production of an admitted entry. If admission fails or the home does not acknowledge, return the response solely to the initiating requester and let other waiters make independently bounded requests. Apply each waiter’s conditions and encoding preferences separately after successful admission. Test concurrent differing `Accept` headers, rejected `Set-Cookie` responses and unacknowledged fills.
53
54reject