| 1 | # Census: db region forward, plan 2 (the console and CLI for `carlos db query` and `query --at`) |
| 2 | |
| 3 | Status: ACCEPTED in full by the census owner on #280, 2026-10-22, as |
| 4 | `census-ruling-db-region-forward-2`. Every row now carries |
| 5 | `rev3=census-ruling-db-region-forward-2`. The ruling covers the |
| 6 | `dbQueryForward` CLI read (J4) and the `readDBReadBody` console read added in |
| 7 | Astra's round 1; the re-frozen `serve`, `NewServer`, `doorError` and |
| 8 | deployment-buckets module rows; the new 9B8 create sites and the re-digested |
| 9 | ones; the claim-routes.txt line; and the overlay's order after |
| 10 | `s3-change-index`. |
| 11 | |
| 12 | The census owner's rationale: the console never reads another region's |
| 13 | bucket, the CLI reads only its own response, and Astra independently matched |
| 14 | every hash. |
| 15 | |
| 16 | The branch is `db-region-forward-2`, cut from amadan `main` at 13e2f75f |
| 17 | (plan 1, cd55508a, plus its nudge-flake fix). It builds plan 2 of |
| 18 | `docs/superpowers/specs/2026-10-22-db-region-forward-design.md` (rev 6): |
| 19 | the list door's forward marker, the one reads route |
| 20 | (`POST /api/cli/apps/{account}/{app}/db/{host}/reads`) with its admission |
| 21 | and its streamed relay of the box's sealed answer, `CARLOS_DB_FORWARD`, |
| 22 | `console.NewHTTPServer`, the CLI's buffered forwarded query, and the |
| 23 | `db-reads/` lifecycle rule in the `deployment-buckets` module (prepared, not |
| 24 | applied). A console with `CARLOS_DB_FORWARD` unset answers byte-identically |
| 25 | to main. |
| 26 | |
| 27 | It adds one root-read overlay, |
| 28 | `internal/provision/testdata/plan14-root-reads-db-region-forward-2.tsv`, |
| 29 | loaded last in `TestPlan14RootReadCensus`, after `s3-change-index` (the |
| 30 | overlay main loads last at 26fbd042, merged into the branch). Its record-write entries are layered |
| 31 | on `s3ChangeIndexWriteCensusInventory` in |
| 32 | `internal/provision/db_region_forward_2_census_test.go`. |
| 33 | |
| 34 | ## Root reads |
| 35 | |
| 36 | Executing identities, named once: |
| 37 | |
| 38 | - **the console**: `cmd/console serve` under `console.service`, user |
| 39 | `carlos-console`. The root carlos binary does not link `internal/console`. |
| 40 | - **the CLI**: `carlos db query` on a person's machine, as the person. |
| 41 | |
| 42 | The scanner names fewer units than the plan listed. The reads route's own |
| 43 | units (`handleAPIDBRead`, `admitDBRead`, `streamDBRead`, `dbLineWriter`, |
| 44 | `dbfCall`, `readDBResult`, `cancelDBRead`, `announceDBRead`, `dbResidency`, |
| 45 | `dbForwardEvidence`) and `NewHTTPServer` make no read the scanner counts |
| 46 | (their store calls are `release.Store` methods, the record-write census's |
| 47 | business), so they have no rows: an inventory row with no scanned read is |
| 48 | stale. Plan 1's census found the same (its ruling R8). |
| 49 | |
| 50 | | unit | change | executing identity | proposed disposition | |
| 51 | |---|---|---|---| |
| 52 | | `dbforward.go` `dbQueryForward` | new: reads at most 64 KiB of a refused reads-route answer (`io.ReadAll` over the HTTP response body, not a file) to print the console's sentence | the CLI | legacy, accepted-legacy, J4 (`basis=root-input`, main's footing for `db.go`'s units) | |
| 53 | | `internal/console/apidbforward.go` `readDBReadBody` | new (Astra round 1, P1): reads the request body to EOF, at most 264 KiB (`io.ReadAll` over `http.MaxBytesReader`, not a file), under the admission read deadline, then requires exactly one JSON value | the console | legacy, accepted-legacy, J4 (`root-input`, as main's console request-body reads) | |
| 54 | | `cmd/console/main.go` `serve` | changed: parses `CARLOS_DB_FORWARD` into `Config.DBForward`; builds its `http.Server` with `console.NewHTTPServer` (the same two timeouts). The same three `/data` literals at the same offsets | the console | re-frozen at main's disposition (`PROPOSED-scan-demand-revival`, `PROPOSED-email-signin`, `PROPOSED-s3-change-index`) with this change appended | |
| 55 | | `internal/console/server.go` `NewServer` | changed: sets the forwarded read's open-read limits (`dbReads`) and timing (`dbf`); no goroutine, no store call. The one data-literal is the logs/data route pattern, moved | the console | re-frozen at main's disposition with this change appended | |
| 56 | | `internal/dbdoor/client.go` `doorError` | changed: decodes the forward marker's three additive fields beside `error`, from the same bounded 64 KiB read | the CLI | re-frozen at main's `J4` `root-input` with this change appended | |
| 57 | | `infra/modules/deployment-buckets/main.tf` `external` | changed: the two `db-reads/` lifecycle rules beside `geoip-noncurrent` | an external unit (OpenTofu, applied only on Paul's approval of `docs/superpowers/notes/db-reads-lifecycle-approval.md`) | re-frozen at main's `J4` `root-input` with this change appended | |
| 58 | |
| 59 | Envelopes re-pinned: `.`, `cmd/console`, `infra/modules/deployment-buckets`, |
| 60 | `internal/console`, `internal/dbdoor`, `internal/dbreads`, `internal/release`. |
| 61 | |
| 62 | Seal: `e7c6062c0e1d29833edda7bd9953282a52edbb45ddbe3cd00a447ec5d61d9b8a` |
| 63 | (s3-change-index, checked first) to |
| 64 | `bd4cc1909225cd574c2c609f0cd02177076ddb5c1476d9cf5e178be05acccae1` (after Astra round 1, main's merge and the ruling's markers). |
| 65 | |
| 66 | ## Record writes (9B8) |
| 67 | |
| 68 | | site | class | why | |
| 69 | |---|---|---| |
| 70 | | `internal/console/authcli.go` `Server.registerCLIRoutes` | key-site, re-digested | one more route line: the reads route | |
| 71 | | `internal/console/server.go` `NewServer` | key-site, re-digested | the read limits and timing set beside the db door's | |
| 72 | | `internal/console/apidbforward.go` `Server.admitDBRead` | nonrecord, new | `request.json` and the queue entry: conditional creates under `db-reads/` in the deployment bucket | |
| 73 | | `internal/release/serial.go` `BumpSerial` | nonrecord, re-digested | checks its context before every write of `control/serial`, retries included (Astra round 1, P2) | |
| 74 | | `internal/console/apidbforward.go` `Server.cancelDBRead` | nonrecord, new | `cancel`: a conditional create under `db-reads/` | |
| 75 | |
| 76 | No record writer is added and there is no `Delete` site. The serial bump in |
| 77 | `announceDBRead` goes through `release.BumpSerial`. |
| 78 | |
| 79 | ## Claim routes |
| 80 | |
| 81 | `route POST /api/cli/apps/{account}/{app}/db/{host}/reads` joins |
| 82 | `internal/console/testdata/claim-routes.txt`. The claim invariant census |
| 83 | gets it as a refused fixture: a host-claim console never signs a forwarded |
| 84 | read (`dbForwardSigner`), so the route reads the record and answers main's |
| 85 | residency sentence, writing nothing (spec §6, §9.1). Its message is in |
| 86 | `claimUnsupported` with that reason. |
| 87 | |
| 88 | ## go.mod |
| 89 | |
| 90 | Unchanged. |
| 91 | |