design: edge rate limit, builder check folded in (#358)
Summary
Astra's builder check committed unedited beside the spec. Two code corrections made; door exemption across hops, slot release at response headers and fair share over the sending edge's backhaul slots settled as my calls. Two questions left for Paul in section 9.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+69
−14
docs/superpowers/specs/2026-10-24-edge-rate-limit-design.md+53 −14docs/superpowers/specs/CODEX-FINDINGS-EDGE-RATE-LIMIT-builder-check.md+16 −0
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 v1.44.0
go: downloading github.com/aws/smithy-go v1.28.1
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/superfly/ltx v0.5.1
go: downloading golang.org/x/net v0.60.0
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 github.com/oschwald/maxminddb-golang v1.13.1
go: downloading github.com/aws/aws-sdk-go-v2/service/autoscaling v1.74.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/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/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/benbjohnson/litestream v0.5.14
go: downloading golang.org/x/sys v0.48.0
go: downloading golang.org/x/crypto v0.57.0
go: downloading github.com/aws/aws-sdk-go-v2/credentials v1.19.6
go: downloading github.com/pion/logging v0.2.4
go: downloading github.com/pion/stun/v3 v3.1.5
go: downloading github.com/pion/turn/v4 v4.1.4
go: downloading github.com/aws/aws-sdk-go-v2/service/sesv2 v1.66.6
go: downloading github.com/aws/aws-sdk-go-v2/service/s3 v1.105.0
go: downloading github.com/superfly/ltx v0.5.1
go: downloading github.com/benbjohnson/litestream v0.5.14
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/ec2 v1.324.0
go: downloading github.com/aws/aws-sdk-go-v2/service/iam v1.58.2
go: downloading github.com/klauspost/compress v1.18.0
go: downloading github.com/pion/logging v0.2.4
go: downloading github.com/aws/aws-sdk-go-v2/service/sesv2 v1.66.6
go: downloading github.com/pion/turn/v4 v4.1.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/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/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/pion/dtls/v3 v3.1.4
go: downloading github.com/pion/transport/v4 v4.0.2
go: downloading github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12
go: downloading github.com/pion/dtls/v3 v3.1.4
go: downloading github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.40
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/presigned-url v1.13.40
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19
go: downloading golang.org/x/text v0.42.0
go: downloading github.com/wlynxg/anet v0.0.5
go: downloading golang.org/x/text v0.42.0
go: downloading github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.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/v4a v1.4.38
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.40
go: downloading github.com/wlynxg/anet v0.0.5
go: downloading github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.40
go: downloading github.com/pierrec/lz4/v4 v4.1.22
go: downloading github.com/pierrec/lz4/v4 v4.1.22
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/s3shared v1.19.31
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23
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/s3shared v1.19.31
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23
go: downloading github.com/prometheus/client_golang v1.17.0
go: downloading golang.org/x/sync v0.23.0
go: downloading github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading github.com/lmittmann/tint v1.1.3
go: downloading github.com/prometheus/client_golang v1.17.0
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading golang.org/x/sync v0.23.0
go: downloading github.com/lmittmann/tint v1.1.3
go: downloading github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18
go: downloading github.com/pion/randutil v0.1.0
go: downloading github.com/pion/randutil v0.1.0
go: downloading github.com/prometheus/client_model v0.5.0
go: downloading google.golang.org/protobuf v1.36.10
go: downloading github.com/prometheus/procfs v0.12.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/common v0.45.0
go: downloading github.com/beorn7/perks v1.0.1
go: downloading github.com/prometheus/common v0.45.0
go: downloading github.com/prometheus/procfs v0.12.0
go: downloading github.com/cespare/xxhash/v2 v2.3.0
go: downloading github.com/prometheus/client_model v0.5.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/dustin/go-humanize v1.0.1
go: downloading modernc.org/mathutil v1.7.1
go: downloading github.com/google/uuid v1.6.0
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 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec
go: downloading github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec
=== launchctx (4 s)
ok amadan.net/carlos/platform.git/launchctx 0.011s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
=== vet (45 s)
go: downloading github.com/benbjohnson/litestream v0.5.14
go: downloading github.com/superfly/ltx v0.5.1
go: downloading github.com/aws/aws-sdk-go-v2/service/route53 v1.64.1
go: downloading github.com/aws/aws-sdk-go-v2/service/ec2 v1.324.0
go: downloading github.com/aws/aws-sdk-go-v2/service/ssm v1.74.0
go: downloading modernc.org/sqlite v1.55.0
go: downloading github.com/aws/aws-sdk-go-v2/service/s3 v1.105.0
go: downloading github.com/aws/aws-sdk-go-v2/service/sesv2 v1.66.6
go: downloading github.com/aws/aws-sdk-go-v2/service/iam v1.58.2
go: downloading github.com/klauspost/compress v1.18.0
go: downloading github.com/pion/logging v0.2.4
go: downloading github.com/pion/turn/v4 v4.1.4
go: downloading golang.org/x/tools v0.49.0
go: downloading github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.40
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/presigned-url v1.13.40
go: downloading golang.org/x/text v0.42.0
go: downloading github.com/wlynxg/anet v0.0.5
go: downloading github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.40
go: downloading github.com/pierrec/lz4/v4 v4.1.22
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/s3shared v1.19.31
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23
go: downloading golang.org/x/sync v0.23.0
go: downloading github.com/prometheus/client_golang v1.17.0
go: downloading github.com/lmittmann/tint v1.1.3
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18
go: downloading golang.org/x/mod v0.41.0
go: downloading github.com/pion/randutil v0.1.0
go: downloading github.com/beorn7/perks v1.0.1
go: downloading github.com/prometheus/common v0.45.0
go: downloading google.golang.org/protobuf v1.36.10
go: downloading github.com/cespare/xxhash/v2 v2.3.0
go: downloading github.com/prometheus/procfs v0.12.0
go: downloading github.com/prometheus/client_model v0.5.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/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
=== gofmt (1 s)
gofmt -l .: clean
=== rest (197 s)
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 3.219s
ok github.com/carlosframework/platform/cmd/moveprobe 11.897s
ok github.com/carlosframework/platform/cmd/zddprobe 0.766s
ok github.com/carlosframework/platform/internal/activator 59.592s
ok github.com/carlosframework/platform/internal/agentsock 0.027s
ok github.com/carlosframework/platform/internal/alerting 0.005s
ok github.com/carlosframework/platform/internal/analytics 0.026s
ok github.com/carlosframework/platform/internal/appconfig 2.664s
ok github.com/carlosframework/platform/internal/apperr 0.161s
ok github.com/carlosframework/platform/internal/applog 0.268s
ok github.com/carlosframework/platform/internal/awsinv 0.004s
ok github.com/carlosframework/platform/internal/boxchoice 0.015s
ok github.com/carlosframework/platform/internal/boxid 0.920s
? github.com/carlosframework/platform/internal/boxid/boxidtest [no test files]
? github.com/carlosframework/platform/internal/boxid/internal/signtest [no test files]
ok github.com/carlosframework/platform/internal/boxvolumes 0.019s
ok github.com/carlosframework/platform/internal/caps 0.019s
ok github.com/carlosframework/platform/internal/certwarm 0.005s
ok github.com/carlosframework/platform/internal/cgroup 0.805s
ok github.com/carlosframework/platform/internal/changelog 0.570s
ok github.com/carlosframework/platform/internal/claimactivation 1.221s
ok github.com/carlosframework/platform/internal/clamd 0.056s
? github.com/carlosframework/platform/internal/cliflag [no test files]
? github.com/carlosframework/platform/internal/controlname [no test files]
? github.com/carlosframework/platform/internal/controlsock [no test files]
ok github.com/carlosframework/platform/internal/dbdoor 8.252s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.023s
ok github.com/carlosframework/platform/internal/dbquery 0.009s
ok github.com/carlosframework/platform/internal/dbreads 2.181s
? github.com/carlosframework/platform/internal/dbreads/dbreadstest [no test files]
ok github.com/carlosframework/platform/internal/dbverify 0.011s
ok github.com/carlosframework/platform/internal/dnsrec 0.003s
ok github.com/carlosframework/platform/internal/docsite 0.016s
ok github.com/carlosframework/platform/internal/domains 2.643s
ok github.com/carlosframework/platform/internal/doorkey 0.011s
ok github.com/carlosframework/platform/internal/economics 0.008s
ok github.com/carlosframework/platform/internal/edge 49.264s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.008s
ok github.com/carlosframework/platform/internal/fleetapi 0.135s
ok github.com/carlosframework/platform/internal/gate 1.655s
ok github.com/carlosframework/platform/internal/genselect 0.015s
ok github.com/carlosframework/platform/internal/geo 0.015s
ok github.com/carlosframework/platform/internal/geoip 0.029s
ok github.com/carlosframework/platform/internal/historyreadback 0.164s
ok github.com/carlosframework/platform/internal/host 145.804s
ok github.com/carlosframework/platform/internal/hostactors 6.506s
ok github.com/carlosframework/platform/internal/hostactors/awsmembership 0.005s
ok github.com/carlosframework/platform/internal/hostbox 3.076s
ok github.com/carlosframework/platform/internal/hostclaim 0.782s
ok github.com/carlosframework/platform/internal/hostenv 0.006s
ok github.com/carlosframework/platform/internal/hostevidence 0.009s
ok github.com/carlosframework/platform/internal/hostexec 5.690s
ok github.com/carlosframework/platform/internal/hostfence 0.068s
ok github.com/carlosframework/platform/internal/hostfiles 10.633s
ok github.com/carlosframework/platform/internal/hostfloor 0.023s
ok github.com/carlosframework/platform/internal/hostguard 1.082s
ok github.com/carlosframework/platform/internal/hostops 2.060s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.006s
ok github.com/carlosframework/platform/internal/hostquarantine 0.006s
ok github.com/carlosframework/platform/internal/hostrelocate 0.624s
ok github.com/carlosframework/platform/internal/hostresolve 0.230s
ok github.com/carlosframework/platform/internal/hostwrite 0.005s
ok github.com/carlosframework/platform/internal/infraview 0.006s
ok github.com/carlosframework/platform/internal/instancectl 5.271s
ok github.com/carlosframework/platform/internal/instanceexec 2.812s
ok github.com/carlosframework/platform/internal/instancefs 0.007s
ok github.com/carlosframework/platform/internal/instancekey 0.004s
ok github.com/carlosframework/platform/internal/instanceupdates 0.009s
ok github.com/carlosframework/platform/internal/layout 1.812s
ok github.com/carlosframework/platform/internal/lbhealth 0.005s
ok github.com/carlosframework/platform/internal/lease 10.079s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.581s
ok github.com/carlosframework/platform/internal/ledger 0.023s
ok github.com/carlosframework/platform/internal/mail 0.221s
ok github.com/carlosframework/platform/internal/maintenance 0.091s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.604s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.101s
ok github.com/carlosframework/platform/internal/metrics 0.007s
ok github.com/carlosframework/platform/internal/moves 29.429s
ok github.com/carlosframework/platform/internal/moves/archive 1.003s
ok github.com/carlosframework/platform/internal/objstore 0.320s
ok github.com/carlosframework/platform/internal/ops 0.179s
ok github.com/carlosframework/platform/internal/park 0.301s
ok github.com/carlosframework/platform/internal/plans 0.006s
ok github.com/carlosframework/platform/internal/privatefile 0.005s
ok github.com/carlosframework/platform/internal/provision 53.017s
ok github.com/carlosframework/platform/internal/publicrelease 0.012s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 5.881s
ok github.com/carlosframework/platform/internal/relay 7.254s
ok github.com/carlosframework/platform/internal/release 30.238s
ok github.com/carlosframework/platform/internal/rollout 4.151s
ok github.com/carlosframework/platform/internal/rolloutwords 0.004s
ok github.com/carlosframework/platform/internal/rootaws 0.011s
ok github.com/carlosframework/platform/internal/rootparticipation 0.058s
ok github.com/carlosframework/platform/internal/rootstate 0.031s
ok github.com/carlosframework/platform/internal/runs 0.517s
ok github.com/carlosframework/platform/internal/s3compat 0.008s
ok github.com/carlosframework/platform/internal/safefile 0.011s
ok github.com/carlosframework/platform/internal/schedule 2.811s
ok github.com/carlosframework/platform/internal/seeds 0.013s
ok github.com/carlosframework/platform/internal/sim/engines 3.063s
ok github.com/carlosframework/platform/internal/sim/hostlife 10.971s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 4.061s
ok github.com/carlosframework/platform/internal/status 0.091s
ok github.com/carlosframework/platform/internal/steering 0.007s
ok github.com/carlosframework/platform/internal/stopevidence 0.364s
ok github.com/carlosframework/platform/internal/svcrole 0.002s
ok github.com/carlosframework/platform/internal/telemetry 0.006s
ok github.com/carlosframework/platform/internal/termfence 0.005s
ok github.com/carlosframework/platform/internal/tunnelclient 0.007s
ok github.com/carlosframework/platform/internal/unixdial 0.003s
ok github.com/carlosframework/platform/internal/updatewords 0.004s
ok github.com/carlosframework/platform/internal/usage 0.006s
ok github.com/carlosframework/platform/internal/version 0.002s
ok github.com/carlosframework/platform/internal/vet 1.662s
=== internal_console@0 (88 s)
ok github.com/carlosframework/platform/internal/console 86.989s
=== internal_console@1 (49 s)
ok github.com/carlosframework/platform/internal/console 48.029s
=== internal_console@2 (43 s)
ok github.com/carlosframework/platform/internal/console 42.021s
=== internal_console@3 (46 s)
ok github.com/carlosframework/platform/internal/console 44.447s
=== internal_console@4 (47 s)
ok github.com/carlosframework/platform/internal/console 45.981s
=== internal_console@5 (48 s)
ok github.com/carlosframework/platform/internal/console 46.567s
=== internal_console@6 (45 s)
ok github.com/carlosframework/platform/internal/console 43.384s
=== internal_console@7 (51 s)
ok github.com/carlosframework/platform/internal/console 49.893s
=== root@0 (113 s)
ok github.com/carlosframework/platform 111.518s
=== root@1 (84 s)
ok github.com/carlosframework/platform 82.871s
=== root@2 (96 s)
ok github.com/carlosframework/platform 94.397s
=== cross ===
--- shard 0 of 5 ---
cross-compiling darwin/arm64
--- shard 1 of 5 ---
cross-compiling darwin/amd64
--- shard 2 of 5 ---
cross-compiling linux/arm64
linux/arm64 carlos binary: 50659490 bytes (ceiling 52000000)
--- shard 3 of 5 ---
cross-compiling windows/amd64
--- shard 4 of 5 ---
cross-compiling windows/arm64
=== minio-contract ===
minio contract: arm64, minio RELEASE.2025-09-07T16-13-09Z, mc RELEASE.2025-08-13T08-35-41Z
minio: downloading https://github.com/minio/minio/releases/download/RELEASE.2025-09-07T16-13-09Z/minio.linux-arm64.RELEASE.2025-09-07T16-13-09Z
minio: downloaded, digest verified
mc: downloading https://github.com/minio/mc/releases/download/RELEASE.2025-08-13T08-35-41Z/mc.linux-arm64.RELEASE.2025-08-13T08-35-41Z
mc: downloaded, digest verified
minio healthy on 127.0.0.1:20999
Added `local` successfully.
Bucket created successfully `local/contract-bucket`.
Bucket created successfully `local/denied-bucket`.
Created policy `contract-only` successfully.
Added user `scopeduser` successfully.
Attached Policies: [contract-only]
To User: scopeduser
buckets and scoped user ready
=== RUN TestDeliveredContractMinio
=== RUN TestDeliveredContractMinio/put
=== RUN TestDeliveredContractMinio/get_round-trips_the_body
=== RUN TestDeliveredContractMinio/list_shows_the_key
=== RUN TestDeliveredContractMinio/head_and_list_agree_on_the_version
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict
=== RUN TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed
=== RUN TestDeliveredContractMinio/delete_removes_it
=== RUN TestDeliveredContractMinio/cross-bucket_denial
--- PASS: TestDeliveredContractMinio (0.02s)
--- PASS: TestDeliveredContractMinio/put (0.00s)
--- PASS: TestDeliveredContractMinio/get_round-trips_the_body (0.00s)
--- PASS: TestDeliveredContractMinio/list_shows_the_key (0.00s)
--- PASS: TestDeliveredContractMinio/head_and_list_agree_on_the_version (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route (0.02s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/delete_removes_it (0.00s)
--- PASS: TestDeliveredContractMinio/cross-bucket_denial (0.00s)
PASS
ok github.com/carlosframework/platform/internal/objstore 0.030s
=== RUN TestT4StorageProbeMinio
2026/10/24 20:12:24 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18E19042FC1A3F80, HostID: 7c420053e0fbcd7f41653fdd92ffa2802c903d05303b1aa15adc2e8bb65d183f, api error SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
--- PASS: TestT4StorageProbeMinio (0.01s)
PASS
ok github.com/carlosframework/platform/internal/host 0.024s
=== RUN TestS3StoreMinioContract
=== RUN TestS3StoreMinioContract/conditional_get_and_etag_listing
=== RUN TestS3StoreMinioContract/bump_through_every_mutation_path
--- PASS: TestS3StoreMinioContract (0.04s)
--- PASS: TestS3StoreMinioContract/conditional_get_and_etag_listing (0.02s)
--- PASS: TestS3StoreMinioContract/bump_through_every_mutation_path (0.03s)
PASS
ok github.com/carlosframework/platform/internal/release 0.054s
Bucket created successfully `local/dbf-deploy`.
Bucket created successfully `local/dbf-data-ie`.
Bucket created successfully `local/dbf-data-uk`.
local/dbf-deploy versioning is enabled
Created policy `dbf-console` successfully.
Created policy `dbf-ukbox` successfully.
Added user `dbfconsole` successfully.
Added user `dbfukbox` successfully.
Attached Policies: [dbf-console]
To User: dbfconsole
Attached Policies: [dbf-ukbox]
To User: dbfukbox
amadan: job cancelled — a newer push superseded it
diff --git a/docs/superpowers/specs/2026-10-24-edge-rate-limit-design.md b/docs/superpowers/specs/2026-10-24-edge-rate-limit-design.md| index aa695675d..c09abcdb4 100644 |
| --- a/docs/superpowers/specs/2026-10-24-edge-rate-limit-design.md |
| +++ b/docs/superpowers/specs/2026-10-24-edge-rate-limit-design.md |
| @@ -100,28 +100,41 @@ otherwise** |
| `clientIP(r)` (`internal/edge/analytics.go:76-91`) is already the trusted |
| address: the last `X-Forwarded-For` element only on a signed cross-box hop |
| -(`hopVerified`), otherwise `RemoteAddr`'s host. Unverified forwarding |
| -headers are stripped (`homemap.go:1110-1115`). The key is that address, |
| -truncated to /64 for IPv6, /32 for IPv4. |
| - |
| -Edge-local door callers (`door.go:124`, whose address is the box itself) are |
| -never limited. |
| +(`hopVerified`), otherwise `RemoteAddr`'s host. Without a verified hop, |
| +`clientIP` ignores forwarding headers whether or not they were stripped |
| +(they are stripped only when a presented hop fails verification, |
| +`homemap.go:1070`, `1095`). The key is that address, truncated to /64 for |
| +IPv6, /32 for IPv4. |
| + |
| +Edge-door callers (`door.go:124`, whose address is the box itself) are never |
| +limited, **including after a forward to another box**. *My call (builder |
| +check 4):* today the door identity lives only in the local request context |
| +(`door.go:28`) and a forwarded door request arrives as an ordinary signed |
| +hop carrying the sending box's address (`edge.go:1548`). The signed hop |
| +therefore carries the door mark, so moving an instance between boxes never |
| +changes whether its internal callers are limited. |
| ### 4.2 Busy |
| The edge counts, per host, the requests it currently has outstanding to the |
| instance: forwarded and not yet answered, including requests waiting on a |
| -wake. Today only the activator counts in-flight requests, privately, and only |
| -for hibernating routes (`activator.go:518-525`, `1541`, `1704-1718`); always-on |
| -routes go straight to the proxy uncounted. So the edge needs its own per-host |
| -counter on the path to both. |
| +wake. Nothing counts that per instance today. The activator counts in-flight |
| +requests privately and only for hibernating routes (`activator.go:518-525`, |
| +`1541`, `1704-1718`), always-on routes go straight to the proxy uncounted, |
| +and the edge's backhaul counter is per destination box, not per instance |
| +(`edge.go:2795`). So the edge needs its own per-host counter on the path to |
| +both the activator and the proxy. |
| An instance is **busy** while that count is at or above its `busy_at` |
| setting. |
| -Upgraded connections (WebSocket) are judged when the handshake arrives but |
| -do not hold an in-flight slot once upgraded. Otherwise a page with a few |
| -hundred open sockets would read as permanently busy. |
| +*My call (builder check 2):* a request holds its slot until the instance |
| +sends response headers, not until the body finishes. The count measures |
| +work the instance is doing, not how fast a client downloads. A server-sent |
| +event stream or a long download therefore releases its slot once it starts, |
| +so idle streams cannot make a comfortable instance read as busy. Upgraded |
| +connections (WebSocket) follow the same rule: judged when the handshake |
| +arrives, released once the upgrade is answered. |
| ### 4.3 Fair share (only while busy) |
| @@ -214,6 +227,18 @@ So the limiter runs on the home box's edge only, keyed by the hop-carried |
| address. Its state is in memory and is lost on restart, which is acceptable: |
| both the busy count and the buckets refill within seconds anyway. |
| +**The sending edge's backhaul slots.** Before a forwarded request reaches |
| +the home box, the sending edge admits it against a cap of 64 outstanding |
| +requests per destination box, shared by every host and client |
| +(`edge.go:2761`, `2781`, `2903`). One client landing on the wrong box can |
| +fill those slots and push everyone else forwarded through it to `503`, while |
| +the instance itself is quiet. *My call (builder check 1):* the sending edge |
| +gets the same fair share over its backhaul slots. When the slots for a |
| +destination box are at or above half full, a client key already holding 8 |
| +or more of them is refused with `429` and `Retry-After: 1`. These are fixed |
| +box-level numbers, not per-instance settings, because the sending edge has |
| +no route row to read them from. |
| + |
| **Fleet tunnels are the open case.** A fleet-tunnelled request passes the hub |
| edge and then the fleet box's edge, and on the fleet side `clientIP` is the |
| tunnel peer (the hub), not the client (`FromTunnel`; |
| @@ -335,4 +360,18 @@ those stay on the instance record, as #358 asked. |
| ## 9. Open for Paul |
| -(Filled in after the builder check.) |
| +Astra's builder check (`CODEX-FINDINGS-EDGE-RATE-LIMIT-builder-check.md`) |
| +raised four questions and two corrections. The corrections and questions 1, |
| +2 and 4 are settled above as my calls. Two remain for Paul: |
| + |
| +1. **Can a plan push the backstop below the platform default?** (builder |
| + check 3.) If a Free plan's ceiling were lower than the default `rate` or |
| + `burst`, a quiet instance on that plan would refuse a busy shared |
| + address, which breaks decision 4. Recommendation: no. A catalog ceiling |
| + may never be below the platform default (the catalog loader refuses |
| + one), so a plan can only limit how far an owner raises the numbers. |
| +2. **An app-wide default that instances inherit?** Tito runs one instance |
| + per customer. With per-instance settings only, a change of policy is one |
| + call per instance. Recommendation: not in v1; the API makes the loop |
| + cheap, and the layer can be added later as app default → instance |
| + override without changing anything here. |
diff --git a/docs/superpowers/specs/CODEX-FINDINGS-EDGE-RATE-LIMIT-builder-check.md b/docs/superpowers/specs/CODEX-FINDINGS-EDGE-RATE-LIMIT-builder-check.md| new file mode 100644 |
| index 000000000..e1a161bd6 |
| --- /dev/null |
| +++ b/docs/superpowers/specs/CODEX-FINDINGS-EDGE-RATE-LIMIT-builder-check.md |
| @@ -0,0 +1,16 @@ |
| +1. **Must fair sharing protect clients competing for backhaul capacity, or is that an accepted exception?** |
| + The sending edge already limits outstanding requests to **64 per destination box**, shared across hosts and clients. Streams and WebSockets retain those slots. One client can fill them and make other clients receive `503` before reaching the proposed limiter—even while the destination instance is quiet. Covering this case requires changes to admission on the sending edge; accepting it narrows the stated guarantee. See [internal/edge/edge.go:2761](/home/paulca/.cache/tmp/claude-1001/design-edge-rate-limit-358/internal/edge/edge.go:2761), [2781](/home/paulca/.cache/tmp/claude-1001/design-edge-rate-limit-358/internal/edge/edge.go:2781) and [2903](/home/paulca/.cache/tmp/claude-1001/design-edge-rate-limit-358/internal/edge/edge.go:2903). |
| + |
| +2. **Do non-upgraded streams and slow response downloads hold fair-share slots until their bodies finish?** |
| + §4.2 exempts upgraded connections but does not settle what “answered” means for ordinary streaming responses. Enough idle server-sent-event streams could make a comfortably running instance permanently “busy” and trigger refusals for a shared address. Counting until response completion versus releasing earlier changes the pressure measurement, response instrumentation and protection against slow requests. This needs a policy decision beyond choosing where the counter sits. |
| + |
| +3. **May a plan ceiling turn the backstop into a limit on legitimate traffic while an instance is quiet?** |
| + §5.3 clamps `rate` and `burst` to plan ceilings, but the anti-goals require those values to remain above legitimate shared-address traffic. A sufficiently low ceiling violates that requirement regardless of the benchmarked defaults. The answer determines whether catalog validation must enforce minimum acceptable ceilings, or whether paid-plan throttling is an explicit exception to the flood-only backstop. |
| + |
| +4. **Does the door-call exemption survive forwarding to another box?** |
| + §4.1 says door callers are never limited. Today their authenticated door identity exists only in local request context; forwarded door requests become ordinary signed hops carrying the sending box’s address. See [internal/edge/door.go:28](/home/paulca/.cache/tmp/claude-1001/design-edge-rate-limit-358/internal/edge/door.go:28) and [internal/edge/edge.go:1548](/home/paulca/.cache/tmp/claude-1001/design-edge-rate-limit-358/internal/edge/edge.go:1548). Preserving the exemption requires authenticated propagation of that distinction. Otherwise, moving an instance between boxes changes whether its internal callers are limited. |
| + |
| +Two factual corrections about the code at `5dacdb88`: |
| + |
| +- **§4.2: “only the activator counts in-flight requests” is incorrect.** The edge already counts backhauled requests per destination box in [internal/edge/edge.go:2795](/home/paulca/.cache/tmp/claude-1001/design-edge-rate-limit-358/internal/edge/edge.go:2795). A new per-instance counter is still needed. |
| +- **§4.1: unverified forwarding headers are not universally stripped.** With no hop marker, `acceptHop` returns without stripping them; stripping occurs when a presented hop fails verification. See [internal/edge/homemap.go:1070](/home/paulca/.cache/tmp/claude-1001/design-edge-rate-limit-358/internal/edge/homemap.go:1070) and [1095](/home/paulca/.cache/tmp/claude-1001/design-edge-rate-limit-358/internal/edge/homemap.go:1095). The client-key conclusion remains correct: `clientIP` ignores those headers without a verified hop. |
| \ No newline at end of file |