spec: edge asset cache rev 3 (carlos deploy declares too)
Summary
carlos deploy takes --assets/--no-assets, the .carlos/config project default gains an assets list, and the console ship door checks the grammar itself.
1 file changed,
+36
−5
docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md+36 −5
CI cancelled — superseded by a newer push — run details
CI log
=== gate === .amadan/test-gate.sh go: downloading github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.68.0 go: downloading github.com/aws/aws-sdk-go-v2/service/costexplorer v1.67.5 go: downloading github.com/aws/aws-sdk-go-v2/service/s3 v1.105.0 go: downloading github.com/aws/smithy-go v1.28.1 go: downloading github.com/aws/aws-sdk-go-v2 v1.44.0 go: downloading golang.org/x/net v0.56.0 go: downloading github.com/superfly/ltx v0.5.1 go: downloading modernc.org/sqlite v1.55.0 go: downloading github.com/aws/aws-sdk-go-v2/config v1.32.6 go: downloading github.com/aws/aws-sdk-go-v2/service/sns v1.43.0 go: downloading golang.org/x/crypto v0.53.0 go: downloading github.com/aws/aws-sdk-go-v2/service/route53 v1.64.1 go: downloading github.com/aws/aws-sdk-go-v2/service/acm v1.45.0 go: downloading github.com/aws/aws-sdk-go-v2/service/ec2 v1.324.0 go: downloading github.com/aws/aws-sdk-go-v2/service/iam v1.58.2 go: downloading github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.37.0 go: downloading github.com/aws/aws-sdk-go-v2/service/sts v1.45.6 go: downloading github.com/aws/aws-sdk-go-v2/service/autoscaling v1.74.0 go: downloading github.com/benbjohnson/litestream v0.5.14 go: downloading github.com/oschwald/maxminddb-golang v1.13.1 go: downloading github.com/aws/aws-sdk-go-v2/credentials v1.19.6 go: downloading golang.org/x/sys v0.46.0 go: downloading github.com/pion/logging v0.2.4 go: downloading github.com/pion/turn/v4 v4.1.4 go: downloading github.com/pion/stun/v3 v3.0.1 go: downloading github.com/aws/aws-sdk-go-v2/service/sesv2 v1.66.6 go: downloading github.com/pierrec/lz4/v4 v4.1.22 go: downloading github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.38 go: downloading github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19 go: downloading github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.40 go: downloading github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.40 go: downloading github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.40 go: downloading golang.org/x/text v0.38.0 go: downloading github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14 go: downloading github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23 go: downloading github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31 go: downloading github.com/prometheus/client_golang v1.17.0 go: downloading github.com/aws/aws-sdk-go-v2/service/ec2 v1.324.0 go: downloading modernc.org/sqlite v1.55.0 go: downloading github.com/aws/aws-sdk-go-v2/service/ssm v1.74.0 go: downloading github.com/aws/aws-sdk-go-v2/service/sesv2 v1.66.6 go: downloading golang.org/x/sync v0.21.0 go: downloading github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18 go: downloading github.com/lmittmann/tint v1.1.3 go: downloading github.com/mattn/go-isatty v0.0.20 go: downloading github.com/pierrec/lz4/v4 v4.1.22 go: downloading github.com/prometheus/client_golang v1.17.0 go: downloading github.com/pion/turn/v4 v4.1.4 go: downloading github.com/klauspost/compress v1.18.0 go: downloading golang.org/x/sync v0.21.0 go: downloading github.com/pion/transport/v3 v3.0.8 go: downloading github.com/pion/dtls/v3 v3.0.7 go: downloading github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18 go: downloading golang.org/x/text v0.38.0 go: downloading github.com/pion/randutil v0.1.0 go: downloading github.com/pion/transport/v4 v4.0.1 go: downloading github.com/pion/randutil v0.1.0 go: downloading github.com/pion/transport/v4 v4.0.1 go: downloading github.com/pion/dtls/v3 v3.0.7 go: downloading github.com/wlynxg/anet v0.0.5 go: downloading github.com/wlynxg/anet v0.0.5 go: downloading github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 go: downloading github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 go: downloading github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 go: downloading github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 go: downloading github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 go: downloading github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 go: downloading github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 go: downloading github.com/aws/aws-sdk-go-v2/service/sso v1.30.8 go: downloading github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 go: downloading github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 go: downloading github.com/beorn7/perks v1.0.1 go: downloading github.com/cespare/xxhash/v2 v2.3.0 go: downloading github.com/prometheus/common v0.45.0 go: downloading github.com/prometheus/procfs v0.12.0 go: downloading google.golang.org/protobuf v1.36.10 go: downloading github.com/prometheus/client_model v0.5.0 go: downloading github.com/prometheus/client_model v0.5.0 go: downloading github.com/beorn7/perks v1.0.1 go: downloading github.com/cespare/xxhash/v2 v2.3.0 go: downloading github.com/prometheus/procfs v0.12.0 go: downloading github.com/prometheus/common v0.45.0 go: downloading google.golang.org/protobuf v1.36.10 go: downloading github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 go: downloading github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 go: downloading modernc.org/libc v1.74.1 go: downloading modernc.org/libc v1.74.1 go: downloading modernc.org/memory v1.11.0 go: downloading github.com/google/uuid v1.6.0 go: downloading github.com/dustin/go-humanize v1.0.1 go: downloading modernc.org/mathutil v1.7.1 go: downloading modernc.org/memory v1.11.0 go: downloading github.com/google/uuid v1.6.0 go: downloading modernc.org/mathutil v1.7.1 go: downloading github.com/dustin/go-humanize v1.0.1 go: downloading github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec go: downloading github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec amadan: job cancelled — a newer push superseded it
diff --git a/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md b/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md| index aa5a40a21..07dd0347b 100644 |
| --- a/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md |
| +++ b/docs/superpowers/specs/2026-10-24-edge-asset-cache-design.md |
| @@ -1,6 +1,6 @@ |
| # Edge asset cache: versioned build assets served from every edge |
| -Branch `edge-asset-cache`. Status: rev 2, 2026-10-24, builder check folded in; rulings R1 and R2 (§13). Awaiting Paul's approval, then Astra review. |
| +Branch `edge-asset-cache`. Status: rev 3, 2026-10-24, builder check folded in; rulings R1 to R3 (§13). Awaiting Paul's approval, then Astra review. |
| Related: media roadmap (`2026-09-07-media-platform-roadmap-design.md`), |
| which this does not amend; #368 (the shared cache stores 206 responses). |
| @@ -76,7 +76,8 @@ untouched and still next in that line; §11 notes what it can reuse from here. |
| **Goals** |
| -- G1. An app declares path prefixes as build assets once, at ship time. |
| +- G1. An app declares path prefixes as build assets once, at ship or |
| + deploy time, and a saved project default keeps declaring them. |
| - G2. Any edge that receives a request under a declared prefix serves it |
| from its own disk after the first fill, with no backhaul and no request |
| to the app. |
| @@ -132,6 +133,27 @@ Old binaries ignore the key (`encoding/json` drops unknown top-level keys |
| on the manifest read path, `release.go:95-100`). `kind:static` releases |
| refuse the flag; they are already everywhere. |
| +**`carlos deploy` declares the same way** (Paul, 2026-10-24). Deploy is |
| +ship, promote and watch in one verb, and its ship half is `runShipAPI` |
| +(`deploy.go:1-6`, `:334`), which already carries `--capabilities`. So: |
| + |
| +- `carlos deploy --assets /assets/` takes the same repeatable flag with |
| + the same grammar and passes it to the ship half. |
| +- The project-defaults block in `.carlos/config` (`config.go:58-65`: |
| + `app`, `kind`, `artifact`, `target`) gains `"assets": ["/assets/"]`, so |
| + a zero-arg `carlos deploy` keeps declaring on every release. A flag on |
| + the command line replaces the saved list for that run; `--no-assets` |
| + ships with none. Without either, a release declares nothing, and since |
| + paths come from the serving release (§4.1), deploying a build without |
| + them turns catching off for it. That is why the saved default matters. |
| +- The console's ship door (API mode) puts the block in the manifest it |
| + writes and checks the same grammar itself. It does not trust the CLI. |
| +- Deploy's watch probes the app's own URL for `X-Carlos-Version`. `/` can |
| + never be declared, so the watch never lands on a caught path and a hit |
| + can never answer it with a stale version (§5.5). |
| +- `--kind static` refuses `--assets` and ignores a saved list, saying so |
| + once. |
| + |
| Why the release manifest and not the instance record: the paths an app |
| builds assets under change with its build tooling, and a rollback to a |
| build that used `/static/` must catch `/static/`, not the newer build's |
| @@ -455,8 +477,10 @@ any touched package; a test runs the full fill/hit/purge path against |
| check, flagship boxes, flagship console. Arm one dev box far from a test |
| app's home, prove the gate (§12), arm the rest of dev, then flagship one |
| box at a time, a small box (US or AU) first to watch disk. |
| -- **CLI.** `carlos ship --assets`, `carlos assets purge`, `carlos assets |
| - status`, `carlos instances update --assets` get `docs/site/cli.md` |
| +- **CLI.** `carlos ship --assets`, `carlos deploy --assets` and |
| + `--no-assets`, the `assets` project default, `carlos assets purge`, |
| + `carlos assets status`, `carlos instances update --assets` get |
| + `docs/site/cli.md` |
| headings (docsite gate). Every user-facing string goes through copy |
| review before it is written. |
| - **Census.** Touching `internal/provision` and `internal/host` likely |
| @@ -505,7 +529,10 @@ routes. Attacks first: |
| - one app requesting unbounded unique query strings evicts its own entries |
| before another app's, and no fill starts under 15% free disk; |
| - a hibernating route's caught hit does not wake it; |
| -- `/` and the other bad prefixes are refused at ship. |
| +- `/` and the other bad prefixes are refused at ship, at deploy and by |
| + the console's ship door with a CLI that skipped the check; |
| +- a zero-arg `carlos deploy` with a saved `assets` default declares it; |
| + `--assets` replaces it for the run; `--no-assets` declares none. |
| Then, on dev: an asset requested through the far region's edge is a |
| `miss` once and a `hit` after, the home box's access log shows one request |
| @@ -518,6 +545,7 @@ On flagship, the same from a small box with the disk figures recorded. |
| instance can switch catching off and cannot declare paths (§3.2). |
| - **R2. Asset bytes count the same.** Every hit and fill is the app's |
| request and bytes out, against plan caps like any other response (§8). |
| +- **R3. It works with `carlos deploy`** as well as `carlos ship` (§3.1). |
| ## 14. Review log |
| @@ -531,3 +559,6 @@ On flagship, the same from a small box with the disk figures recorded. |
| stamp and record-view bound; B9 import gate excluded. Purge status no |
| longer claims a far-edge acknowledgement it has no channel for. |
| Rulings R1 and R2 recorded. |
| +- rev 3, 2026-10-24: `carlos deploy` declares too (Paul): `--assets`, |
| + `--no-assets`, the `.carlos/config` default, and the console ship door's |
| + own check (§3.1). |