census: re-seal after the final fix wave (#358)
The fix wave (b20d8be4..6526925f) moved four root-read units and six envelopes, and added one CLI read the record-write census did not list. Every root-read change is a body change: no new kind of read, no new or removed unit, so no new decision. - Decisions overlay: Edge.rateAdmit (D1) and UsageMeter.RecordRateLimited (D4) re-frozen on their new digests, same reads at moved offsets, same disposition and basis. Seal 86570d13 -> 3e3af3ff (was cec20594). - census-propose rerun: the nine earlier claims, Edge.ServeHTTP's now saying the upgrade path holds a slot until its handshake is answered, plus UsageMeter.Record (row.SetOwner). Seal 3e3af3ff -> f1eb4ea3. - Card: the hand-written Decisions section restored, its seal line updated. - 9B8: apiSession.instanceRateLimitSettings, a read that writes nothing, listed as a key-site like instanceGet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 files changed,
+31
−18
docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md+6 −3internal/provision/edge_rate_limit_census_test.go+7 −0internal/provision/testdata/plan14-root-reads-chain.tsv+2 −2internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358-decisions.tsv+5 −4internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv+11 −9
CI passed — run details
CI log
=== gate ===
.amadan/test-gate.sh
=== launchctx (0 s)
ok amadan.net/carlos/platform.git/launchctx 0.014s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
=== vet (14 s)
=== gofmt (0 s)
gofmt -l .: clean
=== rest (168 s)
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 3.833s
ok github.com/carlosframework/platform/cmd/moveprobe 12.046s
ok github.com/carlosframework/platform/cmd/zddprobe 0.817s
ok github.com/carlosframework/platform/internal/activator 58.403s
ok github.com/carlosframework/platform/internal/agentsock 0.031s
ok github.com/carlosframework/platform/internal/alerting 0.007s
ok github.com/carlosframework/platform/internal/analytics 0.031s
ok github.com/carlosframework/platform/internal/appconfig 3.007s
ok github.com/carlosframework/platform/internal/apperr 0.176s
ok github.com/carlosframework/platform/internal/applog 0.336s
ok github.com/carlosframework/platform/internal/assetcache 0.200s
ok github.com/carlosframework/platform/internal/awsinv 0.005s
ok github.com/carlosframework/platform/internal/boxchoice 0.015s
ok github.com/carlosframework/platform/internal/boxid 0.746s
? 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.026s
ok github.com/carlosframework/platform/internal/caps 0.035s
ok github.com/carlosframework/platform/internal/certwarm 0.008s
ok github.com/carlosframework/platform/internal/cgroup 0.841s
ok github.com/carlosframework/platform/internal/changelog 0.645s
ok github.com/carlosframework/platform/internal/claimactivation 1.415s
ok github.com/carlosframework/platform/internal/clamd 0.059s
? 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.119s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.020s
ok github.com/carlosframework/platform/internal/dbquery 0.008s
ok github.com/carlosframework/platform/internal/dbreads 2.306s
? github.com/carlosframework/platform/internal/dbreads/dbreadstest [no test files]
ok github.com/carlosframework/platform/internal/dbverify 0.010s
ok github.com/carlosframework/platform/internal/dnsrec 0.015s
ok github.com/carlosframework/platform/internal/docsite 0.010s
ok github.com/carlosframework/platform/internal/domains 3.000s
ok github.com/carlosframework/platform/internal/doorkey 0.009s
ok github.com/carlosframework/platform/internal/economics 0.004s
ok github.com/carlosframework/platform/internal/edge 45.953s
? 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.134s
ok github.com/carlosframework/platform/internal/gate 1.656s
ok github.com/carlosframework/platform/internal/genselect 0.015s
ok github.com/carlosframework/platform/internal/geo 0.016s
ok github.com/carlosframework/platform/internal/geoip 0.029s
ok github.com/carlosframework/platform/internal/historyreadback 0.154s
ok github.com/carlosframework/platform/internal/host 143.410s
ok github.com/carlosframework/platform/internal/hostactors 6.099s
ok github.com/carlosframework/platform/internal/hostactors/awsmembership 0.007s
ok github.com/carlosframework/platform/internal/hostbox 3.051s
ok github.com/carlosframework/platform/internal/hostclaim 0.731s
ok github.com/carlosframework/platform/internal/hostenv 0.006s
ok github.com/carlosframework/platform/internal/hostevidence 0.008s
ok github.com/carlosframework/platform/internal/hostexec 5.348s
ok github.com/carlosframework/platform/internal/hostfence 0.037s
ok github.com/carlosframework/platform/internal/hostfiles 10.279s
ok github.com/carlosframework/platform/internal/hostfloor 0.019s
ok github.com/carlosframework/platform/internal/hostguard 1.036s
ok github.com/carlosframework/platform/internal/hostops 1.969s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.003s
ok github.com/carlosframework/platform/internal/hostquarantine 0.006s
ok github.com/carlosframework/platform/internal/hostrelocate 0.558s
ok github.com/carlosframework/platform/internal/hostresolve 0.193s
ok github.com/carlosframework/platform/internal/hostwrite 0.006s
ok github.com/carlosframework/platform/internal/infraview 0.004s
ok github.com/carlosframework/platform/internal/instancectl 5.226s
ok github.com/carlosframework/platform/internal/instanceexec 2.805s
ok github.com/carlosframework/platform/internal/instancefs 0.013s
ok github.com/carlosframework/platform/internal/instancekey 0.003s
ok github.com/carlosframework/platform/internal/instanceupdates 0.027s
ok github.com/carlosframework/platform/internal/layout 1.721s
ok github.com/carlosframework/platform/internal/lbhealth 0.002s
ok github.com/carlosframework/platform/internal/lease 10.095s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.475s
ok github.com/carlosframework/platform/internal/ledger 0.025s
ok github.com/carlosframework/platform/internal/mail 0.234s
ok github.com/carlosframework/platform/internal/maintenance 0.096s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.521s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.087s
ok github.com/carlosframework/platform/internal/metrics 0.008s
ok github.com/carlosframework/platform/internal/moves 21.943s
ok github.com/carlosframework/platform/internal/moves/archive 0.937s
ok github.com/carlosframework/platform/internal/objstore 0.234s
ok github.com/carlosframework/platform/internal/ops 0.278s
ok github.com/carlosframework/platform/internal/park 0.270s
ok github.com/carlosframework/platform/internal/plans 0.006s
ok github.com/carlosframework/platform/internal/privatefile 0.007s
ok github.com/carlosframework/platform/internal/provision 22.228s
ok github.com/carlosframework/platform/internal/publicrelease 0.008s
ok github.com/carlosframework/platform/internal/ratelimit 0.109s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 5.732s
ok github.com/carlosframework/platform/internal/relay 7.206s
ok github.com/carlosframework/platform/internal/release 26.072s
ok github.com/carlosframework/platform/internal/rollout 3.758s
ok github.com/carlosframework/platform/internal/rolloutwords 0.006s
ok github.com/carlosframework/platform/internal/rootaws 0.008s
ok github.com/carlosframework/platform/internal/rootparticipation 0.059s
ok github.com/carlosframework/platform/internal/rootstate 0.031s
ok github.com/carlosframework/platform/internal/runs 0.582s
ok github.com/carlosframework/platform/internal/s3compat 0.007s
ok github.com/carlosframework/platform/internal/safefile 0.005s
ok github.com/carlosframework/platform/internal/schedule 2.687s
ok github.com/carlosframework/platform/internal/seeds 0.011s
ok github.com/carlosframework/platform/internal/sim/engines 2.567s
ok github.com/carlosframework/platform/internal/sim/hostlife 10.851s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 3.925s
ok github.com/carlosframework/platform/internal/status 0.067s
ok github.com/carlosframework/platform/internal/steering 0.007s
ok github.com/carlosframework/platform/internal/stopevidence 0.054s
ok github.com/carlosframework/platform/internal/svcrole 0.002s
ok github.com/carlosframework/platform/internal/telemetry 0.007s
ok github.com/carlosframework/platform/internal/termfence 0.004s
ok github.com/carlosframework/platform/internal/tunnelclient 0.005s
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.005s
ok github.com/carlosframework/platform/internal/version 0.002s
ok github.com/carlosframework/platform/internal/vet 1.655s
=== internal_console@0 (82 s)
ok github.com/carlosframework/platform/internal/console 80.854s
=== internal_console@1 (43 s)
ok github.com/carlosframework/platform/internal/console 41.907s
=== internal_console@2 (37 s)
ok github.com/carlosframework/platform/internal/console 35.862s
=== internal_console@3 (42 s)
ok github.com/carlosframework/platform/internal/console 40.811s
=== internal_console@4 (44 s)
ok github.com/carlosframework/platform/internal/console 42.164s
=== internal_console@5 (40 s)
ok github.com/carlosframework/platform/internal/console 38.129s
=== internal_console@6 (39 s)
ok github.com/carlosframework/platform/internal/console 37.885s
=== internal_console@7 (49 s)
ok github.com/carlosframework/platform/internal/console 47.472s
=== root@0 (116 s)
ok github.com/carlosframework/platform 114.508s
=== root@1 (94 s)
ok github.com/carlosframework/platform 92.774s
=== root@2 (75 s)
ok github.com/carlosframework/platform 73.440s
=== 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: 50790562 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: cached, digest verified
mc: cached, 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.01s)
--- 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.023s
=== RUN TestT4StorageProbeMinio
2026/10/25 00:13:07 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18E19D65CD448568, 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.00s)
PASS
ok github.com/carlosframework/platform/internal/host 0.021s
=== RUN TestS3StoreMinioContract
=== RUN TestS3StoreMinioContract/conditional_get_and_etag_listing
=== RUN TestS3StoreMinioContract/bump_through_every_mutation_path
--- PASS: TestS3StoreMinioContract (0.02s)
--- PASS: TestS3StoreMinioContract/conditional_get_and_etag_listing (0.01s)
--- PASS: TestS3StoreMinioContract/bump_through_every_mutation_path (0.01s)
PASS
ok github.com/carlosframework/platform/internal/release 0.030s
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
=== RUN TestDBForwardMinio
2026/10/25 00:13:09 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000000 txid.db=0000000000000001
2026/10/25 00:13:09 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000001 maxTXID=0000000000000001 size=720
2026/10/25 00:13:09 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000001
2026/10/25 00:13:09 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000002
2026/10/25 00:13:09 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000002 maxTXID=0000000000000002 size=370
2026/10/25 00:13:09 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000002 txid.db=0000000000000002
2026/10/25 00:13:09 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000002 txid.db=0000000000000003
2026/10/25 00:13:09 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000003 maxTXID=0000000000000003 size=454
2026/10/25 00:13:09 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000003 txid.db=0000000000000003
2026/10/25 00:13:09 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000000 txid.db=0000000000000001
2026/10/25 00:13:09 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000001 maxTXID=0000000000000001 size=720
2026/10/25 00:13:09 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000001
2026/10/25 00:13:09 console: CARLOS_SECRETS_PUBKEY is unset, so no region outside the home can be chosen automatically
2026/10/25 00:13:09 console: could not notify member@example.com of a CLI token issue: keymail: lookup member@example.com: keymail: GET /api/federation/lookup?addr=member%40example.com&from=console%40127.0.0.1%3A40237: could not determine target mailbox
agent.go:135: dbreads: dbr_4inhe42xfnacsfmiyvue6yqwyi: planned 3 files (1544 bytes) and restored to 3 in 10ms
agent.go:135: dbreads: dbr_4inhe42xfnacsfmiyvue6yqwyi: output 5 bytes in 1 confirmed chunks in 1ms
2026/10/25 00:13:10 console: db read dbr_4inhe42xfnacsfmiyvue6yqwyi: relayed 1 chunks (102 bytes) in 1.004s, ended done
agent.go:135: dbreads: dbr_mh74wx5tmrv6c3mokwklnnvq3i: planned 1 files (720 bytes) and restored to 1 in 7ms
agent.go:135: dbreads: dbr_mh74wx5tmrv6c3mokwklnnvq3i: output 5 bytes in 1 confirmed chunks in 1ms
2026/10/25 00:13:11 console: db read dbr_mh74wx5tmrv6c3mokwklnnvq3i: relayed 1 chunks (102 bytes) in 1.004s, ended done
agent.go:135: dbreads: dbr_y2f43z4fh4mbrrmbd6pbaymnqa: planned 3 files (1544 bytes) and held through 3 in 8ms
agent.go:135: dbreads: dbr_y2f43z4fh4mbrrmbd6pbaymnqa: output 1544 bytes in 1 confirmed chunks in 1ms
2026/10/25 00:13:12 console: db read dbr_y2f43z4fh4mbrrmbd6pbaymnqa: relayed 1 chunks (1641 bytes) in 1.003s, ended done
=== RUN TestDBForwardMinio/by_disconnect
=== NAME TestDBForwardMinio
agent.go:135: dbreads: dbr_qtcvl6rsdtm3z4avk646hx5x7a: planned 3 files (1544 bytes) and restored to 3 in 9ms
2026/10/25 00:13:12 console: db read dbr_qtcvl6rsdtm3z4avk646hx5x7a: relayed 0 chunks (0 bytes) in 26ms, ended client gone
agent.go:135: dbreads: dbr_qtcvl6rsdtm3z4avk646hx5x7a: output 5 bytes in 1 confirmed chunks in 35ms
=== RUN TestDBForwardMinio/by_timeout
=== NAME TestDBForwardMinio
agent.go:135: dbreads: dbr_2rb2lm4qlygsnq6abzhutlfn5m: planned 3 files (1544 bytes) and restored to 3 in 9ms
2026/10/25 00:13:32 console: db read dbr_2rb2lm4qlygsnq6abzhutlfn5m: relayed 0 chunks (0 bytes) in 19.195s, ended no-result
agent.go:135: dbreads: dbr_2rb2lm4qlygsnq6abzhutlfn5m: output 5 bytes in 1 confirmed chunks in 19.166s
--- PASS: TestDBForwardMinio (22.57s)
--- PASS: TestDBForwardMinio/by_disconnect (0.17s)
--- PASS: TestDBForwardMinio/by_timeout (19.30s)
PASS
ok github.com/carlosframework/platform/internal/console 22.594s
minio contract: PASS
diff --git a/docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md b/docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md| index 7833b6668..cc74e66b7 100644 |
| --- a/docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md |
| +++ b/docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md |
| @@ -6,7 +6,8 @@ Ruling `census-ruling-design-edge-rate-limit-358`. Every change below keeps the |
| |---|---|---|---| |
| | `internal/console/server.go` `NewServer` | body | unchanged (1) | one route registered beside the gate's form: POST /a/{sqid}/apps/{app}/ratelimit to handleAppRateLimit, the Settings page's rate-limit form, member-gated like the gate; no read added, its one data-literal site unchanged (offset moved) | |
| | `internal/console/templates/app_settings.html` `external` | body | unchanged (1) | the Settings page gains a Rate limit section: per instance host, a form of four numbers (busy at, per address while busy, backstop rate, backstop burst) and a reset form, both posting to /a/{sqid}/apps/{app}/ratelimit with the CSRF token, and the record's path rules listed read-only; embedded and rendered by the console (carlos-console), as before; no read added | |
| -| `internal/edge/edge.go` `Edge.ServeHTTP` | body | unchanged (21) | calls rateAdmit twice: on the upgrade path before the activator or proxy (judged, holds no slot), and on the ordinary path after the response-cache check and before the activator and proxy (an admitted request holds a slot through slotWriter, released by a defer); a refusal is a 429 written there and returns; one comment on the door mark reworded; read sites unchanged (21), offsets moved; no read added | |
| +| `internal/edge/edge.go` `Edge.ServeHTTP` | body | unchanged (21) | calls rateAdmit twice, and an admitted request holds a slot on both paths: on the upgrade path before the activator or proxy (the handshake holds its slot through slotWriter, given back at the first final answer or at the reverse proxy's hijack on a 101, so an open WebSocket is not counted; released by a defer), and on the ordinary path after the response-cache check and before the activator and proxy (an admitted request holds a slot through slotWriter, released by a defer); a refusal is a 429 written there and returns; the upgrade path's comment now names slotWriter as its one wrapper; one comment on the door mark reworded; read sites unchanged (21), offsets moved; no read added | |
| +| `internal/edge/usagemeter.go` `UsageMeter.Record` | body | unchanged (4) | the two lines that set the row's Account and App become one call, row.SetOwner(release.RouteAccount(rt), rt.App) (usage.EdgeRow.SetOwner, on the in-memory row), which sets the same two fields and, when the host's owner changes, first zeroes the row's two rate-limit refusal counters; Requests, BytesOut and the hop counters sum as before; read sites unchanged (4); no read added | |
| | `internal/host/agent.go` `runAgent` | body | unchanged (5) | arms the edge's plan rate-ceiling hook, e.SetRateCeilingFor(planRateCeilingFor), right after EnableUsage; read sites unchanged (5), offsets moved; no read added | |
| | `internal/provision/reconcile.go` `RouteFor` | body | unchanged (9) | the route literal gains RateLimit: rec.RateLimitColumn(), the record's settings as canonical JSON or "" for the defaults (a provision.Record method, not a registry read); every caller gets it, the root ones included (ClaimRootHTTP.rootLandingRoute, relocationRecord), which only carry the column and never read it; read sites unchanged (9); no read added | |
| | `internal/registry/registry.go` `Registry.Fingerprint` | body | unchanged (26) | the routes SELECT gains rate_limit, scanned into one more local and hashed as a tagged rate_limit field only when non-empty, so a registry with no custom limits digests as before and a change reaches a running edge; read sites unchanged (26); no read added | |
| @@ -16,7 +17,7 @@ Ruling `census-ruling-design-edge-rate-limit-358`. Every change below keeps the |
| Envelopes re-pinned: `.`, `internal/console`, `internal/console/templates`, `internal/edge`, `internal/host`, `internal/plans`, `internal/provision`, `internal/ratelimit`, `internal/registry`, `internal/usage`. |
| -Seal: `cec2059456e34cda6953cd9aebacdaa4f1bd758ac5164777e6fb0f78528d7bf3` → `75e9e18780807b2e262400cab5c82068536bb9adc1e96ea55dcf5d670a987487`. |
| +Seal: `3e3af3ff6b6b92bd41a02e2ac58543f15b1f50f7479e2f1cfaae464bc8781136` → `f1eb4ea3670d0a7d8bc25843cdf11c4604e2859468971356b7b9f3f2ab1ced10`. |
| Overlay: `internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv`, appended to `internal/provision/testdata/plan14-root-reads-chain.tsv`. |
| @@ -25,7 +26,9 @@ Overlay: `internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-3 |
| census-propose refuses decisions, so these rows are in a hand-written overlay, |
| `internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358-decisions.tsv`, |
| loaded through the chain manifest just before the overlay above. Its seal is |
| -`86570d13…` → `cec20594…` (eight frozen declarations added). Each row carries |
| +`86570d13…` → `3e3af3ff…` (eight frozen declarations added). After the final |
| +fix wave (b20d8be4..6526925f), D1 and D4 were re-frozen on their new digests: |
| +the same reads at moved offsets, the same disposition. Each row carries |
| `rev3=census-ruling-design-edge-rate-limit-358` and needs the owner's ruling, |
| not just an approval. If census-propose is rerun, this section has to be added |
| again by hand. |
diff --git a/internal/provision/edge_rate_limit_census_test.go b/internal/provision/edge_rate_limit_census_test.go| index cc6b22a69..bf97cd919 100644 |
| --- a/internal/provision/edge_rate_limit_census_test.go |
| +++ b/internal/provision/edge_rate_limit_census_test.go |
| @@ -39,6 +39,12 @@ package provision |
| // of .../rate-limit, and a PATCH carrying only rate_limit) and write |
| // nothing themselves; the console's PATCH door does the write. key-site, |
| // like instanceGet and instanceSetGate. |
| +// - apiSession.instanceRateLimitSettings is new (the final fix wave): a |
| +// read, not a write. It GETs the console's .../instances/<host> and |
| +// returns the record's rate_limit as stored (none is the defaults), so |
| +// `carlos ratelimit set` overlays the stored settings without the |
| +// counts-bearing .../rate-limit GET; it writes nothing. key-site, like |
| +// instanceGet. |
| func edgeRateLimitWriteCensusInventory() []censusEntry { |
| entries := append([]censusEntry(nil), wakeLatency3WriteCensusInventory()...) |
| replacements := []censusEntry{ |
| @@ -50,6 +56,7 @@ func edgeRateLimitWriteCensusInventory() []censusEntry { |
| {"main.go", "main", "key-site", "lit:instances,lit:sidecars", "6eab7deb7b99dfcb4f239733247731d5dc4ee73a02d16b1dfdf30129b227cdea"}, |
| {"apimode.go", "apiSession.instanceRateLimit", "key-site", "lit:instances", "909e1f6e4dd9e800c09f9a956f2457dac9dcfb8955584e26c453608a3d8144b8"}, |
| {"apimode.go", "apiSession.instanceSetRateLimit", "key-site", "lit:instances", "566a98be38b8b1cde03397b2d1c6edd5633b7fe21c58a14e2c5d8e16be68ab4f"}, |
| + {"apimode.go", "apiSession.instanceRateLimitSettings", "key-site", "lit:instances", "36af94a811d8aae5178b88ac365018a348a3709368aee6b52a02359a5f301421"}, |
| } |
| for _, r := range replacements { |
| found := false |
diff --git a/internal/provision/testdata/plan14-root-reads-chain.tsv b/internal/provision/testdata/plan14-root-reads-chain.tsv| index 0138d43f4..2e35abea1 100644 |
| --- a/internal/provision/testdata/plan14-root-reads-chain.tsv |
| +++ b/internal/provision/testdata/plan14-root-reads-chain.tsv |
| @@ -10,5 +10,5 @@ plan14-root-reads-edge-asset-cache-2.tsv de15b849fcb93b76caca55be924cde41512f8c4 |
| plan14-root-reads-pro-6214-service-runs-decisions.tsv ec2d8daaec385b34b3be9c8c6430427c082ac36cd40150e1c6f520e20e3da72d |
| plan14-root-reads-pro-6214-service-runs.tsv 86570d1326baad6d866b4066b6bf65218434b201fb1f2c05ebc6e3c79f9c5a98 |
| plan14-root-reads-wake-latency-3.tsv 86570d1326baad6d866b4066b6bf65218434b201fb1f2c05ebc6e3c79f9c5a98 |
| -plan14-root-reads-design-edge-rate-limit-358-decisions.tsv cec2059456e34cda6953cd9aebacdaa4f1bd758ac5164777e6fb0f78528d7bf3 |
| -plan14-root-reads-design-edge-rate-limit-358.tsv 75e9e18780807b2e262400cab5c82068536bb9adc1e96ea55dcf5d670a987487 |
| +plan14-root-reads-design-edge-rate-limit-358-decisions.tsv 3e3af3ff6b6b92bd41a02e2ac58543f15b1f50f7479e2f1cfaae464bc8781136 |
| +plan14-root-reads-design-edge-rate-limit-358.tsv f1eb4ea3670d0a7d8bc25843cdf11c4604e2859468971356b7b9f3f2ab1ced10 |
diff --git a/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358-decisions.tsv b/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358-decisions.tsv| index 19e43d6b5..bcd325ec7 100644 |
| --- a/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358-decisions.tsv |
| +++ b/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358-decisions.tsv |
| @@ -1,18 +1,19 @@ |
| # Census overlay design-edge-rate-limit-358-decisions (#358, the per-instance edge rate limit), loaded through plan14-root-reads-chain.tsv after wake-latency-3 and before the census-propose overlay design-edge-rate-limit-358, which carries this branch's approvals (body, sites, envelopes). census-ruling-design-edge-rate-limit-358, put to the census owner on #280 before the merge; the approval card is docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md. Written by hand: every row here is a decision census-propose refuses (new units, new kinds of read, the registry field list). |
| # Six new units, each accepted legacy like its nearest neighbour: three in the edge's request path and reload (rateAdmit, parseRateSettings, noteRateLimited; Edge.ServeHTTP and Edge.Reload are accepted legacy), the usage meter's refusal counter (UsageMeter.Record's twin), the plans ceiling hook (planIdleFor's twin) and the registry setter (SetGate's twin). Four units gain a new kind of read, registry:RateLimit, the new column, each re-frozen at the disposition it already has: Reconcile and scanRoute accepted legacy, routeArgs authority E3, dispatchRemote hint E2. |
| # @fields gains RateLimit (Route.RateLimit and remoteRequest.RateLimit in internal/registry). Its readers are exactly the four reads units above and parseRateSettings: the agent, its edge and the registry child, all as carlos. No root unit reads it, so rate_limit is not a root input. Eight frozen declarations are added (six new, Reconcile and scanRoute re-frozen), so the seal moves; wake-latency-3's seal is checked first. |
| +# Final fix wave (b20d8be4..6526925f): rateAdmit and RecordRateLimited re-frozen on their new digests, same reads (offsets moved), same disposition and basis. rateAdmit lost its holdSlot parameter: an upgrade now holds a slot until its handshake is answered, like any request; RecordRateLimited (like Record) now labels the row through usage.EdgeRow.SetOwner, which zeroes the two refusal counters when the host's owner changes. Neither gains a read. |
| @legacy 641f0678ee5d651a76c759b031e5219ea336d01f62c47359a8e1a9fec0997264 internal/edge/ratelimit.go Edge.noteRateLimited legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), serving only: counts one rate-limit refusal (or, observing, one that would have been) on the usage meter (UsageMeter.RecordRateLimited, passed the row) and logs it, throttled per host and reason; it reads the row's host for the log key and line; no file, record or root decision registry:Host@505,registry:Host@597,whole:Route@166 2a7c2bdb6a7e8a666660f2551a79fd9bf7e310f6952133314fc9eaa937d1230b |
| @legacy 4e49936e0e8f8e7cd9342a8bb72cfe9670955a35a3b2cabcfe3b91609f885afe internal/edge/ratelimit.go Edge.parseRateSettings legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), at Reload: parses one route's rate_limit column (the owner's settings, converged from the instance record by provision.Reconcile) into ratelimit.Settings; an unparseable or out-of-range column runs at the platform defaults and is logged, throttled per host; it reads the row's rate_limit and host only; no file, record or root decision registry:Host@271,registry:Host@367,registry:RateLimit@158,registry:RateLimit@77 4420ba9c98146057f9d06ebe1e2c883e21e61d843a3e9790be12d3449f665504 |
| -@legacy cf0bc11bbc6bbd3b1825842526e2fa8ead5c852838b24ae7900547e41a116e25 internal/edge/ratelimit.go Edge.rateAdmit legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), serving only: judges a request to an instance against the owner's settings, the plan ceiling hook (planRateCeilingFor, passed the row) and the in-memory limiter keyed on the row's host, and answers 429 when CARLOS_RATE_LIMIT=enforce; a non-instance row, a door caller, a signed door hop and a fleet-tunnel request are never judged; it reads the row's kind and host; the limiter's buckets and slots are in memory only; no file, record or root decision registry:Host@834,registry:Kind@150,whole:Route@153,whole:Route@561,whole:Route@837,whole:Route@943 0d64f6b291978a45c4025bf6bcc2f5e243ecb4d19c643f1e258ad49f17803a99 |
| -@legacy 974d16765eb4460b12448c13a43fe9152fa0fa878bd7a71a2cbeace9fdbbf3e9 internal/edge/usagemeter.go UsageMeter.RecordRateLimited legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): UsageMeter.Record's twin, adding one to the host's fair-share or backstop refusal counter in the in-memory usage row; it reads the row's host, app and account (release.RouteAccount); the counts ship with the rows Record fills; no file, record or root decision registry:App@206,registry:Host@146,registry:Host@294,whole:Route@191 d37236452f8d82c27dfca0937b8281d26d1894f180b13fff581a368022598229 |
| +@legacy 44badb776ad17d3d7f7b32bd72a020d5a0b82f86603f0eb77ea8f9f4bcbb9509 internal/edge/ratelimit.go Edge.rateAdmit legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), serving only: judges a request to an instance against the owner's settings, the plan ceiling hook (planRateCeilingFor, passed the row) and the in-memory limiter keyed on the row's host, and answers 429 when CARLOS_RATE_LIMIT=enforce; a non-instance row, a door caller, a signed door hop and a fleet-tunnel request are never judged; it reads the row's kind and host; the limiter's buckets and slots are in memory only; no file, record or root decision registry:Host@819,registry:Kind@135,whole:Route@138,whole:Route@546,whole:Route@822,whole:Route@924 30c48832f478dcd916e453d1ee6797eea9d46e3dc4cc7c0b6f8c1b89f96f7612 |
| +@legacy c007cb75d5d3591b89b2280c723a65af31bebff61b77267c99a869a0385ac97c internal/edge/usagemeter.go UsageMeter.RecordRateLimited legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): UsageMeter.Record's twin, adding one to the host's fair-share or backstop refusal counter in the in-memory usage row; it reads the row's host, app and account (release.RouteAccount); the counts ship with the rows Record fills; no file, record or root decision registry:App@195,registry:Host@146,registry:Host@284,whole:Route@190 c6d76bd368b93a6e1421840b2b0af3ac69d1572d657aee084c137095d4d903cb |
| @legacy 36d7a7ed4a7a7c3b21b038d7b992c69b7ffcbce9b37898c67072f5619b3ea177 internal/host/plans_pass.go planRateCeilingFor legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), as the edge's ceiling hook armed in runAgent: planIdleFor's twin, it reads the row's account (release.RouteAccount) and the plans pass's in-memory limits cache (planLimitsFor) and returns the plan's rate ceiling, or none; it reads no file or bucket object itself; a ceiling only clamps what an owner's settings allow (ratelimit.Resolve); no root decision whole:Route@108 768a1202101dbd3cfc1744c5b65750bf4c1a5c413ca3f83eb7d0ef8a625c213f |
| @legacy bf1cec7a0a74da9e2a63a6172be4c82186d0c1513fb29969a911535b14d99b5d internal/provision/reconcile.go Reconcile legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import journal read before the records are acted on (journalPass), seeded records dispatched first (seedAction), journaled hosts kept out of the removal phase and a row's seed column converged from its record; the agent's own pass;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=the record walk moves unchanged into the pass's scan closure (over a store argument) and the removal phase into its retire closure; over a record view snapshot, a pass that reaches a removal candidate proved by absence (record gone, app in the trash) removes nothing on the snapshot's word: it runs scan again over the bucket (freshStore) and decides every removal that pass from that walk, by the walk's own rules (unusable records protected before scope, hosts matched across every key, the bucket's trash marker); a walk that cannot read cleanly keeps every row; with no candidate, or disarmed (never a snapshot), nothing is read again; the registry sites are main's, moved; relative to main's single walk a removal can only be withheld, never added;rev3=census-ruling-design-edge-rate-limit-358;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the owned-converge arm gains the rate limit beside the gate: when the row's rate_limit differs from the record's (Record.RateLimitColumn), Registry.SetRateLimit converges it, logged as default or custom and never the settings (dry-run logs only); the new kind is registry:RateLimit, three sites, all existing.RateLimit (the comparison and the two log lines); no other read is added; the agent's own pass, no root decision registry:Account@20586,registry:Account@21678,registry:Account@36424,registry:Account@36470,registry:App@20559,registry:App@21651,registry:App@36444,registry:App@36482,registry:ClaimOwnership@21173,registry:DBPath@27903,registry:DBPath@27918,registry:DBPath@28164,registry:DBPath@28695,registry:DBPath@28708,registry:Gate@24314,registry:Gate@24454,registry:Gate@24719,registry:Hibernate@23292,registry:Hibernate@23610,registry:Hibernate@23961,registry:Hibernate@24249,registry:Host@14463,registry:Host@36402,registry:Host@36572,registry:Host@36669,registry:Host@36784,registry:Host@37129,registry:Host@37226,registry:Host@37403,registry:Host@37561,registry:Host@37663,registry:Kind@21315,registry:Kind@21578,registry:Kind@27821,registry:Kind@27834,registry:Kind@27944,registry:Kind@27957,registry:Kind@28606,registry:Kind@28617,registry:Kind@35638,registry:Kind@37394,registry:Kind@37552,registry:Kind@37654,registry:Pool@35730,registry:Provisioned@20535,registry:Provisioned@21627,registry:Provisioned@35688,registry:RateLimit@24805,registry:RateLimit@24956,registry:RateLimit@25243,registry:Region@35719,registry:Replication@23695,registry:Replication@23822,registry:Seed@26323,registry:SeedSource@25828,registry:Socket@27869,registry:Socket@27884,registry:Socket@28181,registry:Socket@28665,registry:Socket@28678,registry:Unit@27787,registry:Unit@27800,registry:Unit@28632,registry:Unit@28643,whole:ClaimOwnership@21176,whole:ClaimOwnership@21193,whole:Route@14445,whole:Route@14456,whole:Route@14474,whole:Route@15574,whole:Route@15874,whole:Route@15881,whole:Route@15921,whole:Route@16282,whole:Route@16600,whole:Route@17461,whole:Route@17817,whole:Route@17826,whole:Route@17872,whole:Route@20180,whole:Route@20651,whole:Route@20661,whole:Route@21018,whole:Route@21025,whole:Route@21093,whole:Route@21416,whole:Route@22059,whole:Route@23382,whole:Route@28013,whole:Route@29492,whole:Route@29537,whole:Route@29547,whole:Route@30410,whole:Route@31162,whole:Route@35086,whole:Route@35755,whole:Route@37474 5fd01d0295ed60c16c718c0825e0b4ce75d2e541ece2c40fcf07545c26bcc3b3 |
| @legacy 74d6d584f4c9ea8ad4ee277c6cb6b2a189d38225595ad6463e7244bc187d2468 internal/registry/registry.go Registry.SetRateLimit legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user): SetGate's twin, one UPDATE of routes.rate_limit by host, erroring on an unmatched host; its only caller is provision.Reconcile's converge in the agent, and the remote arm (Method SetRateLimit) is served by dispatchRemote; no root pass calls it; no root decision file:Exec@225,registry:remote@68,registry:remote@98,registry:sql@225,whole:remoteClient@100,whole:remoteClient@70 98673aee993b47c7f1610ac2f8fc1ad4881165c1b35369bbc6116d1e2d7577ac |
| @legacy a6d2441e353ebe51dce69db59aa75f28b46d4b98b22d0fce499902f6ed3355d2 internal/registry/registry.go scanRoute legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user): main's body with the two new columns scanned;rev3=census-ruling-design-edge-rate-limit-358;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user): main's body with the rate_limit column scanned into Route.RateLimit; the new kind is registry:RateLimit, one site; no other read registry:Account@393,registry:Addr@161,registry:Addrs@483,registry:App@236,registry:Args@542,registry:Backing@318,registry:BuildState@767,registry:Canary@852,registry:Caps@423,registry:CertExpiresAt@375,registry:Channel@266,registry:ClaimIncarnation@604,registry:ClaimOwner@640,registry:ClaimRowID@655,registry:ClaimStamp@625,registry:CreatedAt@526,registry:DBPath@197,registry:DNSCheckedAt@358,registry:DNSStatus@344,registry:Environment@407,registry:FleetBox@468,registry:Gate@517,registry:GoodDemand@714,registry:GoodDigest@699,registry:GoodVersion@683,registry:Health@493,registry:Hibernate@828,registry:HoldOp@670,registry:Host@123,registry:IdleSeconds@551,registry:ImportGate@799,registry:Kind@141,registry:LastError@183,registry:MaxRunSeconds@567,registry:NextDue@306,registry:Platform@898,registry:Pool@244,registry:PrevVersion@220,registry:Provisioned@922,registry:RateLimit@814,registry:Region@255,registry:Replica@949,registry:Replicas@585,registry:Replication@290,registry:Seed@450,registry:SeedSource@784,registry:ServingVersion@729,registry:Slug@132,registry:Socket@150,registry:Status@170,registry:StatusNamed@873,registry:Steering@504,registry:Tunnel@432,registry:Unit@459,registry:UpdateSettings@748,registry:Version@208,whole:Route@978 865112cbe26c41f815522679ed025a92acde5d2e998169bcdc610b211511a3ec |
| internal/edge/ratelimit.go Edge.noteRateLimited legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), serving only: counts one rate-limit refusal (or, observing, one that would have been) on the usage meter (UsageMeter.RecordRateLimited, passed the row) and logs it, throttled per host and reason; it reads the row's host for the log key and line; no file, record or root decision registry:Host@505,registry:Host@597,whole:Route@166 2a7c2bdb6a7e8a666660f2551a79fd9bf7e310f6952133314fc9eaa937d1230b |
| internal/edge/ratelimit.go Edge.parseRateSettings legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), at Reload: parses one route's rate_limit column (the owner's settings, converged from the instance record by provision.Reconcile) into ratelimit.Settings; an unparseable or out-of-range column runs at the platform defaults and is logged, throttled per host; it reads the row's rate_limit and host only; no file, record or root decision registry:Host@271,registry:Host@367,registry:RateLimit@158,registry:RateLimit@77 4420ba9c98146057f9d06ebe1e2c883e21e61d843a3e9790be12d3449f665504 |
| -internal/edge/ratelimit.go Edge.rateAdmit legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), serving only: judges a request to an instance against the owner's settings, the plan ceiling hook (planRateCeilingFor, passed the row) and the in-memory limiter keyed on the row's host, and answers 429 when CARLOS_RATE_LIMIT=enforce; a non-instance row, a door caller, a signed door hop and a fleet-tunnel request are never judged; it reads the row's kind and host; the limiter's buckets and slots are in memory only; no file, record or root decision registry:Host@834,registry:Kind@150,whole:Route@153,whole:Route@561,whole:Route@837,whole:Route@943 0d64f6b291978a45c4025bf6bcc2f5e243ecb4d19c643f1e258ad49f17803a99 |
| -internal/edge/usagemeter.go UsageMeter.RecordRateLimited legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): UsageMeter.Record's twin, adding one to the host's fair-share or backstop refusal counter in the in-memory usage row; it reads the row's host, app and account (release.RouteAccount); the counts ship with the rows Record fills; no file, record or root decision registry:App@206,registry:Host@146,registry:Host@294,whole:Route@191 d37236452f8d82c27dfca0937b8281d26d1894f180b13fff581a368022598229 |
| +internal/edge/ratelimit.go Edge.rateAdmit legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), serving only: judges a request to an instance against the owner's settings, the plan ceiling hook (planRateCeilingFor, passed the row) and the in-memory limiter keyed on the row's host, and answers 429 when CARLOS_RATE_LIMIT=enforce; a non-instance row, a door caller, a signed door hop and a fleet-tunnel request are never judged; it reads the row's kind and host; the limiter's buckets and slots are in memory only; no file, record or root decision registry:Host@819,registry:Kind@135,whole:Route@138,whole:Route@546,whole:Route@822,whole:Route@924 30c48832f478dcd916e453d1ee6797eea9d46e3dc4cc7c0b6f8c1b89f96f7612 |
| +internal/edge/usagemeter.go UsageMeter.RecordRateLimited legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): UsageMeter.Record's twin, adding one to the host's fair-share or backstop refusal counter in the in-memory usage row; it reads the row's host, app and account (release.RouteAccount); the counts ship with the rows Record fills; no file, record or root decision registry:App@195,registry:Host@146,registry:Host@284,whole:Route@190 c6d76bd368b93a6e1421840b2b0af3ac69d1572d657aee084c137095d4d903cb |
| internal/host/plans_pass.go planRateCeilingFor legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), as the edge's ceiling hook armed in runAgent: planIdleFor's twin, it reads the row's account (release.RouteAccount) and the plans pass's in-memory limits cache (planLimitsFor) and returns the plan's rate ceiling, or none; it reads no file or bucket object itself; a ceiling only clamps what an owner's settings allow (ratelimit.Resolve); no root decision whole:Route@108 768a1202101dbd3cfc1744c5b65750bf4c1a5c413ca3f83eb7d0ef8a625c213f |
| internal/provision/reconcile.go Reconcile legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import journal read before the records are acted on (journalPass), seeded records dispatched first (seedAction), journaled hosts kept out of the removal phase and a row's seed column converged from its record; the agent's own pass;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=the record walk moves unchanged into the pass's scan closure (over a store argument) and the removal phase into its retire closure; over a record view snapshot, a pass that reaches a removal candidate proved by absence (record gone, app in the trash) removes nothing on the snapshot's word: it runs scan again over the bucket (freshStore) and decides every removal that pass from that walk, by the walk's own rules (unusable records protected before scope, hosts matched across every key, the bucket's trash marker); a walk that cannot read cleanly keeps every row; with no candidate, or disarmed (never a snapshot), nothing is read again; the registry sites are main's, moved; relative to main's single walk a removal can only be withheld, never added;rev3=census-ruling-design-edge-rate-limit-358;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): the owned-converge arm gains the rate limit beside the gate: when the row's rate_limit differs from the record's (Record.RateLimitColumn), Registry.SetRateLimit converges it, logged as default or custom and never the settings (dry-run logs only); the new kind is registry:RateLimit, three sites, all existing.RateLimit (the comparison and the two log lines); no other read is added; the agent's own pass, no root decision registry:Account@20586,registry:Account@21678,registry:Account@36424,registry:Account@36470,registry:App@20559,registry:App@21651,registry:App@36444,registry:App@36482,registry:ClaimOwnership@21173,registry:DBPath@27903,registry:DBPath@27918,registry:DBPath@28164,registry:DBPath@28695,registry:DBPath@28708,registry:Gate@24314,registry:Gate@24454,registry:Gate@24719,registry:Hibernate@23292,registry:Hibernate@23610,registry:Hibernate@23961,registry:Hibernate@24249,registry:Host@14463,registry:Host@36402,registry:Host@36572,registry:Host@36669,registry:Host@36784,registry:Host@37129,registry:Host@37226,registry:Host@37403,registry:Host@37561,registry:Host@37663,registry:Kind@21315,registry:Kind@21578,registry:Kind@27821,registry:Kind@27834,registry:Kind@27944,registry:Kind@27957,registry:Kind@28606,registry:Kind@28617,registry:Kind@35638,registry:Kind@37394,registry:Kind@37552,registry:Kind@37654,registry:Pool@35730,registry:Provisioned@20535,registry:Provisioned@21627,registry:Provisioned@35688,registry:RateLimit@24805,registry:RateLimit@24956,registry:RateLimit@25243,registry:Region@35719,registry:Replication@23695,registry:Replication@23822,registry:Seed@26323,registry:SeedSource@25828,registry:Socket@27869,registry:Socket@27884,registry:Socket@28181,registry:Socket@28665,registry:Socket@28678,registry:Unit@27787,registry:Unit@27800,registry:Unit@28632,registry:Unit@28643,whole:ClaimOwnership@21176,whole:ClaimOwnership@21193,whole:Route@14445,whole:Route@14456,whole:Route@14474,whole:Route@15574,whole:Route@15874,whole:Route@15881,whole:Route@15921,whole:Route@16282,whole:Route@16600,whole:Route@17461,whole:Route@17817,whole:Route@17826,whole:Route@17872,whole:Route@20180,whole:Route@20651,whole:Route@20661,whole:Route@21018,whole:Route@21025,whole:Route@21093,whole:Route@21416,whole:Route@22059,whole:Route@23382,whole:Route@28013,whole:Route@29492,whole:Route@29537,whole:Route@29547,whole:Route@30410,whole:Route@31162,whole:Route@35086,whole:Route@35755,whole:Route@37474 5fd01d0295ed60c16c718c0825e0b4ce75d2e541ece2c40fcf07545c26bcc3b3 |
| internal/registry/registry.go Registry.SetRateLimit legacy accepted-legacy accepted-legacy;rev3=census-ruling-design-edge-rate-limit-358;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user): SetGate's twin, one UPDATE of routes.rate_limit by host, erroring on an unmatched host; its only caller is provision.Reconcile's converge in the agent, and the remote arm (Method SetRateLimit) is served by dispatchRemote; no root pass calls it; no root decision file:Exec@225,registry:remote@68,registry:remote@98,registry:sql@225,whole:remoteClient@100,whole:remoteClient@70 98673aee993b47c7f1610ac2f8fc1ad4881165c1b35369bbc6116d1e2d7577ac |
diff --git a/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv b/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv| index fe8b6b627..9fc7c22e0 100644 |
| --- a/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv |
| +++ b/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv |
| @@ -1,27 +1,29 @@ |
| # Census overlay design-edge-rate-limit-358, written by census-propose (#369). census-ruling-design-edge-rate-limit-358, approved by the census owner before the merge; the approval card is docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md. |
| -# 8 body, 1 sites, 10 envelope: each changed unit re-frozen at its existing disposition with its claim appended. |
| +# 9 body, 1 sites, 10 envelope: each changed unit re-frozen at its existing disposition with its claim appended. |
| @legacy 12666f5777e9cdd14f7081080a34942ab70fb1181891102264a2679beabc7034 internal/console/server.go NewServer legacy accepted-legacy accepted-legacy;rev3=PROPOSED-scan-demand-revival;basis=Console construction adds queue and notification state. The existing logs/data route literal moves; it is not a filesystem read.;rev3=PROPOSED-email-signin;identity=the console (cmd/console serve under console.service, user carlos-console);basis=sets consoleNameCfg from Config.ConsoleName and the challengeSem send bound, and registers the four /auth/email routes; no goroutine; the one data-literal is still the logs/data route pattern, moved; the record-write census re-digests the same unit;rev3=census-ruling-db-region-forward-2;identity=the console (cmd/console serve under console.service, user carlos-console);basis=sets the forwarded db read's open-read limits (dbReads, held by each read's request) and its timing (dbf); no goroutine and no store call; the one data-literal is still the logs/data route pattern, moved; the record-write census re-digests the same unit;rev3=census-ruling-design-edge-rate-limit-358;basis=one route registered beside the gate's form: POST /a/{sqid}/apps/{app}/ratelimit to handleAppRateLimit, the Settings page's rate-limit form, member-gated like the gate; no read added, its one data-literal site unchanged (offset moved) data-literal@9622 4343f2a14894c83e13d92b6d6355de37dac460f60e6e1c0695ea1cf6ed3546ad |
| @legacy 4dc877a4cdd78db02dabc37009ce94a65ab7800cb2a98e3290fc66c4b0b770af internal/console/templates/app_settings.html external legacy accepted-legacy accepted-legacy;rev3=J4;basis=root-input;rev3=census-ruling-design-edge-rate-limit-358;basis=the Settings page gains a Rate limit section: per instance host, a form of four numbers (busy at, per address while busy, backstop rate, backstop burst) and a reset form, both posting to /a/{sqid}/apps/{app}/ratelimit with the CSRF token, and the record's path rules listed read-only; embedded and rendered by the console (carlos-console), as before; no read added file:external@0 0f1d88200a26eb1b1e502ef5b1839985ce0c54027caabd2caefa03682b7d289b |
| -@legacy 15e46da0ce10b15d774c98b4d840bda0bdaee7481e6533cb81764dd1934bedb1 internal/edge/edge.go Edge.ServeHTTP legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import gate checked after the door's scope and a gated row left out of the response cache; serving only;rev3=census-ruling-design-edge-rate-limit-358;basis=calls rateAdmit twice: on the upgrade path before the activator or proxy (judged, holds no slot), and on the ordinary path after the response-cache check and before the activator and proxy (an admitted request holds a slot through slotWriter, released by a defer); a refusal is a 429 written there and returns; one comment on the door mark reworded; read sites unchanged (21), offsets moved; no read added registry:Gate@13548,registry:Gate@13608,registry:Gate@13666,registry:Host@13651,registry:ImportGate@17008,registry:Kind@11787,registry:Kind@16979,whole:Route@10017,whole:Route@11790,whole:Route@12348,whole:Route@12443,whole:Route@12519,whole:Route@13551,whole:Route@13611,whole:Route@13654,whole:Route@13669,whole:Route@14767,whole:Route@16982,whole:Route@17011,whole:Route@18849,whole:Route@9805 609519d34988d78661b0a15fdc0ccfc68afe121440078244ef415a9b43c67a0e |
| +@legacy d39213a91e68bd5190aeec166f34c3c6976d943538df97aed30577100017af28 internal/edge/edge.go Edge.ServeHTTP legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import gate checked after the door's scope and a gated row left out of the response cache; serving only;rev3=census-ruling-design-edge-rate-limit-358;basis=calls rateAdmit twice, and an admitted request holds a slot on both paths: on the upgrade path before the activator or proxy (the handshake holds its slot through slotWriter, given back at the first final answer or at the reverse proxy's hijack on a 101, so an open WebSocket is not counted; released by a defer), and on the ordinary path after the response-cache check and before the activator and proxy (an admitted request holds a slot through slotWriter, released by a defer); a refusal is a 429 written there and returns; the upgrade path's comment now names slotWriter as its one wrapper; one comment on the door mark reworded; read sites unchanged (21), offsets moved; no read added registry:Gate@13548,registry:Gate@13608,registry:Gate@13666,registry:Host@13651,registry:ImportGate@17416,registry:Kind@11787,registry:Kind@17387,whole:Route@10017,whole:Route@11790,whole:Route@12348,whole:Route@12443,whole:Route@12519,whole:Route@13551,whole:Route@13611,whole:Route@13654,whole:Route@13669,whole:Route@15175,whole:Route@17390,whole:Route@17419,whole:Route@19251,whole:Route@9805 440946467380de55e0a452c3bc27f6a7913c4aa77ee89848676eb204396c4b21 |
| +@legacy 988a2a3e1f4356c74417d0b3c4e6a52953dfe6127fbe84ed912a3e151f7ace70 internal/edge/usagemeter.go UsageMeter.Record legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=census-ruling-design-edge-rate-limit-358;basis=the two lines that set the row's Account and App become one call, row.SetOwner(release.RouteAccount(rt), rt.App) (usage.EdgeRow.SetOwner, on the in-memory row), which sets the same two fields and, when the host's owner changes, first zeroes the row's two rate-limit refusal counters; Requests, BytesOut and the hop counters sum as before; read sites unchanged (4); no read added registry:App@159,registry:Host@110,registry:Host@294,whole:Route@154 26201bb2b0c6265323b7e308d5bea124d2027552bddb4acd0ba10be641d5556a |
| @legacy 0055249a3fc293277c78f91e2b72775f74963f3e7972e5202df2daba0c698a5c internal/registry/registry.go Registry.Fingerprint legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user); the remote arm, unchanged, in the process that holds a remote handle: main's body with the import gate folded into the edge's change poll when it is set, so an ungated registry digests as before;rev3=census-ruling-design-edge-rate-limit-358;basis=the routes SELECT gains rate_limit, scanned into one more local and hashed as a tagged rate_limit field only when non-empty, so a registry with no custom limits digests as before and a change reaches a running edge; read sites unchanged (26); no read added file:Exec@284,file:Open@188,file:Query@3213,file:Query@368,file:Query@3692,file:Query@4678,file:Query@5374,file:Query@6286,registry:ClaimIncarnation@1151,registry:ClaimIncarnation@2495,registry:ClaimIncarnation@2572,registry:ClaimOwner@1195,registry:ClaimOwner@2696,registry:ClaimOwner@2761,registry:ClaimRowID@1214,registry:ClaimRowID@2788,registry:ClaimRowID@2854,registry:ClaimStamp@1176,registry:ClaimStamp@2605,registry:ClaimStamp@2669,registry:Text@158,registry:path@207,registry:remote@55,registry:remote@87,whole:remoteClient@57,whole:remoteClient@89 0ebad83d83f27a1a3d05956ada3871e551ba2941d9050fb3b0ece9360c3647e3 |
| @legacy 617ef492e8fe770122a162c4ddf2da357ae42ef107580ef341407abaa573f8e6 internal/registry/registry.go Registry.migrate legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user), on every registry open; a box CLI verb that opens the registry directly runs it as whoever runs the verb: main's body with two columns added to routes (seed_source, import_gate) and the import journal's and fence counter's migrations called;rev3=census-ruling-design-edge-rate-limit-358;basis=one more additive statement in the existing loop, ALTER TABLE routes ADD COLUMN rate_limit TEXT NOT NULL DEFAULT '' (a duplicate column is ignored, as for the others); read sites unchanged (16); no read added file:Exec@3545,file:Exec@3869,file:Exec@4600,file:Exec@51,file:Exec@5460,file:Exec@5739,file:Exec@6602,file:Exec@6778,registry:sql@3545,registry:sql@3869,registry:sql@4600,registry:sql@51,registry:sql@5460,registry:sql@5739,registry:sql@6602,registry:sql@6778 c8b342b28b86ce5a07e9605774a44a4f100d869838bc3eecfdffdcc0e7fd74c2 |
| @legacy 84de56fb3bd2ffca9ef55e812d7306ba3051e228a47148b86020a11750b15065 internal/edge/edge.go Edge.Reload legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=census-ruling-design-edge-rate-limit-358;basis=each route's upstream entry gains rate: e.parseRateSettings(t), the row's rate_limit column parsed once per reload; the one added site is that whole:Route pass of t (parseRateSettings is a new unit, classified in the decisions overlay); no other read added registry:Account@18112,registry:Alias@16421,registry:Alias@16508,registry:Alias@16604,registry:FleetBox@5526,registry:Health@7689,registry:Health@7807,registry:Hibernate@12450,registry:Hibernate@14360,registry:Hibernate@6049,registry:Host@12498,registry:Host@14422,registry:Host@14730,registry:Host@14757,registry:Host@15558,registry:Host@15824,registry:Host@16547,registry:Host@6098,registry:Host@8290,registry:Host@8385,registry:Host@8665,registry:Host@8691,registry:Host@8743,registry:Kind@10975,registry:Kind@10997,registry:Kind@12426,registry:Kind@14336,registry:Kind@6025,registry:Kind@8831,registry:Kind@8891,registry:Name@18102,registry:Prefix@15799,registry:Region@2252,registry:Socket@14738,registry:Socket@5633,registry:Socket@6162,registry:Status@1835,registry:Target@15811,registry:Tunnel@4574,registry:Tunnel@4630,registry:Version@10956,registry:Version@11058,whole:Fleet@18052,whole:Fleet@18081,whole:Route@130,whole:Route@14790,whole:Route@14797,whole:Route@14893,whole:Route@4692,whole:Route@5590,whole:Route@6218,whole:Route@648,whole:Route@8808,whole:Route@8881,whole:Route@8941,whole:RouteAlias@16392,whole:RoutePath@15536 16c52a2546fa47d998316fbf6ed8b26d88bd3cebeff73a8c24da572f260502be |
| internal/console/server.go NewServer legacy accepted-legacy accepted-legacy;rev3=PROPOSED-scan-demand-revival;basis=Console construction adds queue and notification state. The existing logs/data route literal moves; it is not a filesystem read.;rev3=PROPOSED-email-signin;identity=the console (cmd/console serve under console.service, user carlos-console);basis=sets consoleNameCfg from Config.ConsoleName and the challengeSem send bound, and registers the four /auth/email routes; no goroutine; the one data-literal is still the logs/data route pattern, moved; the record-write census re-digests the same unit;rev3=census-ruling-db-region-forward-2;identity=the console (cmd/console serve under console.service, user carlos-console);basis=sets the forwarded db read's open-read limits (dbReads, held by each read's request) and its timing (dbf); no goroutine and no store call; the one data-literal is still the logs/data route pattern, moved; the record-write census re-digests the same unit;rev3=census-ruling-design-edge-rate-limit-358;basis=one route registered beside the gate's form: POST /a/{sqid}/apps/{app}/ratelimit to handleAppRateLimit, the Settings page's rate-limit form, member-gated like the gate; no read added, its one data-literal site unchanged (offset moved) data-literal@9622 4343f2a14894c83e13d92b6d6355de37dac460f60e6e1c0695ea1cf6ed3546ad |
| internal/console/templates/app_settings.html external legacy accepted-legacy accepted-legacy;rev3=J4;basis=root-input;rev3=census-ruling-design-edge-rate-limit-358;basis=the Settings page gains a Rate limit section: per instance host, a form of four numbers (busy at, per address while busy, backstop rate, backstop burst) and a reset form, both posting to /a/{sqid}/apps/{app}/ratelimit with the CSRF token, and the record's path rules listed read-only; embedded and rendered by the console (carlos-console), as before; no read added file:external@0 0f1d88200a26eb1b1e502ef5b1839985ce0c54027caabd2caefa03682b7d289b |
| -internal/edge/edge.go Edge.ServeHTTP legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import gate checked after the door's scope and a gated row left out of the response cache; serving only;rev3=census-ruling-design-edge-rate-limit-358;basis=calls rateAdmit twice: on the upgrade path before the activator or proxy (judged, holds no slot), and on the ordinary path after the response-cache check and before the activator and proxy (an admitted request holds a slot through slotWriter, released by a defer); a refusal is a 429 written there and returns; one comment on the door mark reworded; read sites unchanged (21), offsets moved; no read added registry:Gate@13548,registry:Gate@13608,registry:Gate@13666,registry:Host@13651,registry:ImportGate@17008,registry:Kind@11787,registry:Kind@16979,whole:Route@10017,whole:Route@11790,whole:Route@12348,whole:Route@12443,whole:Route@12519,whole:Route@13551,whole:Route@13611,whole:Route@13654,whole:Route@13669,whole:Route@14767,whole:Route@16982,whole:Route@17011,whole:Route@18849,whole:Route@9805 609519d34988d78661b0a15fdc0ccfc68afe121440078244ef415a9b43c67a0e |
| +internal/edge/edge.go Edge.ServeHTTP legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the edge inside the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with the import gate checked after the door's scope and a gated row left out of the response cache; serving only;rev3=census-ruling-design-edge-rate-limit-358;basis=calls rateAdmit twice, and an admitted request holds a slot on both paths: on the upgrade path before the activator or proxy (the handshake holds its slot through slotWriter, given back at the first final answer or at the reverse proxy's hijack on a 101, so an open WebSocket is not counted; released by a defer), and on the ordinary path after the response-cache check and before the activator and proxy (an admitted request holds a slot through slotWriter, released by a defer); a refusal is a 429 written there and returns; the upgrade path's comment now names slotWriter as its one wrapper; one comment on the door mark reworded; read sites unchanged (21), offsets moved; no read added registry:Gate@13548,registry:Gate@13608,registry:Gate@13666,registry:Host@13651,registry:ImportGate@17416,registry:Kind@11787,registry:Kind@17387,whole:Route@10017,whole:Route@11790,whole:Route@12348,whole:Route@12443,whole:Route@12519,whole:Route@13551,whole:Route@13611,whole:Route@13654,whole:Route@13669,whole:Route@15175,whole:Route@17390,whole:Route@17419,whole:Route@19251,whole:Route@9805 440946467380de55e0a452c3bc27f6a7913c4aa77ee89848676eb204396c4b21 |
| +internal/edge/usagemeter.go UsageMeter.Record legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=census-ruling-design-edge-rate-limit-358;basis=the two lines that set the row's Account and App become one call, row.SetOwner(release.RouteAccount(rt), rt.App) (usage.EdgeRow.SetOwner, on the in-memory row), which sets the same two fields and, when the host's owner changes, first zeroes the row's two rate-limit refusal counters; Requests, BytesOut and the hop counters sum as before; read sites unchanged (4); no read added registry:App@159,registry:Host@110,registry:Host@294,whole:Route@154 26201bb2b0c6265323b7e308d5bea124d2027552bddb4acd0ba10be641d5556a |
| internal/host/agent.go runAgent authority B,C,D,F rev3=census-ruling-seeded-instances;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): main's body with wireSeedPlacement called in the activator start's Configure step, before armMovesPass, and the startup sweep's result stored for the import rollback in Recover; read sites unchanged, offsets moved; main's B,C,D,F authority retained PROPOSED E46: captured claim selection and root journal mutation; root RPC outside service host exclusion; SQL/route data never grants root authority. Executing identity: service controller; root for inventory/retirement callbacks.;rev3=PROPOSED-325;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=passes the agent's log sink to armRunsPass; reads unchanged;rev3=census-ruling-db-region-forward-1;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=arms the db-reads loop (armDBReads) beside armRunsPass in the activator start's Configure step; reads unchanged, offsets moved; main's authority retained;rev3=PROPOSED-s3-change-index;identity=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos);basis=arms the change index (armChangeIndex) and starts the record view's backstop loop before the loops that read through it, and hands the edge the watch loader (edge.WithChangeWatch); read sites unchanged at the same offsets;rev3=census-ruling-design-edge-rate-limit-358;basis=arms the edge's plan rate-ceiling hook, e.SetRateCeilingFor(planRateCeilingFor), right after EnableUsage; read sites unchanged (5), offsets moved; no read added file:Exec@13802,file:Open@731,registry:App@10065,whole:Route@10057,whole:Route@23518 e16e48c7cc247e1deeefdd832f5c911c8cf6c48c254e649563287096154dbe66 |
| internal/provision/reconcile.go RouteFor authority C,E3 rev3=census-ruling-seeded-instances;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos); also root, in the claim root's landing registration (ClaimRootHTTP.rootLandingRoute) and the relocation install (relocationRecord): main's body with one more field: the row's seed column, derived from the record's seed (SeedColumn). Every caller gets it, the two root ones included, so a root-registered row for a seeded record now carries the seed the activator places from; main's C,E3 authority retained;rev3=census-ruling-design-edge-rate-limit-358;basis=the route literal gains RateLimit: rec.RateLimitColumn(), the record's settings as canonical JSON or "" for the defaults (a provision.Record method, not a registry read); every caller gets it, the root ones included (ClaimRootHTTP.rootLandingRoute, relocationRecord), which only carry the column and never read it; read sites unchanged (9); no read added registry:Addr@1306,registry:Addrs@1315,registry:DBPath@1254,registry:DBPath@952,registry:Health@1325,registry:Hibernate@1198,registry:Socket@1216,registry:Socket@914,whole:Route@1363 f6d1b81f120584b95615a5dc701348e2f404ce8e95264259f3c2bf2d106ebfa4 |
| internal/registry/registry.go Registry.Fingerprint legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user); the remote arm, unchanged, in the process that holds a remote handle: main's body with the import gate folded into the edge's change poll when it is set, so an ungated registry digests as before;rev3=census-ruling-design-edge-rate-limit-358;basis=the routes SELECT gains rate_limit, scanned into one more local and hashed as a tagged rate_limit field only when non-empty, so a registry with no custom limits digests as before and a change reaches a running edge; read sites unchanged (26); no read added file:Exec@284,file:Open@188,file:Query@3213,file:Query@368,file:Query@3692,file:Query@4678,file:Query@5374,file:Query@6286,registry:ClaimIncarnation@1151,registry:ClaimIncarnation@2495,registry:ClaimIncarnation@2572,registry:ClaimOwner@1195,registry:ClaimOwner@2696,registry:ClaimOwner@2761,registry:ClaimRowID@1214,registry:ClaimRowID@2788,registry:ClaimRowID@2854,registry:ClaimStamp@1176,registry:ClaimStamp@2605,registry:ClaimStamp@2669,registry:Text@158,registry:path@207,registry:remote@55,registry:remote@87,whole:remoteClient@57,whole:remoteClient@89 0ebad83d83f27a1a3d05956ada3871e551ba2941d9050fb3b0ece9360c3647e3 |
| internal/registry/registry.go Registry.Upsert authority E3 rev3=census-ruling-seeded-instances;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user); the remote arm, unchanged, in the process that holds a remote handle, root passes included: main's body with its insert defaults moved to normalizeRoute and its bind list to routeArgs, and two columns added (seed_source, import_gate); the conflict clause, with the tenant-change rule E3 names, is unchanged; main's E3 authority retained;rev3=census-ruling-design-edge-rate-limit-358;basis=the ON CONFLICT clause gains rate_limit=CASE WHEN excluded.rate_limit = '' THEN routes.rate_limit ELSE excluded.rate_limit END, the gate's idiom, so a full-row writer that predates the column cannot reset an owner's limits; the bind list is routeArgs (re-frozen in the decisions overlay); read sites unchanged (9); no read added file:Exec@175,registry:remote@47,registry:remote@77,registry:sql@175,whole:Route@128,whole:Route@136,whole:Route@3028,whole:remoteClient@49,whole:remoteClient@79 9cc69884de67aa6ef2e51a6b231dab30c9a07f7f468d905566a61ad585aa22c3 |
| internal/registry/registry.go Registry.migrate legacy accepted-legacy accepted-legacy;rev3=census-ruling-seeded-instances;basis=the registry's SQLite side, as carlos: in the agent (/opt/carlos/carlos agent, carlos-edge.service) and in the registry child (carlos __registry-child, which a root pass forks as the service user), on every registry open; a box CLI verb that opens the registry directly runs it as whoever runs the verb: main's body with two columns added to routes (seed_source, import_gate) and the import journal's and fence counter's migrations called;rev3=census-ruling-design-edge-rate-limit-358;basis=one more additive statement in the existing loop, ALTER TABLE routes ADD COLUMN rate_limit TEXT NOT NULL DEFAULT '' (a duplicate column is ignored, as for the others); read sites unchanged (16); no read added file:Exec@3545,file:Exec@3869,file:Exec@4600,file:Exec@51,file:Exec@5460,file:Exec@5739,file:Exec@6602,file:Exec@6778,registry:sql@3545,registry:sql@3869,registry:sql@4600,registry:sql@51,registry:sql@5460,registry:sql@5739,registry:sql@6602,registry:sql@6778 c8b342b28b86ce5a07e9605774a44a4f100d869838bc3eecfdffdcc0e7fd74c2 |
| internal/edge/edge.go Edge.Reload legacy accepted-legacy accepted-legacy;rev3=J1;basis=root-route;rev3=census-ruling-design-edge-rate-limit-358;basis=each route's upstream entry gains rate: e.parseRateSettings(t), the row's rate_limit column parsed once per reload; the one added site is that whole:Route pass of t (parseRateSettings is a new unit, classified in the decisions overlay); no other read added registry:Account@18112,registry:Alias@16421,registry:Alias@16508,registry:Alias@16604,registry:FleetBox@5526,registry:Health@7689,registry:Health@7807,registry:Hibernate@12450,registry:Hibernate@14360,registry:Hibernate@6049,registry:Host@12498,registry:Host@14422,registry:Host@14730,registry:Host@14757,registry:Host@15558,registry:Host@15824,registry:Host@16547,registry:Host@6098,registry:Host@8290,registry:Host@8385,registry:Host@8665,registry:Host@8691,registry:Host@8743,registry:Kind@10975,registry:Kind@10997,registry:Kind@12426,registry:Kind@14336,registry:Kind@6025,registry:Kind@8831,registry:Kind@8891,registry:Name@18102,registry:Prefix@15799,registry:Region@2252,registry:Socket@14738,registry:Socket@5633,registry:Socket@6162,registry:Status@1835,registry:Target@15811,registry:Tunnel@4574,registry:Tunnel@4630,registry:Version@10956,registry:Version@11058,whole:Fleet@18052,whole:Fleet@18081,whole:Route@130,whole:Route@14790,whole:Route@14797,whole:Route@14893,whole:Route@4692,whole:Route@5590,whole:Route@6218,whole:Route@648,whole:Route@8808,whole:Route@8881,whole:Route@8941,whole:RouteAlias@16392,whole:RoutePath@15536 16c52a2546fa47d998316fbf6ed8b26d88bd3cebeff73a8c24da572f260502be |
| -@coverage . 4d61a01a06679b36cf3cf38da83553c4acb2425a4365cc91e384a3b6b6af5bd6 |
| -@coverage internal/console c0063d66b0de8b090e72853b16aaf2333c18e211cb24a8407d78285c09683f7a |
| +@coverage . 3c5f87289555ab64a5e8bdfbd06f30e41f69149a31e15989851e23b4e304a0bc |
| +@coverage internal/console 1957e8dc92e5eea4e66d8383dfc0e2b06b2b769316b0f189a37e5443fe30a3f0 |
| @coverage internal/console/templates a8c01dd0083c310f3bd3502ccbf449a0ab3d0ce55f3b493ad116b80b505077fa |
| -@coverage internal/edge 3e20595cb0e7470eb0803d69845028e1377551746000b2b6fe4416a10e32f217 |
| +@coverage internal/edge 6135ebfee605b6b6884ffa0c08f51f642ed7ea8580080cc62093144445dfd6dd |
| @coverage internal/host f83c03b67ef0ef359805e7cc4ddbfebca00531f2fe916a080c12273394bd6210 |
| -@coverage internal/plans 239eda11f74ab55ab8cf122e0007c1e71a48582c6759c2f999dd8f952d73b85c |
| +@coverage internal/plans 46b6f69ea1e2515286a866b3c691213a2231361fa8a40e5e8e4c343fe64a7a5f |
| @coverage internal/provision 06dd00d5db597198fcdd823a3fdc5d78df1ec9cb06dbcd61487476be5cb60d69 |
| -@coverage internal/ratelimit af90b95e13a5234c92e9d0bba18507a40116f05615cdc01f1db595c3ecd69bdb |
| +@coverage internal/ratelimit 6be3d8b8bb735625ca669cf55b3a943356fdd9421fd8aa6cac7dce72d31480a5 |
| @coverage internal/registry a5d78e9d8dc69a497941817cff1e2b423917265332ec9f2f7d8eed00a44ffaa2 |
| -@coverage internal/usage abff13ddd6cc3cfa90b33af54166be798586cf356d5ff1ac25677b41e8f4e6ef |
| +@coverage internal/usage 06b1c2063329df4dcdc786717d1cab0945b5d25703213c0cd3ddbd9e6946b12f |