docs: cohort-1 runbook: 7a.1 complete, box-record verb being built
- 7a.1 complete: alias applied from a fresh alias-only plan (1 added), list-aliases shows alias/cohort1-fence-leo -> ef26a257; #45 merged as a0b3f5a. The targeted-plans-only caution is removed: a whole-root plan from main a0b3f5a shows 13 to add, 0 to change, 0 to destroy (owed module drift only), nothing for the key, alias or grant. - Blocker 4: the box-record verb is being built (claim-owned, after region HA 2b).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+6
−5
docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md+6 −5
CI passed — run details
CI log
=== gate ===
cd launchctx && go vet ./... && go test ./... -count=1
ok amadan.net/carlos/platform.git/launchctx 0.011s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
go vet ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok github.com/carlosframework/platform 321.194s
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 2.849s
ok github.com/carlosframework/platform/cmd/moveprobe 92.306s
ok github.com/carlosframework/platform/cmd/zddprobe 0.726s
ok github.com/carlosframework/platform/internal/activator 251.773s
ok github.com/carlosframework/platform/internal/agentsock 0.033s
ok github.com/carlosframework/platform/internal/alerting 0.003s
ok github.com/carlosframework/platform/internal/analytics 0.029s
ok github.com/carlosframework/platform/internal/appconfig 2.495s
ok github.com/carlosframework/platform/internal/apperr 0.107s
ok github.com/carlosframework/platform/internal/applog 0.154s
ok github.com/carlosframework/platform/internal/awsinv 0.007s
ok github.com/carlosframework/platform/internal/boxchoice 0.005s
ok github.com/carlosframework/platform/internal/boxid 0.478s
? 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.015s
ok github.com/carlosframework/platform/internal/caps 0.019s
ok github.com/carlosframework/platform/internal/certwarm 0.005s
ok github.com/carlosframework/platform/internal/cgroup 0.714s
ok github.com/carlosframework/platform/internal/changelog 0.334s
ok github.com/carlosframework/platform/internal/claimactivation 0.034s
ok github.com/carlosframework/platform/internal/clamd 0.061s
? github.com/carlosframework/platform/internal/cliflag [no test files]
ok github.com/carlosframework/platform/internal/console 410.194s
? 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 6.424s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.012s
ok github.com/carlosframework/platform/internal/dbverify 0.006s
ok github.com/carlosframework/platform/internal/dnsrec 0.003s
ok github.com/carlosframework/platform/internal/docsite 0.008s
ok github.com/carlosframework/platform/internal/domains 2.429s
ok github.com/carlosframework/platform/internal/doorkey 0.006s
ok github.com/carlosframework/platform/internal/economics 0.004s
ok github.com/carlosframework/platform/internal/edge 44.911s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.009s
ok github.com/carlosframework/platform/internal/fleetapi 0.150s
ok github.com/carlosframework/platform/internal/gate 1.656s
ok github.com/carlosframework/platform/internal/genselect 0.020s
ok github.com/carlosframework/platform/internal/geo 0.017s
ok github.com/carlosframework/platform/internal/geoip 0.036s
ok github.com/carlosframework/platform/internal/historyreadback 0.171s
ok github.com/carlosframework/platform/internal/host 178.414s
ok github.com/carlosframework/platform/internal/hostactors 0.690s
ok github.com/carlosframework/platform/internal/hostbox 2.701s
ok github.com/carlosframework/platform/internal/hostclaim 0.572s
ok github.com/carlosframework/platform/internal/hostevidence 0.008s
ok github.com/carlosframework/platform/internal/hostexec 4.828s
ok github.com/carlosframework/platform/internal/hostfence 0.030s
ok github.com/carlosframework/platform/internal/hostfiles 10.361s
ok github.com/carlosframework/platform/internal/hostfloor 0.012s
ok github.com/carlosframework/platform/internal/hostguard 1.001s
ok github.com/carlosframework/platform/internal/hostops 1.685s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.002s
ok github.com/carlosframework/platform/internal/hostquarantine 0.002s
ok github.com/carlosframework/platform/internal/hostrelocate 0.480s
ok github.com/carlosframework/platform/internal/hostresolve 0.142s
ok github.com/carlosframework/platform/internal/hostwrite 0.002s
ok github.com/carlosframework/platform/internal/infraview 0.003s
ok github.com/carlosframework/platform/internal/instancectl 5.225s
ok github.com/carlosframework/platform/internal/instanceexec 2.729s
ok github.com/carlosframework/platform/internal/instancefs 0.005s
ok github.com/carlosframework/platform/internal/instancekey 0.002s
ok github.com/carlosframework/platform/internal/instanceupdates 0.008s
ok github.com/carlosframework/platform/internal/layout 1.554s
ok github.com/carlosframework/platform/internal/lbhealth 0.003s
ok github.com/carlosframework/platform/internal/lease 9.807s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.006s
ok github.com/carlosframework/platform/internal/ledger 0.016s
ok github.com/carlosframework/platform/internal/mail 0.154s
ok github.com/carlosframework/platform/internal/maintenance 0.081s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.504s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.076s
ok github.com/carlosframework/platform/internal/metrics 0.006s
ok github.com/carlosframework/platform/internal/moves 20.946s
ok github.com/carlosframework/platform/internal/moves/archive 0.816s
ok github.com/carlosframework/platform/internal/objstore 0.166s
ok github.com/carlosframework/platform/internal/ops 0.177s
ok github.com/carlosframework/platform/internal/park 0.195s
ok github.com/carlosframework/platform/internal/privatefile 0.003s
ok github.com/carlosframework/platform/internal/provision 17.144s
ok github.com/carlosframework/platform/internal/publicrelease 0.006s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 5.396s
ok github.com/carlosframework/platform/internal/relay 7.230s
ok github.com/carlosframework/platform/internal/release 22.115s
ok github.com/carlosframework/platform/internal/rollout 3.681s
ok github.com/carlosframework/platform/internal/rolloutwords 0.003s
ok github.com/carlosframework/platform/internal/rootaws 0.007s
ok github.com/carlosframework/platform/internal/rootparticipation 0.059s
ok github.com/carlosframework/platform/internal/rootstate 0.026s
ok github.com/carlosframework/platform/internal/runs 0.568s
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.485s
ok github.com/carlosframework/platform/internal/seeds 0.011s
ok github.com/carlosframework/platform/internal/sim/hostlife 8.875s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 4.321s
ok github.com/carlosframework/platform/internal/status 0.038s
ok github.com/carlosframework/platform/internal/steering 0.005s
ok github.com/carlosframework/platform/internal/stopevidence 0.197s
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.004s
ok github.com/carlosframework/platform/internal/usage 0.004s
ok github.com/carlosframework/platform/internal/version 0.001s
ok github.com/carlosframework/platform/internal/vet 1.533s
=== 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: 48824482 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.03s)
--- PASS: TestDeliveredContractMinio/put (0.00s)
--- PASS: TestDeliveredContractMinio/get_round-trips_the_body (0.00s)
--- PASS: TestDeliveredContractMinio/list_shows_the_key (0.00s)
--- PASS: TestDeliveredContractMinio/head_and_list_agree_on_the_version (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route (0.02s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed (0.00s)
--- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict (0.01s)
--- 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.032s
=== RUN TestT4StorageProbeMinio
2026/10/18 00:21:59 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18DF77D1DC99ADE7, 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.029s
minio contract: PASS
diff --git a/docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md b/docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md| index 7503c2388..bb22a285c 100644 |
| --- a/docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md |
| +++ b/docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md |
| @@ -198,6 +198,8 @@ Pass: all twelve are root-owned regular files in `/etc/systemd/system`; the edge |
| There is no supported way today. `carlos system box` only sets roles (`system_roles.go`), and the only caller of `publishBoxRecord` (`internal/host/boxrecord.go:121`) is the agent's `boxRecordLoop`, which returns at once unless `CARLOS_REGION_HA` is on. Records are never hand-written. |
| + Status: being built (claim-owned, after region HA 2b). The design is the proposal below. |
| + |
| Proposal, the smallest platform change: a verb `carlos system box publish-record` that calls the existing `publishBoxRecord` once with the box's own label (`metricsBoxLabel`) and `readIdentityRecord`, without the region HA gate, and refuses on fleet boxes as the loop does (`shouldSkipPublisherElection`). It writes `control/boxes/<box>.json` create-only through the box's own credentials. The record is `{v: 1, box, identity_document, identity_signature, written_at}`: the instance identity document from IMDS (base64) and AWS's RSA-SHA256 signature over it, checked later against the embedded regional AWS certificates. It is AWS-signed, not signed by the box or the operator, and grants nothing until enrollment reads it. An existing record for the same instance is a no-op; one for another instance is refused. Cost: |
| - about 40 lines plus tests (parse; no-op on the same instance; refusal on a different instance; refusal on a fleet box; no region HA needed), reusing `publishBoxRecord`'s existing tests; |
| - copy: the usage line, the published and already-in-place lines, the refusals, and a `docs/site/cli.md` paragraph, for Paul's copy review; |
| @@ -213,7 +215,7 @@ Paul deferred these for this trial only. They are not blockers here, and they mu |
| ## Owed before production cohorts |
| -- **Dev module drift.** A whole-root `tofu plan` of `platform-infrastructure/dev` on 2026-10-17 showed 15 adds and 1 change that come from the platform modules (pinned `?ref=main`) moving ahead of dev: termination SQS queues and EventBridge rules for both IE boxes, the deployment bucket's lifecycle rule and its box-records bucket policy, leo's object-version actions (`host_buckets` gains `PullDoorObjectVersions`, `s3:DeleteObjectVersion` and `PullDoorVersionList`; applied for the trial on 2026-10-18), and an SSM parameter scope policy on both IE roles (a deny on parameter reads outside `/carlos/*`). It is owed: its own plan and Paul's approval later, before production cohorts. It is not part of step 7a, whose plan is targeted at its own three resources. Step 3's IAM overlaps it (see open question 3). |
| +- **Dev module drift.** A whole-root `tofu plan` of `platform-infrastructure/dev` on 2026-10-17 showed 15 adds and 1 change (13 adds after leo's `host_buckets` change and the box-records bucket policy were applied for the trial; whole-root plan from main `a0b3f5a` on 2026-10-18: `13 to add, 0 to change, 0 to destroy`) that come from the platform modules (pinned `?ref=main`) moving ahead of dev: termination SQS queues and EventBridge rules for both IE boxes, the deployment bucket's lifecycle rule and its box-records bucket policy, leo's object-version actions (`host_buckets` gains `PullDoorObjectVersions`, `s3:DeleteObjectVersion` and `PullDoorVersionList`; applied for the trial on 2026-10-18), and an SSM parameter scope policy on both IE roles (a deny on parameter reads outside `/carlos/*`). It is owed: its own plan and Paul's approval later, before production cohorts. It is not part of step 7a, whose plan is targeted at its own three resources. Step 3's IAM overlaps it (see open question 3). |
| ## Step 1. Release and roll, claims off |
| @@ -623,9 +625,8 @@ Dev's infrastructure is OpenTofu in `platform-infrastructure/dev`, so the key is |
| Status on 2026-10-18 (Paul's go to apply): |
| - The first apply created `aws_iam_role_policy.cohort1_fence_read` and the key `ef26a257-fc1d-4fe3-ad9e-77a4b7b789f6`, then failed reading the key back: the provider's refresh calls `DescribeKey`, `GetKeyPolicy`, `GetKeyRotationStatus` and `ListResourceTags` (CloudTrail), and the operator statement lacked `kms:GetKeyRotationStatus`. The key was left tainted and the alias was not created. |
| - Fix forward, approved: `kms:GetKeyRotationStatus` added to the operator statement (the file below); the live key policy replaced with that exact rendering by `aws kms put-key-policy` without the lockout bypass (equal to the file apart from AWS storing the one-element `Principal` list as a string; the operator keeps `ScheduleKeyDeletion`, `CancelKeyDeletion` and `PutKeyPolicy`); `tofu untaint aws_kms_key.cohort1_fence`. |
| -- A fresh targeted plan showed `Plan: 1 to add, 0 to change, 0 to destroy.` (the alias only). On Paul's go to apply it, tofu refused it as stale (`Saved plan is stale`): the `host_buckets` apply in step 3 moved the state after the alias plan was saved. Not applied. The alias needs a new targeted plan and Paul's go; #45 stays unmerged until then. |
| -- Live today: the key (Enabled, policy as below) and leo's `cohort1-fence-read` grant. Not yet: the alias. |
| -- Until #45 merges, main's code lacks `cohort1-fence-kms.tf` while the key and grant are in state, so a whole-root plan from main would destroy them. Run only targeted plans on dev until then. |
| +- The first alias plan went stale when the step 3 `host_buckets` apply moved the state; a fresh alias-only targeted plan (`Plan: 1 to add, 0 to change, 0 to destroy.`) was applied on Paul's go (`1 added`). `aws kms list-aliases` shows `alias/cohort1-fence-leo` pointing at `ef26a257-fc1d-4fe3-ad9e-77a4b7b789f6`. |
| +- **7a.1 complete (2026-10-18).** Live: the key (Enabled, policy as below), its alias, and leo's `cohort1-fence-read` grant. PR #45 merged as `a0b3f5a`. A whole-root plan of dev from main `a0b3f5a` shows `Plan: 13 to add, 0 to change, 0 to destroy.`, only the owed module drift, and nothing for the key, alias or grant. |
| - The alias refresh uses `ListAliases`, an account-level action covered by the operator's IAM policy, not the key policy. |
| Its content: |
| @@ -1402,5 +1403,5 @@ For platform-1e: |
| 1. Should `hostops.Apps` skip an empty app segment instead of refusing, so one stray object cannot stop activation on a whole deployment? |
| 2. For a later teardown out of hold: how do writes made under the claim reach the claims-off restore path? |
| 3. Answered 2026-10-18: leo's object-version actions are applied for the trial; the box-records bucket policy goes with the fence-writer role in platform-infrastructure#46. |
| -4. Box identity records: Paul ruled a reviewed one-off publish with region HA off. No supported verb exists; the proposal in blocker 4 needs a decision, a build, copy review, census rows, a release and a dev roll. |
| +4. Box identity records: Paul ruled a reviewed one-off publish with region HA off. The `carlos system box publish-record` verb (blocker 4) is being built, claim-owned, after region HA 2b. It still needs copy review, census rows, a release and a dev roll. |
| 5. The console's mutation classifier lets it delete under `control/boxes/` and `control/box-volumes/`, which the new box-records bucket policy refuses: amadan carlos/platform#302. |