census: overlay and record-write entries for design-edge-rate-limit-358 (#358)
Root-read census: two overlays, appended to the chain manifest in order. - plan14-root-reads-design-edge-rate-limit-358-decisions.tsv, written by hand: the eleven decisions census-propose refuses. Six new units (Edge.rateAdmit, parseRateSettings, noteRateLimited, UsageMeter.RecordRateLimited, planRateCeilingFor, Registry.SetRateLimit) proposed accepted legacy like their neighbours; four units that gain the registry:RateLimit kind (Reconcile, scanRoute, routeArgs, dispatchRemote) re-frozen at the disposition each already has; @fields gains RateLimit. Seal 945934f5 -> 73889e6d. - plan14-root-reads-design-edge-rate-limit-358.tsv, from make census-propose: 8 body, 1 sites, 10 envelope re-pins. Seal 73889e6d -> 01b8594b. The card, docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md, is census-propose's, with a hand-written decisions section appended. Every row carries rev3=census-ruling-design-edge-rate-limit-358; the ruling is to be asked on #280. Record-write census (9B8): edgeRateLimitWriteCensusInventory, layered on dbRegionForward3WriteCensusInventory. handleAppRateLimit is a new record-writer (handleAppGate's twin), handleAPIInstanceUpdate stays a record-writer, two new apimode CLI clients are key-sites, and registerCLIRoutes, NewServer, Reconcile and main are re-pinned as key-sites. No raw record write is added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 files changed,
+160
−1
docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md+45 −0internal/provision/edge_rate_limit_census_test.go+63 −0internal/provision/plan9_b8_census_test.go+1 −1internal/provision/testdata/plan14-root-reads-chain.tsv+2 −0internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358-decisions.tsv+22 −0internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv+27 −0
CI failed — run details
CI log
=== gate ===
.amadan/test-gate.sh
=== launchctx (0 s)
ok amadan.net/carlos/platform.git/launchctx 0.015s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
=== vet (1 s)
=== gofmt (0 s)
gofmt -l .: clean
=== rest (148 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 11.839s
ok github.com/carlosframework/platform/cmd/zddprobe 0.771s
ok github.com/carlosframework/platform/internal/activator 59.297s
ok github.com/carlosframework/platform/internal/agentsock 0.028s
ok github.com/carlosframework/platform/internal/alerting 0.005s
ok github.com/carlosframework/platform/internal/analytics 0.024s
ok github.com/carlosframework/platform/internal/appconfig 3.239s
ok github.com/carlosframework/platform/internal/apperr 0.096s
ok github.com/carlosframework/platform/internal/applog 0.265s
ok github.com/carlosframework/platform/internal/awsinv 0.004s
ok github.com/carlosframework/platform/internal/boxchoice 0.004s
ok github.com/carlosframework/platform/internal/boxid 0.804s
? 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.008s
ok github.com/carlosframework/platform/internal/caps 0.016s
ok github.com/carlosframework/platform/internal/certwarm 0.002s
ok github.com/carlosframework/platform/internal/cgroup 0.775s
ok github.com/carlosframework/platform/internal/changelog 0.526s
ok github.com/carlosframework/platform/internal/claimactivation 1.368s
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.517s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.009s
ok github.com/carlosframework/platform/internal/dbquery 0.007s
ok github.com/carlosframework/platform/internal/dbreads 2.086s
? github.com/carlosframework/platform/internal/dbreads/dbreadstest [no test files]
ok github.com/carlosframework/platform/internal/dbverify 0.004s
ok github.com/carlosframework/platform/internal/dnsrec 0.004s
--- FAIL: TestFenceLanguagesAreDeclared (0.00s)
fences_test.go:32: cli.md:1196: fence declares no language
FAIL
FAIL github.com/carlosframework/platform/internal/docsite 0.012s
ok github.com/carlosframework/platform/internal/domains 3.042s
ok github.com/carlosframework/platform/internal/doorkey 0.015s
ok github.com/carlosframework/platform/internal/economics 0.004s
ok github.com/carlosframework/platform/internal/edge 46.378s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.010s
ok github.com/carlosframework/platform/internal/fleetapi 0.217s
ok github.com/carlosframework/platform/internal/gate 1.971s
ok github.com/carlosframework/platform/internal/genselect 0.034s
ok github.com/carlosframework/platform/internal/geo 0.023s
ok github.com/carlosframework/platform/internal/geoip 0.072s
ok github.com/carlosframework/platform/internal/historyreadback 0.294s
ok github.com/carlosframework/platform/internal/host 144.630s
ok github.com/carlosframework/platform/internal/hostactors 7.325s
ok github.com/carlosframework/platform/internal/hostactors/awsmembership 0.008s
ok github.com/carlosframework/platform/internal/hostbox 3.260s
ok github.com/carlosframework/platform/internal/hostclaim 0.973s
ok github.com/carlosframework/platform/internal/hostenv 0.008s
ok github.com/carlosframework/platform/internal/hostevidence 0.013s
ok github.com/carlosframework/platform/internal/hostexec 5.620s
ok github.com/carlosframework/platform/internal/hostfence 0.055s
ok github.com/carlosframework/platform/internal/hostfiles 10.267s
ok github.com/carlosframework/platform/internal/hostfloor 0.032s
ok github.com/carlosframework/platform/internal/hostguard 1.089s
ok github.com/carlosframework/platform/internal/hostops 2.285s
? 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.703s
ok github.com/carlosframework/platform/internal/hostresolve 0.226s
ok github.com/carlosframework/platform/internal/hostwrite 0.003s
ok github.com/carlosframework/platform/internal/infraview 0.005s
ok github.com/carlosframework/platform/internal/instancectl 5.272s
ok github.com/carlosframework/platform/internal/instanceexec 2.835s
ok github.com/carlosframework/platform/internal/instancefs 0.006s
ok github.com/carlosframework/platform/internal/instancekey 0.006s
ok github.com/carlosframework/platform/internal/instanceupdates 0.008s
ok github.com/carlosframework/platform/internal/layout 1.927s
ok github.com/carlosframework/platform/internal/lbhealth 0.008s
ok github.com/carlosframework/platform/internal/lease 10.077s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.593s
ok github.com/carlosframework/platform/internal/ledger 0.030s
ok github.com/carlosframework/platform/internal/mail 0.259s
ok github.com/carlosframework/platform/internal/maintenance 0.081s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.606s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.141s
ok github.com/carlosframework/platform/internal/metrics 0.005s
ok github.com/carlosframework/platform/internal/moves 21.217s
ok github.com/carlosframework/platform/internal/moves/archive 1.106s
ok github.com/carlosframework/platform/internal/objstore 0.254s
ok github.com/carlosframework/platform/internal/ops 0.187s
ok github.com/carlosframework/platform/internal/park 0.299s
ok github.com/carlosframework/platform/internal/plans 0.006s
ok github.com/carlosframework/platform/internal/privatefile 0.006s
ok github.com/carlosframework/platform/internal/provision 13.986s
ok github.com/carlosframework/platform/internal/publicrelease 0.010s
ok github.com/carlosframework/platform/internal/ratelimit 0.099s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 5.653s
ok github.com/carlosframework/platform/internal/relay 7.235s
ok github.com/carlosframework/platform/internal/release 24.829s
ok github.com/carlosframework/platform/internal/rollout 3.692s
ok github.com/carlosframework/platform/internal/rolloutwords 0.005s
ok github.com/carlosframework/platform/internal/rootaws 0.008s
ok github.com/carlosframework/platform/internal/rootparticipation 0.058s
ok github.com/carlosframework/platform/internal/rootstate 0.026s
ok github.com/carlosframework/platform/internal/runs 0.566s
ok github.com/carlosframework/platform/internal/s3compat 0.006s
ok github.com/carlosframework/platform/internal/safefile 0.004s
ok github.com/carlosframework/platform/internal/schedule 2.750s
ok github.com/carlosframework/platform/internal/seeds 0.010s
ok github.com/carlosframework/platform/internal/sim/engines 2.346s
ok github.com/carlosframework/platform/internal/sim/hostlife 9.475s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 3.667s
ok github.com/carlosframework/platform/internal/status 0.073s
ok github.com/carlosframework/platform/internal/steering 0.009s
ok github.com/carlosframework/platform/internal/stopevidence 0.234s
ok github.com/carlosframework/platform/internal/svcrole 0.002s
ok github.com/carlosframework/platform/internal/telemetry 0.004s
ok github.com/carlosframework/platform/internal/termfence 0.004s
ok github.com/carlosframework/platform/internal/tunnelclient 0.004s
ok github.com/carlosframework/platform/internal/unixdial 0.003s
ok github.com/carlosframework/platform/internal/updatewords 0.008s
ok github.com/carlosframework/platform/internal/usage 0.010s
ok github.com/carlosframework/platform/internal/version 0.003s
ok github.com/carlosframework/platform/internal/vet 1.642s
FAIL
=== internal_console@0 (85 s)
ok github.com/carlosframework/platform/internal/console 83.382s
=== internal_console@1 (40 s)
ok github.com/carlosframework/platform/internal/console 38.690s
=== internal_console@2 (39 s)
ok github.com/carlosframework/platform/internal/console 37.365s
=== internal_console@3 (44 s)
ok github.com/carlosframework/platform/internal/console 42.181s
=== internal_console@4 (44 s)
ok github.com/carlosframework/platform/internal/console 42.334s
=== internal_console@5 (43 s)
ok github.com/carlosframework/platform/internal/console 40.804s
=== internal_console@6 (41 s)
ok github.com/carlosframework/platform/internal/console 38.976s
=== internal_console@7 (44 s)
ok github.com/carlosframework/platform/internal/console 42.234s
=== root@0 (110 s)
ok github.com/carlosframework/platform 107.830s
=== root@1 (84 s)
ok github.com/carlosframework/platform 82.536s
=== root@2 (91 s)
ok github.com/carlosframework/platform 89.575s
FAILED: rest
make: *** [Makefile:19: test] Error 1
amadan: step gate failed: exit status 2
amadan: job failed at step gate — its output is above, not at the tail of this log
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| new file mode 100644 |
| index 000000000..1e34fa091 |
| --- /dev/null |
| +++ b/docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md |
| @@ -0,0 +1,45 @@ |
| +# Census approval: design-edge-rate-limit-358 |
| + |
| +Ruling `census-ruling-design-edge-rate-limit-358`. Every change below keeps the disposition it already has, so it needs an approval, not a decision. |
| + |
| +| unit | change | read sites | what changed | |
| +|---|---|---|---| |
| +| `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/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 | |
| +| `internal/registry/registry.go` `Registry.Upsert` | body | unchanged (9) | 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 | |
| +| `internal/registry/registry.go` `Registry.migrate` | body | unchanged (16) | 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 | |
| +| `internal/edge/edge.go` `Edge.Reload` | sites | +whole:Route | 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 | |
| + |
| +Envelopes re-pinned: `.`, `internal/console`, `internal/console/templates`, `internal/edge`, `internal/host`, `internal/plans`, `internal/provision`, `internal/ratelimit`, `internal/registry`, `internal/usage`. |
| + |
| +Seal: `73889e6d4061935be9f6354c2ff13817730be33b8b656b155d65048b134fb3c9` → `01b8594b68fcd345ff65131f7d574a666b6c5a0b25c7280fb26cb2549026eb22`. |
| + |
| +Overlay: `internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv`, appended to `internal/provision/testdata/plan14-root-reads-chain.tsv`. |
| + |
| +## Decisions (written by hand, not by census-propose) |
| + |
| +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 |
| +`945934f5…` → `73889e6d…` (eight frozen declarations added). 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. |
| + |
| +| # | unit | change | proposed disposition | why | |
| +|---|---|---|---|---| |
| +| D1 | `internal/edge/ratelimit.go` `Edge.rateAdmit` | new: +registry:Host, +registry:Kind, +whole:Route ×4 | legacy, accepted-legacy | The edge inside the agent (user carlos), serving only. It judges a request to an instance against the owner's settings, the plan ceiling hook and the in-memory limiter, and answers 429 when enforcing. Door callers, signed door hops and fleet-tunnel requests are never judged. It reads only the row's kind and host. Its neighbour Edge.ServeHTTP is accepted legacy. | |
| +| D2 | `internal/edge/ratelimit.go` `Edge.parseRateSettings` | new: +registry:Host ×2, +registry:RateLimit ×2 | legacy, accepted-legacy | The edge at Reload parses the row's rate_limit column. An unusable column falls back to the defaults and is logged, throttled. Its neighbour Edge.Reload is accepted legacy. | |
| +| D3 | `internal/edge/ratelimit.go` `Edge.noteRateLimited` | new: +registry:Host ×2, +whole:Route | legacy, accepted-legacy | The edge counts a refusal on the usage meter and logs it, throttled per host and reason. | |
| +| D4 | `internal/edge/usagemeter.go` `UsageMeter.RecordRateLimited` | new: +registry:App, +registry:Host ×2, +whole:Route | legacy, accepted-legacy | UsageMeter.Record's twin (accepted legacy, J1). It adds one to an in-memory refusal counter, keyed by host, with app and account. | |
| +| D5 | `internal/host/plans_pass.go` `planRateCeilingFor` | new: +whole:Route | legacy, accepted-legacy | planIdleFor's twin (accepted legacy). It reads the plans pass's in-memory cache for the row's account. A ceiling can only clamp what an owner's settings allow. | |
| +| D6 | `internal/registry/registry.go` `Registry.SetRateLimit` | new: +file:Exec, +registry:remote ×2, +registry:sql, +whole:remoteClient ×2 | legacy, accepted-legacy | SetGate's twin (accepted legacy, J1,J4). One UPDATE of routes.rate_limit by host. Its only caller is provision.Reconcile in the agent. No root pass calls it. | |
| +| D7 | `internal/provision/reconcile.go` `Reconcile` | reads: +registry:RateLimit ×3 | legacy, accepted-legacy (unchanged) | The agent's own pass converges rate_limit from the record beside the gate. The three sites are existing.RateLimit: one comparison and two log lines. | |
| +| D8 | `internal/registry/registry.go` `routeArgs` | reads: +registry:RateLimit | authority E3 (unchanged) | The bind list gains t.RateLimit. It binds the value and decides nothing. Same family as Registry.Upsert. | |
| +| D9 | `internal/registry/registry.go` `scanRoute` | reads: +registry:RateLimit | legacy, accepted-legacy (unchanged) | Scans the new column into Route.RateLimit. | |
| +| D10 | `internal/registry/remote_dispatch.go` `Registry.dispatchRemote` | reads: +registry:Host, +registry:RateLimit | hint E2 (unchanged) | The registry child serves one more method, SetRateLimit, as SetGate's case does. E2's ArtifactHosts read is unchanged. | |
| +| D11 | registry field list (`@fields`) | other: changed registry schema | add `RateLimit` | Route.RateLimit and remoteRequest.RateLimit. Its only readers are D2 and D7 to D10, all running as carlos (the agent, its edge and the registry child). No root unit reads it, so rate_limit is not a root input. | |
diff --git a/internal/provision/edge_rate_limit_census_test.go b/internal/provision/edge_rate_limit_census_test.go| new file mode 100644 |
| index 000000000..b2b8a5c12 |
| --- /dev/null |
| +++ b/internal/provision/edge_rate_limit_census_test.go |
| @@ -0,0 +1,63 @@ |
| +package provision |
| + |
| +// Record-write census entries for design-edge-rate-limit-358 (#358, the |
| +// per-instance edge rate limit), layered on dbRegionForward3WriteCensusInventory. |
| +// Reviewed by the branch author; the census owner rules on #280 |
| +// (census-ruling-design-edge-rate-limit-358, with the root-read card |
| +// docs/superpowers/notes/census-proposal-design-edge-rate-limit-358.md). |
| +// The record gains rate_limit; both doors that write it are the existing |
| +// typed path, one provision.UpdateRecord under the record's etag. No raw |
| +// record write is added. |
| +// - Server.handleAPIInstanceUpdate (the instance PATCH) gains a rate_limit |
| +// field: absent leaves the settings alone, {} clears them, anything else |
| +// replaces them whole. checkRateLimit (Validate, then the account plan's |
| +// ceiling) refuses before any write; the record still passes |
| +// ValidateShape and is written by the same UpdateRecord, and the audit |
| +// line names rate_limit. Still record-writer. |
| +// - Server.handleAppRateLimit is new: the Settings page's rate-limit form, |
| +// handleAppGate's twin (session, CSRF, ValidHostShape, GetRecordETag, |
| +// checkRateLimit, ValidateShape, then one UpdateRecord under the etag, |
| +// an audit row and bumpSerial). It sets the four numbers and keeps the |
| +// record's path rules, or clears the settings. record-writer, like the |
| +// gate's form. |
| +// - Server.registerCLIRoutes gains GET .../instances/{host}/rate-limit |
| +// (handleAPIInstanceRateLimitGet, svcrole Instance), a read that writes |
| +// nothing; its instance and sidecar literals are unchanged: key-site. |
| +// - NewServer registers POST /a/{sqid}/apps/{app}/ratelimit |
| +// (handleAppRateLimit) beside the gate's form; its instances literal is |
| +// unchanged: key-site. |
| +// - Reconcile converges a row's rate_limit column from its record |
| +// (Registry.SetRateLimit), a registry write, never a record write; its |
| +// record-key reads (RecordKey, ParseRecordKey) are unchanged: key-site. |
| +// - main dispatches the new `carlos ratelimit` verb (runRatelimit); its |
| +// instance and sidecar literals are unchanged: key-site. |
| +// - apiSession.instanceRateLimit and instanceSetRateLimit are new CLI |
| +// clients: they build the console's .../instances/<host> paths (a GET |
| +// 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. |
| +func edgeRateLimitWriteCensusInventory() []censusEntry { |
| + entries := append([]censusEntry(nil), dbRegionForward3WriteCensusInventory()...) |
| + replacements := []censusEntry{ |
| + {"internal/console/apiinstances.go", "Server.handleAPIInstanceUpdate", "record-writer", "key:UpdateRecord", "6a6979202eb5aba5edda74d60b8939a5db9dc815335221d70a323aed2dc42374"}, |
| + {"internal/console/appsettings.go", "Server.handleAppRateLimit", "record-writer", "key:UpdateRecord", "1da799b014d1e05cd045c8125552737c9a6d4b8cb2c19d9a4b81c4052db7a9cf"}, |
| + {"internal/console/authcli.go", "Server.registerCLIRoutes", "key-site", "lit:instances,lit:sidecars", "25eee4d30b4e036774dbb113fad8716787622731aef2b36c926676bd93666a9a"}, |
| + {"internal/console/server.go", "NewServer", "key-site", "lit:instances", "4343f2a14894c83e13d92b6d6355de37dac460f60e6e1c0695ea1cf6ed3546ad"}, |
| + {"internal/provision/reconcile.go", "Reconcile", "key-site", "key:ParseRecordKey,key:RecordKey,lit:instances", "5fd01d0295ed60c16c718c0825e0b4ce75d2e541ece2c40fcf07545c26bcc3b3"}, |
| + {"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"}, |
| + } |
| + for _, r := range replacements { |
| + found := false |
| + for i, e := range entries { |
| + if e.File == r.File && e.Unit == r.Unit { |
| + entries[i], found = r, true |
| + } |
| + } |
| + if !found { |
| + entries = append(entries, r) |
| + } |
| + } |
| + return entries |
| +} |
diff --git a/internal/provision/plan9_b8_census_test.go b/internal/provision/plan9_b8_census_test.go| index 525edfb2c..180079532 100644 |
| --- a/internal/provision/plan9_b8_census_test.go |
| +++ b/internal/provision/plan9_b8_census_test.go |
| @@ -366,7 +366,7 @@ func TestPlan9B8RecordWriteCensus(t *testing.T) { |
| if len(got) < 100 { |
| t.Fatalf("census found only %d units under %s; the walk is broken", len(got), root) |
| } |
| - inventory := dbRegionForward3WriteCensusInventory() |
| + inventory := edgeRateLimitWriteCensusInventory() |
| problems := append(censusDiff(inventory, got), censusPolicy(inventory)...) |
| if len(problems) > 0 { |
| t.Fatalf("record-write census rejected %d site(s); update the explicit inventory only after reviewing the source:\n %s", len(problems), strings.Join(problems, "\n ")) |
diff --git a/internal/provision/testdata/plan14-root-reads-chain.tsv b/internal/provision/testdata/plan14-root-reads-chain.tsv| index a67ca45fd..1f1019a22 100644 |
| --- a/internal/provision/testdata/plan14-root-reads-chain.tsv |
| +++ b/internal/provision/testdata/plan14-root-reads-chain.tsv |
| @@ -3,3 +3,5 @@ |
| # make census-propose appends here; nothing else edits this file. |
| plan14-root-reads-sec-host-imdsv2-module.tsv 945934f5978ace14dc5a9bae0ed69dfabf29b994504fc843c03d4a633ecd6c6a |
| plan14-root-reads-sec-deps-dos-bumps.tsv 945934f5978ace14dc5a9bae0ed69dfabf29b994504fc843c03d4a633ecd6c6a |
| +plan14-root-reads-design-edge-rate-limit-358-decisions.tsv 73889e6d4061935be9f6354c2ff13817730be33b8b656b155d65048b134fb3c9 |
| +plan14-root-reads-design-edge-rate-limit-358.tsv 01b8594b68fcd345ff65131f7d574a666b6c5a0b25c7280fb26cb2549026eb22 |
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| new file mode 100644 |
| index 000000000..a0415cd86 |
| --- /dev/null |
| +++ b/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358-decisions.tsv |
| @@ -0,0 +1,22 @@ |
| +# Census overlay design-edge-rate-limit-358-decisions (#358, the per-instance edge rate limit), loaded through plan14-root-reads-chain.tsv after sec-deps-dos-bumps 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; sec-deps-dos-bumps' seal is checked first. |
| +@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 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/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 |
| +internal/registry/registry.go routeArgs 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), wherever a route is inserted: Upsert, the cold handover restore and the import journal's inserts: the bind list from Registry.Upsert's body (and RestoreClaimRows'), with seed_source and import_gate added; E3, the same family as Registry.Upsert, whose body it came from;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), wherever a route is inserted: the bind list gains t.RateLimit for the new rate_limit column (routeCols and Upsert's conflict clause gain it too); the new kind is registry:RateLimit, one site; it binds the value and decides nothing; E3, as before registry:Account@355,registry:Addr@83,registry:Addrs@451,registry:App@152,registry:Args@505,registry:Backing@253,registry:BuildState@730,registry:Canary@216,registry:Caps@381,registry:CertExpiresAt@338,registry:Channel@177,registry:ClaimIncarnation@577,registry:ClaimOwner@611,registry:ClaimRowID@625,registry:ClaimStamp@597,registry:CreatedAt@492,registry:DBPath@116,registry:DNSCheckedAt@320,registry:DNSStatus@307,registry:Environment@366,registry:FleetBox@439,registry:Gate@484,registry:GoodDemand@680,registry:GoodDigest@666,registry:GoodVersion@651,registry:Health@460,registry:Hibernate@196,registry:HoldOp@639,registry:Host@49,registry:IdleSeconds@513,registry:ImportGate@760,registry:Kind@65,registry:LastError@101,registry:MaxRunSeconds@528,registry:NextDue@242,registry:Platform@294,registry:Pool@159,registry:PrevVersion@137,registry:Provisioned@407,registry:RateLimit@774,registry:Region@167,registry:Replica@565,registry:Replicas@547,registry:Replication@227,registry:Seed@423,registry:SeedSource@746,registry:ServingVersion@694,registry:Slug@57,registry:Socket@73,registry:Status@91,registry:StatusNamed@272,registry:Steering@472,registry:Tunnel@389,registry:Unit@431,registry:UpdateSettings@712,registry:Version@126 34fda138981eb9a22754ffc801a1fd6d20f27ece1f42f2f3b11864e4ae00be38 |
| +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/registry/remote_dispatch.go Registry.dispatchRemote hint E2 Mixed declaration: E2 adds only the ArtifactHosts read operation; all existing dispatch and write behavior stays legacy. Original immutable legacy fingerprints retained. E32: census-only E2 completeness discovers the bounded union of route and timer hosts, including inactive orphan timers, through the service-user read-only parser. Unknown hosts refuse even with an empty root installation list; discovery supplies no authority and never removes a retained obligation. Pre-flight 33, 80, 82, 83, 89 and 90. Fixtures: TestArtifactHosts, TestRemoteReadOnlyWALRegistry, TestPlan14GenerationRegistryRows, TestPlan14GenerationRegistryProductionReader; extended TestPlan14GenerationRequiredArtifactsRootRunner remains runner-pending. PROPOSED E45: service registry child executes explicit timer row materialization/removal; service-writable SQL is deny-only to root and cannot confer ownership. Root lifecycle producer wiring is pending.;rev3=census-ruling-design-edge-rate-limit-358;basis=the registry child (carlos __registry-child, which a root pass forks as the service user carlos): one more method served, SetRateLimit, passing q.Host and q.RateLimit to Registry.SetRateLimit as SetGate's case does; the new kind is registry:RateLimit and one more registry:Host site, both that case's; E2's ArtifactHosts read and every other method are unchanged registry:A@6393,registry:Account@3790,registry:Accounts@2803,registry:Addr@4367,registry:Addrs@4375,registry:Alias@6441,registry:Alias@6505,registry:Alias@6593,registry:Aliases@6315,registry:Alive@8135,registry:Args@6017,registry:At@5458,registry:At@6524,registry:At@6602,registry:At@7883,registry:Attempts@7905,registry:B@2188,registry:Backing@4186,registry:BuildState@4593,registry:Changed@1996,registry:Changed@3159,registry:Changed@3246,registry:Changed@3335,registry:Changed@3406,registry:Changed@3488,registry:Changed@7815,registry:Channel@3850,registry:Channel@4899,registry:Channel@5303,registry:CheckedAt@5384,registry:Class@4305,registry:DoneBefore@8144,registry:Due@5787,registry:Due@5851,registry:Due@7927,registry:Env@4967,registry:Env@5214,registry:Env@5314,registry:ExcludeHosts@7610,registry:ExcludeHosts@7705,registry:ExpectGood@5583,registry:ExpectOp@3214,registry:Expected@1250,registry:Expected@289,registry:Expected@762,registry:Expected@939,registry:F@1968,registry:F@2029,registry:Fleet@2054,registry:Fleet@2246,registry:Fleet@2328,registry:Fleet@2409,registry:Fleet@2502,registry:FleetBoxes@2463,registry:Fleets@2112,registry:From@3961,registry:From@4022,registry:FromDB@4097,registry:FromOp@3302,registry:FromSock@4107,registry:Hash@4773,registry:Health@4384,registry:Host@1024,registry:Host@1135,registry:Host@272,registry:Host@2987,registry:Host@3028,registry:Host@3114,registry:Host@3190,registry:Host@3276,registry:Host@3368,registry:Host@3440,registry:Host@3532,registry:Host@3782,registry:Host@3842,registry:Host@3900,registry:Host@3953,registry:Host@4014,registry:Host@4089,registry:Host@4178,registry:Host@4232,registry:Host@4297,registry:Host@4359,registry:Host@4437,registry:Host@4512,registry:Host@4585,registry:Host@4650,registry:Host@4711,registry:Host@4765,registry:Host@4826,registry:Host@4959,registry:Host@5013,registry:Host@5074,registry:Host@5136,registry:Host@5366,registry:Host@5450,registry:Host@5507,registry:Host@5575,registry:Host@5664,registry:Host@5724,registry:Host@5779,registry:Host@5843,registry:Host@5958,registry:Host@6009,registry:Host@6076,registry:Host@6151,registry:Host@6214,registry:Host@6811,registry:Host@6958,registry:Host@7246,registry:Host@7310,registry:Host@7369,registry:Host@7452,registry:Host@7535,registry:Host@7766,registry:Host@7851,registry:Host@7983,registry:Host@8064,registry:Host@8227,registry:Hosts@187,registry:Hosts@2866,registry:Hosts@4890,registry:Hosts@5205,registry:Hosts@5294,registry:Id@1244,registry:Id@1555,registry:Id@1654,registry:Id@1734,registry:Id@1885,registry:IdValue@2622,registry:Idle@6084,registry:Journal@1262,registry:Journal@1561,registry:Journal@1740,registry:Journal@442,registry:Keep@8243,registry:Kind@8072,registry:Kind@8235,registry:Label@2255,registry:Label@2337,registry:Label@2418,registry:Label@5082,registry:Limit@7601,registry:Limit@7696,registry:MaxRun@6092,registry:Method@151,registry:Ms@7899,registry:Name@1032,registry:Name@1143,registry:Name@2082,registry:Name@2641,registry:Name@7318,registry:Name@7377,registry:Name@7460,registry:Name@7774,registry:Name@7859,registry:Name@7991,registry:Next@301,registry:NextAt@7917,registry:NextGood@5597,registry:NextValue@1814,registry:NextValue@1912,registry:Now@1167,registry:Now@6285,registry:Now@7594,registry:Now@7689,registry:Now@7782,registry:Number64@2729,registry:Number@8032,registry:Number@8103,registry:Number@8188,registry:Observed@365,registry:ObservedValue@643,registry:Old@1807,registry:Old@1905,registry:On@5732,registry:On@6159,registry:On@6222,registry:Op@3132,registry:Op@3208,registry:Op@3376,registry:Op@3448,registry:Op@3540,registry:Owner@280,registry:Owner@377,registry:Owner@660,registry:P@6912,registry:Path@7143,registry:Paths@6840,registry:Prefix@6966,registry:Prev@5522,registry:RateLimit@4834,registry:Registration@1040,registry:Registration@1151,registry:Registration@7468,registry:Registration@7867,registry:Replica@4719,registry:Replicas@4658,registry:Retirement@1891,registry:Route@2964,registry:Routes@2922,registry:Routes@3566,registry:Routes@5885,registry:Routes@6252,registry:Rows@7254,registry:Seed@5966,registry:Sqid@2633,registry:Sqid@2696,registry:Sqid@2775,registry:Status@1056,registry:Status@2427,registry:Status@3122,registry:Status@3198,registry:Status@3284,registry:Status@3908,registry:Status@5374,registry:Status@6514,registry:Status@7889,registry:Status@7999,registry:Steering@4445,registry:StringMap@2539,registry:T@7194,registry:T@757,registry:T@851,registry:T@934,registry:TValue@3069,registry:Tags@2346,registry:Target@5144,registry:Targets@453,registry:Text@1460,registry:Text@1607,registry:Text@2743,registry:Text@6999,registry:Text@7062,registry:Timer@709,registry:Timer@7282,registry:Timer@891,registry:Timers@7505,registry:Timers@7564,registry:Timers@7653,registry:Times@8277,registry:To@3969,registry:To@4030,registry:ToDB@4119,registry:ToOp@3294,registry:ToSock@4127,registry:TokenHash@2264,registry:Tunnel@5021,registry:Unit@4240,registry:UpdateSettings@4520,registry:Ver@5515,registry:Ver@5672,registry:W@6745,registry:Wildcards@6639,whole:Account@2807,whole:ClaimOwnership@282,whole:ClaimOwnership@379,whole:ClaimOwnership@662,whole:ClaimRow@455,whole:ClaimRowArchive@561,whole:ClaimRowArchive@571,whole:ColdRows@1809,whole:ColdRows@1816,whole:ColdRows@1907,whole:ColdRows@1914,whole:Fleet@1970,whole:Fleet@2031,whole:Fleet@2058,whole:Fleet@2116,whole:FleetBox@2190,whole:FleetBox@2467,whole:GoodBuild@5585,whole:GoodBuild@5599,whole:Route@2926,whole:Route@2968,whole:Route@3071,whole:Route@3570,whole:Route@367,whole:Route@3725,whole:Route@3731,whole:Route@5889,whole:Route@6256,whole:RouteAlias@6319,whole:RouteAlias@6395,whole:RoutePath@6844,whole:RoutePath@6914,whole:Timer@645,whole:Timer@713,whole:Timer@7196,whole:Timer@7256,whole:Timer@7286,whole:Timer@7509,whole:Timer@7568,whole:Timer@759,whole:Timer@7657,whole:Timer@853,whole:Timer@895,whole:Timer@936,whole:WildcardDomain@6643,whole:WildcardDomain@6747 077a11814c4030c5c456559fa9755769831f5ceb04c9f3a7f369e9050c3e0a9a |
| +@fields A,Account,Accounts,AddedAt,Addr,Addrs,Alias,Aliases,Alive,AllowAbsent,App,Archives,Args,At,Attempts,B,Backing,Bucket,BuildState,Callback,CallbackError,CallbackFailed,Canary,Caps,CertExpiresAt,Changed,Channel,CheckedAt,ClaimIncarnation,ClaimOwner,ClaimOwnership,ClaimRowID,ClaimStamp,Class,Contents,CreatedAt,DBPath,DNSCheckedAt,DNSStatus,Deadline,Demand,Digest,DoneBefore,Due,DueAt,Env,EnvBefore,Environment,Error,ErrorKind,ExcludeHosts,ExpectGood,ExpectOp,Expected,F,Failed,FenceGen,Fleet,FleetBox,FleetBoxes,Fleets,From,FromDB,FromOp,FromSock,Gate,GoodDemand,GoodDigest,GoodVersion,Hash,Health,Held,Hibernate,HoldOp,Host,Hosts,ID,Id,IdValue,Idle,IdleSeconds,ImportGate,Journal,Keep,Kind,Label,LastAt,LastError,LastMs,LastStatus,Limit,MaxRun,MaxRunSeconds,Method,Ms,Name,Next,NextAt,NextDue,NextGood,NextValue,Now,Number,Number64,Observed,ObservedValue,Old,On,Op,Original,Owner,Ownership,P,Path,Paths,Platform,Pool,Prefix,Prev,PrevVersion,Provisioned,RateLimit,RecordKey,Region,Registration,Replica,Replicas,Replication,Retirement,Route,Routes,Row,Rows,Seed,SeedID,SeedSource,ServingVersion,Slug,Socket,Spec,Sqid,State,Status,StatusNamed,Steering,StringMap,T,TValue,Tags,Target,Targets,Text,Timer,Timers,Times,To,ToDB,ToOp,ToSock,TokenHash,Tunnel,Unit,UpdateSettings,Ver,Version,W,WakeIncarnation,Wildcards,closed,conn,connect,ctx,d,dec,done,enc,full,input,mu,output,path,remote,sql,wait |
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| new file mode 100644 |
| index 000000000..2b26b7167 |
| --- /dev/null |
| +++ b/internal/provision/testdata/plan14-root-reads-design-edge-rate-limit-358.tsv |
| @@ -0,0 +1,27 @@ |
| +# 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. |
| +@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 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/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 . 3c0f54a5c3a4e3b067990d9de1a23e39580d933c56e18ed573c97c05109bf9e1 |
| +@coverage internal/console d9b95bfb84942ea3bb99e5429744f3b7ec5efe6f4f1bee78a50d381e7b6d1884 |
| +@coverage internal/console/templates 751977f38182d3f85da414ce14ef3bfb985f669c68b88872fd80756e59c8e228 |
| +@coverage internal/edge 3e20595cb0e7470eb0803d69845028e1377551746000b2b6fe4416a10e32f217 |
| +@coverage internal/host 369816074496f6ca280fd41bf35f9f131b6d5e00ff95420aa4787f8ebfeb5d00 |
| +@coverage internal/plans 239eda11f74ab55ab8cf122e0007c1e71a48582c6759c2f999dd8f952d73b85c |
| +@coverage internal/provision 4ebd69441cac610bfbd386439f78d3b86ec0d7d4a1a09d6e4e826babd609da00 |
| +@coverage internal/ratelimit af90b95e13a5234c92e9d0bba18507a40116f05615cdc01f1db595c3ecd69bdb |
| +@coverage internal/registry a5d78e9d8dc69a497941817cff1e2b423917265332ec9f2f7d8eed00a44ffaa2 |
| +@coverage internal/usage abff13ddd6cc3cfa90b33af54166be798586cf356d5ff1ac25677b41e8f4e6ef |