census-astra-approvals
Squashed from census-astra-approvals into main.
3 files changed,
+66
−15
AGENTS.md+33 −9internal/provision/census_propose_internal_test.go+12 −1internal/provision/census_propose_test.go+21 −5
CI passed — run details
CI log
=== gate ===
.amadan/test-gate.sh
=== launchctx (1 s)
ok amadan.net/carlos/platform.git/launchctx 0.013s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
=== vet (20 s)
=== gofmt (1 s)
gofmt -l .: clean
=== rest (72 s)
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 4.138s
ok github.com/carlosframework/platform/cmd/moveprobe 11.869s
ok github.com/carlosframework/platform/cmd/zddprobe 0.817s
ok github.com/carlosframework/platform/internal/activator 58.229s
ok github.com/carlosframework/platform/internal/agentsock 0.021s
ok github.com/carlosframework/platform/internal/alerting 0.007s
ok github.com/carlosframework/platform/internal/analytics 0.022s
ok github.com/carlosframework/platform/internal/appconfig 2.943s
ok github.com/carlosframework/platform/internal/apperr 0.159s
ok github.com/carlosframework/platform/internal/applog 0.209s
ok github.com/carlosframework/platform/internal/assetcache 0.145s
ok github.com/carlosframework/platform/internal/awsinv 0.007s
ok github.com/carlosframework/platform/internal/boxchoice 0.010s
ok github.com/carlosframework/platform/internal/boxid 1.103s
? 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.011s
ok github.com/carlosframework/platform/internal/caps 0.019s
ok github.com/carlosframework/platform/internal/certwarm 0.004s
ok github.com/carlosframework/platform/internal/cgroup 0.845s
ok github.com/carlosframework/platform/internal/changelog 0.536s
ok github.com/carlosframework/platform/internal/claimactivation 1.441s
ok github.com/carlosframework/platform/internal/clamd 0.060s
? 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 7.714s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.013s
ok github.com/carlosframework/platform/internal/dbquery 0.008s
ok github.com/carlosframework/platform/internal/dbreads 2.191s
? github.com/carlosframework/platform/internal/dbreads/dbreadstest [no test files]
ok github.com/carlosframework/platform/internal/dbverify 0.006s
ok github.com/carlosframework/platform/internal/dnsrec 0.008s
ok github.com/carlosframework/platform/internal/docsite 0.011s
ok github.com/carlosframework/platform/internal/domains 3.416s
ok github.com/carlosframework/platform/internal/doorkey 0.014s
ok github.com/carlosframework/platform/internal/economics 0.005s
ok github.com/carlosframework/platform/internal/edge 45.316s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.015s
ok github.com/carlosframework/platform/internal/fleetapi 0.186s
ok github.com/carlosframework/platform/internal/gate 1.658s
ok github.com/carlosframework/platform/internal/genselect 0.023s
ok github.com/carlosframework/platform/internal/geo 0.015s
ok github.com/carlosframework/platform/internal/geoip 0.044s
ok github.com/carlosframework/platform/internal/historyreadback 0.235s
ok github.com/carlosframework/platform/internal/hostactors 6.470s
ok github.com/carlosframework/platform/internal/hostactors/awsmembership 0.015s
ok github.com/carlosframework/platform/internal/hostbox 2.992s
ok github.com/carlosframework/platform/internal/hostclaim 0.700s
ok github.com/carlosframework/platform/internal/hostenv 0.015s
ok github.com/carlosframework/platform/internal/hostevidence 0.015s
ok github.com/carlosframework/platform/internal/hostexec 5.322s
ok github.com/carlosframework/platform/internal/hostfence 0.037s
ok github.com/carlosframework/platform/internal/hostfiles 10.623s
ok github.com/carlosframework/platform/internal/hostfloor 0.020s
ok github.com/carlosframework/platform/internal/hostguard 1.100s
ok github.com/carlosframework/platform/internal/hostops 1.838s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.015s
ok github.com/carlosframework/platform/internal/hostquarantine 0.017s
ok github.com/carlosframework/platform/internal/hostrelocate 0.546s
ok github.com/carlosframework/platform/internal/hostresolve 0.202s
ok github.com/carlosframework/platform/internal/hostwrite 0.004s
ok github.com/carlosframework/platform/internal/infraview 0.004s
ok github.com/carlosframework/platform/internal/instancectl 5.236s
ok github.com/carlosframework/platform/internal/instanceexec 2.785s
ok github.com/carlosframework/platform/internal/instancefs 0.008s
ok github.com/carlosframework/platform/internal/instancekey 0.008s
ok github.com/carlosframework/platform/internal/instanceupdates 0.008s
ok github.com/carlosframework/platform/internal/layout 1.678s
ok github.com/carlosframework/platform/internal/lbhealth 0.006s
ok github.com/carlosframework/platform/internal/lease 10.160s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.494s
ok github.com/carlosframework/platform/internal/ledger 0.019s
ok github.com/carlosframework/platform/internal/mail 0.214s
ok github.com/carlosframework/platform/internal/maintenance 0.128s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.569s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.107s
ok github.com/carlosframework/platform/internal/metrics 0.007s
ok github.com/carlosframework/platform/internal/moves 24.020s
ok github.com/carlosframework/platform/internal/moves/archive 0.888s
ok github.com/carlosframework/platform/internal/objstore 0.237s
ok github.com/carlosframework/platform/internal/ops 0.189s
ok github.com/carlosframework/platform/internal/park 0.228s
ok github.com/carlosframework/platform/internal/plans 0.012s
ok github.com/carlosframework/platform/internal/privatefile 0.005s
ok github.com/carlosframework/platform/internal/provision 26.344s
ok github.com/carlosframework/platform/internal/publicrelease 0.011s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 5.611s
ok github.com/carlosframework/platform/internal/relay 7.238s
ok github.com/carlosframework/platform/internal/release 26.566s
ok github.com/carlosframework/platform/internal/rollout 3.859s
ok github.com/carlosframework/platform/internal/rolloutwords 0.006s
ok github.com/carlosframework/platform/internal/rootaws 0.007s
ok github.com/carlosframework/platform/internal/rootparticipation 0.060s
ok github.com/carlosframework/platform/internal/rootstate 0.026s
ok github.com/carlosframework/platform/internal/runs 0.581s
ok github.com/carlosframework/platform/internal/s3compat 0.005s
ok github.com/carlosframework/platform/internal/safefile 0.004s
ok github.com/carlosframework/platform/internal/schedule 2.673s
ok github.com/carlosframework/platform/internal/seeds 0.011s
ok github.com/carlosframework/platform/internal/sim/engines 2.188s
ok github.com/carlosframework/platform/internal/sim/hostlife 10.946s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 3.609s
ok github.com/carlosframework/platform/internal/status 0.085s
ok github.com/carlosframework/platform/internal/steering 0.007s
ok github.com/carlosframework/platform/internal/stopevidence 0.143s
ok github.com/carlosframework/platform/internal/svcrole 0.003s
ok github.com/carlosframework/platform/internal/telemetry 0.005s
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.004s
ok github.com/carlosframework/platform/internal/updatewords 0.005s
ok github.com/carlosframework/platform/internal/usage 0.009s
ok github.com/carlosframework/platform/internal/version 0.004s
ok github.com/carlosframework/platform/internal/vet 1.608s
=== internal_console@0 (73 s)
ok github.com/carlosframework/platform/internal/console 70.594s
=== internal_console@1 (47 s)
ok github.com/carlosframework/platform/internal/console 45.539s
=== internal_console@2 (43 s)
ok github.com/carlosframework/platform/internal/console 41.362s
=== internal_console@3 (47 s)
ok github.com/carlosframework/platform/internal/console 45.407s
=== internal_console@4 (44 s)
ok github.com/carlosframework/platform/internal/console 42.077s
=== internal_console@5 (49 s)
ok github.com/carlosframework/platform/internal/console 46.667s
=== internal_console@6 (47 s)
ok github.com/carlosframework/platform/internal/console 45.376s
=== internal_console@7 (50 s)
ok github.com/carlosframework/platform/internal/console 48.482s
=== internal_host@0 (66 s)
ok github.com/carlosframework/platform/internal/host 63.077s
=== internal_host@1 (33 s)
ok github.com/carlosframework/platform/internal/host 30.595s
=== internal_host@2 (32 s)
ok github.com/carlosframework/platform/internal/host 29.493s
=== internal_host@3 (31 s)
ok github.com/carlosframework/platform/internal/host 29.443s
=== root@0 (71 s)
ok github.com/carlosframework/platform 68.996s
=== root@1 (49 s)
ok github.com/carlosframework/platform 47.283s
=== root@2 (61 s)
ok github.com/carlosframework/platform 59.109s
=== root@3 (53 s)
ok github.com/carlosframework/platform 50.821s
=== root@4 (59 s)
ok github.com/carlosframework/platform 56.828s
=== cross ===
--- shard 0 of 5 ---
cross-compiling darwin/arm64
--- shard 1 of 5 ---
cross-compiling darwin/amd64
--- shard 2 of 5 ---
cross-compiling linux/arm64
linux/arm64 carlos binary: 50659490 bytes (ceiling 52000000)
--- shard 3 of 5 ---
cross-compiling windows/amd64
--- shard 4 of 5 ---
cross-compiling windows/arm64
=== minio-contract ===
minio contract: arm64, minio RELEASE.2025-09-07T16-13-09Z, mc RELEASE.2025-08-13T08-35-41Z
minio: 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.024s
=== RUN TestT4StorageProbeMinio
2026/10/25 08:56:42 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18E1B9F829ABA685, HostID: 7c420053e0fbcd7f41653fdd92ffa2802c903d05303b1aa15adc2e8bb65d183f, api error SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
--- PASS: TestT4StorageProbeMinio (0.01s)
PASS
ok github.com/carlosframework/platform/internal/host 0.022s
=== RUN TestS3StoreMinioContract
=== RUN TestS3StoreMinioContract/conditional_get_and_etag_listing
=== RUN TestS3StoreMinioContract/bump_through_every_mutation_path
--- PASS: TestS3StoreMinioContract (0.03s)
--- PASS: TestS3StoreMinioContract/conditional_get_and_etag_listing (0.01s)
--- PASS: TestS3StoreMinioContract/bump_through_every_mutation_path (0.02s)
PASS
ok github.com/carlosframework/platform/internal/release 0.031s
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 08:56:44 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000000 txid.db=0000000000000001
2026/10/25 08:56:44 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000001 maxTXID=0000000000000001 size=720
2026/10/25 08:56:44 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000001
2026/10/25 08:56:44 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000002
2026/10/25 08:56:44 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000002 maxTXID=0000000000000002 size=370
2026/10/25 08:56:44 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000002 txid.db=0000000000000002
2026/10/25 08:56:44 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000002 txid.db=0000000000000003
2026/10/25 08:56:44 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000003 maxTXID=0000000000000003 size=454
2026/10/25 08:56:44 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000003 txid.db=0000000000000003
2026/10/25 08:56:44 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000000 txid.db=0000000000000001
2026/10/25 08:56:44 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000001 maxTXID=0000000000000001 size=720
2026/10/25 08:56:44 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000001
2026/10/25 08:56:44 console: CARLOS_SECRETS_PUBKEY is unset, so no region outside the home can be chosen automatically
2026/10/25 08:56:44 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%3A46181: could not determine target mailbox
agent.go:135: dbreads: dbr_ae2jyboqis6m22p7tlv7noifvy: planned 1 files (720 bytes) and restored to 1 in 8ms
agent.go:135: dbreads: dbr_ae2jyboqis6m22p7tlv7noifvy: output 5 bytes in 1 confirmed chunks in 1ms
2026/10/25 08:56:45 console: db read dbr_ae2jyboqis6m22p7tlv7noifvy: relayed 1 chunks (102 bytes) in 1.004s, ended done
agent.go:135: dbreads: dbr_ih6dfwzww7lqhw5bnv4uppbvre: planned 3 files (1544 bytes) and restored to 3 in 9ms
agent.go:135: dbreads: dbr_ih6dfwzww7lqhw5bnv4uppbvre: output 5 bytes in 1 confirmed chunks in 1ms
2026/10/25 08:56:46 console: db read dbr_ih6dfwzww7lqhw5bnv4uppbvre: relayed 1 chunks (102 bytes) in 1.004s, ended done
agent.go:135: dbreads: dbr_rqmig7hprj47d3ustql46l4xce: planned 3 files (1544 bytes) and held through 3 in 12ms
agent.go:135: dbreads: dbr_rqmig7hprj47d3ustql46l4xce: output 1544 bytes in 1 confirmed chunks in 1ms
2026/10/25 08:56:47 console: db read dbr_rqmig7hprj47d3ustql46l4xce: relayed 1 chunks (1641 bytes) in 1.005s, ended done
=== RUN TestDBForwardMinio/by_disconnect
=== NAME TestDBForwardMinio
agent.go:135: dbreads: dbr_nkytsyozd4mfkltmfixjtic5la: planned 3 files (1544 bytes) and restored to 3 in 12ms
2026/10/25 08:56:47 console: db read dbr_nkytsyozd4mfkltmfixjtic5la: relayed 0 chunks (0 bytes) in 32ms, ended client gone
agent.go:135: dbreads: dbr_nkytsyozd4mfkltmfixjtic5la: output 5 bytes in 1 confirmed chunks in 105ms
=== RUN TestDBForwardMinio/by_timeout
=== NAME TestDBForwardMinio
agent.go:135: dbreads: dbr_os2ufszxtdhdtjyuhawawny73m: planned 3 files (1544 bytes) and restored to 3 in 12ms
2026/10/25 08:57:07 console: db read dbr_os2ufszxtdhdtjyuhawawny73m: relayed 0 chunks (0 bytes) in 19.042s, ended no-result
agent.go:135: dbreads: dbr_os2ufszxtdhdtjyuhawawny73m: output 5 bytes in 1 confirmed chunks in 19.014s
--- PASS: TestDBForwardMinio (22.50s)
--- PASS: TestDBForwardMinio/by_disconnect (0.24s)
--- PASS: TestDBForwardMinio/by_timeout (19.15s)
PASS
ok github.com/carlosframework/platform/internal/console 22.517s
minio contract: PASS
diff --git a/AGENTS.md b/AGENTS.md| index 59be1f922..a57f05a58 100644 |
| --- a/AGENTS.md |
| +++ b/AGENTS.md |
| @@ -222,13 +222,15 @@ anything. |
| GOPROXY=off`; go commands may need the sandbox disabled ("read-only file |
| system" from the toolchain is the tell). |
| -## The census: an approval, not a decision (Paul, 2026-10-24, #369) |
| +## The census: an approval, not a decision (Paul, 2026-10-24, #369; reviewer, 2026-10-25) |
| `TestPlan14RootReadCensus` (`internal/provision`) fails when a branch |
| changes a unit that reads root-owned state, or a package inside the |
| -census envelope. Every such change needs the census owner's approval on |
| -#280 before the merge. Most are approvals: the same reads in an edited |
| -body, or an envelope fingerprint that moved. Get them approved like this: |
| +census envelope. Every such change needs an approval on #280 before the |
| +merge. Most are approvals: the same reads in an edited body, or an |
| +envelope fingerprint that moved. An independent reviewer gives those; |
| +the census owner (Paul) sees only decisions and escalations. Get them |
| +approved like this: |
| 1. `make census-card` prints what changed and writes nothing. Each change |
| has a class: |
| @@ -251,18 +253,40 @@ body, or an envelope fingerprint that moved. Get them approved like this: |
| if any step fails. If the code changes again, rerun it with the same |
| NAME: it replaces its own overlay (only one it wrote itself), which must |
| still be the last line of the chain. |
| -4. Show the card to the census owner and ask for an approval. Ask in the |
| - session when they are there (one question: approve or hold); otherwise |
| - post the card on #280. Record the approval on #280: who, when, and the |
| - tip. Rows carry `rev3=census-ruling-<NAME>` from the start, so there is |
| +4. Get the approval from an independent reviewer: a model from the other |
| + family than the one that wrote the change (Astra for a Claude author, |
| + Opus or Fable for a Codex one), never the author itself. Give it the |
| + card and the branch's diff against main on the amadan.net remote |
| + (`origin` or `amadan`, as in the steps above). It gives a verdict for |
| + every unit and every re-pinned envelope, citing the lines it read: |
| + - a unit is compared with its recorded disposition and basis, which |
| + the card lists; |
| + - an envelope means every changed function in that package and what |
| + it reaches, since an envelope re-pin is how the census sees reads its |
| + scanner cannot attribute to a unit. |
| + |
| + It escalates if the change lets root open, run, query or follow |
| + anything it did not before from a path or input a tenant, an app or a |
| + box agent can create, write or name; if it weakens a check, refusal, |
| + validation, argument or environment the basis relies on; or if the |
| + diff cannot settle either. Otherwise it approves. Record each verdict |
| + on #280 with the reviewer and the tip. An escalation goes to the |
| + census owner as a decision. |
| + Rows carry `rev3=census-ruling-<NAME>` from the start, so there is |
| nothing to flip afterwards and no second CI run. |
| +Why a reviewer and not an automatic pass: the classes count kinds of |
| +read, not where a read points, so a `body` change can aim an existing |
| +`Open` at a tenant-writable path. Someone other than the author has to |
| +read the diff, but it need not be the owner. |
| + |
| The tool refuses decisions (`reads`, `new`, `removed`, `other`): a new |
| kind of read can make a unit's disposition wrong, so it is the owner's |
| call, not an approval. Write those rows by hand, following the overlays in the |
| chain, and ask on #280 with the card attached; the census owner decides |
| those. Nothing about the census's strength changes: every changed read is |
| -still named, digested and seen by a person before merge. The record-write |
| +still named, digested and read by someone other than its author before |
| +merge. The record-write |
| census (9B8, the `*_census_test.go` inventories) still takes hand-written |
| entries. |
diff --git a/internal/provision/census_propose_internal_test.go b/internal/provision/census_propose_internal_test.go| index 19a267956..782e197fa 100644 |
| --- a/internal/provision/census_propose_internal_test.go |
| +++ b/internal/provision/census_propose_internal_test.go |
| @@ -168,7 +168,7 @@ func TestCensusProposalClosesEveryApprovableChange(t *testing.T) { |
| t.Errorf("row does not name the ruling: %s", line) |
| } |
| } |
| - for _, want := range []string{"census-ruling-wake-timing", "internal/a/a.go", "body", "sites", "+registry:Host", "internal/a", seal, p.Seal, "logs the wake's timing"} { |
| + for _, want := range []string{"census-ruling-wake-timing", "internal/a/a.go", "body", "sites", "+registry:Host", "internal/a", seal, p.Seal, "logs the wake's timing", censusReviewQuestion, "Recorded dispositions"} { |
| if !strings.Contains(p.Card, want) { |
| t.Errorf("card lacks %q:\n%s", want, p.Card) |
| } |
| @@ -371,3 +371,14 @@ func TestCensusClassifiesAKeyWithASpace(t *testing.T) { |
| t.Fatalf("changes = %+v, want one body for %q", cs, key) |
| } |
| } |
| + |
| +// An envelope-only card still asks the reviewer for a verdict: a re-pin |
| +// is how the census sees reads it cannot attribute to a unit (Astra |
| +// review, census-astra-approvals P1). |
| +func TestCensusCardReviewsAnEnvelopeAlone(t *testing.T) { |
| + cs := []censusChange{{Key: "internal/a", Class: censusEnvelope, OldHash: strings.Repeat("1", 64), NewHash: strings.Repeat("2", 64)}} |
| + card := rootReadCard("x", cs, nil, strings.Repeat("3", 64), "") |
| + if !strings.Contains(card, censusReviewQuestion) || !strings.Contains(card, "`internal/a`") { |
| + t.Errorf("card:\n%s", card) |
| + } |
| +} |
diff --git a/internal/provision/census_propose_test.go b/internal/provision/census_propose_test.go| index 7dd3fa823..415fa5501 100644 |
| --- a/internal/provision/census_propose_test.go |
| +++ b/internal/provision/census_propose_test.go |
| @@ -6,8 +6,8 @@ package provision |
| // the same reads in an edited body, or an envelope fingerprint that moved. |
| // This file classifies each discrepancy, writes the overlay that closes the |
| // approvable ones (rows, @legacy fingerprints, envelope re-pins, the seal, |
| -// the chain manifest line), and the approval card a person reads to |
| -// approve it. Changes that need a disposition (a new unit, a removed one, |
| +// the chain manifest line), and the approval card an independent reviewer |
| +// reads to approve it. Changes that need a disposition (a new unit, a removed one, |
| // the scanner's field list) are decisions: it names them and writes |
| // nothing. |
| // |
| @@ -291,7 +291,7 @@ func proposeRootReads(got rootReadScan, inv rootReadInventory, seal, name string |
| plain = append(plain, row) |
| } |
| header := []string{ |
| - fmt.Sprintf("# Census overlay %s, "+censusProposeMark+". %s, approved by the census owner before the merge; the approval card is docs/superpowers/notes/census-proposal-%s.md.", name, ruling, name), |
| + fmt.Sprintf("# Census overlay %s, "+censusProposeMark+". %s, approved on #280 before the merge; the approval card is docs/superpowers/notes/census-proposal-%s.md.", name, ruling, name), |
| fmt.Sprintf("# %d body, %d sites, %d envelope: each changed unit re-frozen at its existing disposition with its claim appended.", counts[censusBody], counts[censusSites], counts[censusEnvelope]), |
| } |
| overlay := strings.Join(append(append(append(header, frozen...), plain...), cover...), "\n") + "\n" |
| @@ -324,8 +324,10 @@ func censusDiscrepancies(got rootReadScan, inv rootReadInventory, seal string) [ |
| return append(errs, checkRootReadDeclarations(got, inv)...) |
| } |
| -// rootReadCard is what a person reads to approve the change. newSeal is |
| -// empty for a dry run (make census-card). |
| +// rootReadCard is what the reviewer reads to approve the change (AGENTS.md, |
| +// The census): someone other than the author, because the classes count |
| +// kinds of read, not where a read points. newSeal is empty for a dry run |
| +// (make census-card). |
| func rootReadCard(name string, cs []censusChange, claims map[string]string, seal, newSeal string) string { |
| var b strings.Builder |
| fmt.Fprintf(&b, "# Census approval: %s\n\n", name) |
| @@ -365,6 +367,16 @@ func rootReadCard(name string, cs []censusChange, claims map[string]string, seal |
| if len(envelopes) > 0 { |
| fmt.Fprintf(&b, "Envelopes re-pinned: %s.\n\n", strings.Join(envelopes, ", ")) |
| } |
| + if len(units) > 0 || len(envelopes) > 0 { |
| + b.WriteString(censusReviewQuestion) |
| + } |
| + if len(units) > 0 { |
| + b.WriteString("Recorded dispositions, which each change must still satisfy:\n\n") |
| + for _, c := range units { |
| + fmt.Fprintf(&b, "- `%s` `%s`: %s, task %s. Basis: %s\n", c.Before.File, c.Before.Unit, c.Before.Class, c.Before.Task, c.Before.Basis) |
| + } |
| + b.WriteString("\n") |
| + } |
| if len(decisions) > 0 { |
| b.WriteString("Decisions (write their rows by hand and ask on #280):\n\n") |
| for _, c := range decisions { |
| @@ -387,6 +399,10 @@ func rootReadCard(name string, cs []censusChange, claims map[string]string, seal |
| return b.String() |
| } |
| +// censusReviewQuestion is what the independent reviewer answers for the |
| +// approvals on a card (AGENTS.md, The census). |
| +const censusReviewQuestion = "Review: a model from the other family than the author reads the branch's diff against main on the amadan.net remote (`origin` or `amadan`, whichever points at amadan.net) and gives a verdict for every unit and every re-pinned envelope above. For a unit, compare the change with its recorded disposition and basis below; for an envelope, read every changed function in the package and what it reaches. Escalate if the change lets root open, run, query or follow anything it did not before from a path or input a tenant, an app or a box agent can create, write or name; if it weakens a check, refusal, validation, argument or environment the basis relies on; or if the diff cannot settle either. Otherwise approve. Record each verdict on #280 with the tip. An escalation goes to the census owner as a decision.\n\n" |
| + |
| // censusProposeMark is in the first line of every overlay census-propose |
| // writes: a re-run replaces only a file that carries it. |
| const censusProposeMark = "written by census-propose (#369)" |