docs: cohort-1 go package for Paul: v0.28.2 values, 5.0a results, signer, session
- markers now "published (v0.28.2, tag on 7c1beb2d)" - v0.28.2 values filled: carlos linux-arm64 7141e037 and linux-amd64 303f6522 from the signed SHA256SUMS.txt (signature verified), sums and sig digests, router identity values (match dev's signed stable and canary pointers), prebuilt console 08273410 (stripped, cmd/console, version.Build=v0.28.2 once, not executed), ship version 7c1beb2d (not yet shipped), floor min_release v0.28.2 final - 5.0a re-done with read-only results: 1a PASS (bab, canary/console), 1b eight bab apps / nine pointers, none with digests, 1c PASS (3b69c2bd), 1d STOP for ~/bin/carlos v0.17.0 on PATH (shadowed) plus OPEN writer confirmations, 1e digests off, no marker; commands use the prebuilt file; rollback promotes 3b69c2bd with digests on - signing-host.md: trust JSON, user data, policy check for the exact identity key, v0.28.2 CLI sha, remaining TO-CREATE IDs (SG, I, run-id) - signing session order with a go and stop points per block - new "Go package (for Paul)" section at the top
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5 files changed,
+190
−84
docs/superpowers/notes/claim-trial-inputs/README.md+20 −21docs/superpowers/notes/claim-trial-inputs/identity.template.json+3 −3docs/superpowers/notes/claim-trial-inputs/policy.template.json+1 −1docs/superpowers/notes/claim-trial-inputs/signing-host.md+36 −7docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md+130 −52
CI passed — run details
CI log
=== gate ===
go: downloading github.com/aws/aws-sdk-go-v2 v1.44.0
go: downloading github.com/aws/aws-sdk-go-v2/config v1.32.6
go: downloading github.com/aws/aws-sdk-go-v2/service/sns v1.43.0
go: downloading github.com/aws/aws-sdk-go-v2/service/s3 v1.105.0
go: downloading github.com/benbjohnson/litestream v0.5.14
go: downloading modernc.org/sqlite v1.55.0
go: downloading github.com/superfly/ltx v0.5.1
go: downloading github.com/aws/aws-sdk-go-v2/service/route53 v1.64.1
go: downloading golang.org/x/crypto v0.53.0
go: downloading github.com/aws/aws-sdk-go-v2/service/acm v1.45.0
go: downloading github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.68.0
go: downloading github.com/aws/aws-sdk-go-v2/service/ec2 v1.324.0
go: downloading github.com/aws/aws-sdk-go-v2/service/iam v1.58.2
go: downloading github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.37.0
go: downloading github.com/aws/aws-sdk-go-v2/service/sts v1.45.6
go: downloading github.com/aws/smithy-go v1.28.1
go: downloading github.com/aws/aws-sdk-go-v2/credentials v1.19.6
go: downloading github.com/oschwald/maxminddb-golang v1.13.1
go: downloading golang.org/x/sys v0.46.0
go: downloading github.com/klauspost/compress v1.18.0
go: downloading golang.org/x/net v0.56.0
go: downloading github.com/pion/logging v0.2.4
go: downloading github.com/pion/stun/v3 v3.0.1
go: downloading github.com/pion/turn/v4 v4.1.4
go: downloading github.com/aws/aws-sdk-go-v2/service/sesv2 v1.66.6
go: downloading github.com/aws/aws-sdk-go-v2/service/costexplorer v1.67.5
go: downloading github.com/pierrec/lz4/v4 v4.1.22
go: downloading github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.40
go: downloading github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.38
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.40
go: downloading github.com/prometheus/client_golang v1.17.0
go: downloading golang.org/x/sync v0.21.0
go: downloading github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18
go: downloading github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16
go: downloading github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4
go: downloading github.com/aws/aws-sdk-go-v2/service/signin v1.0.4
go: downloading github.com/aws/aws-sdk-go-v2/service/sso v1.30.8
go: downloading github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12
go: downloading github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.40
go: downloading github.com/lmittmann/tint v1.1.3
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31
go: downloading golang.org/x/text v0.38.0
go: downloading github.com/pion/dtls/v3 v3.0.7
go: downloading github.com/pion/transport/v3 v3.0.8
go: downloading github.com/beorn7/perks v1.0.1
go: downloading github.com/cespare/xxhash/v2 v2.3.0
go: downloading github.com/prometheus/client_model v0.5.0
go: downloading github.com/prometheus/common v0.45.0
go: downloading github.com/prometheus/procfs v0.12.0
go: downloading google.golang.org/protobuf v1.36.10
go: downloading github.com/pion/randutil v0.1.0
go: downloading github.com/pion/transport/v4 v4.0.1
go: downloading github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0
go: downloading github.com/wlynxg/anet v0.0.5
go: downloading modernc.org/libc v1.74.1
go: downloading github.com/dustin/go-humanize v1.0.1
go: downloading modernc.org/memory v1.11.0
go: downloading github.com/google/uuid v1.6.0
go: downloading modernc.org/mathutil v1.7.1
go: downloading github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec
cd launchctx && go vet ./... && go test ./... -count=1
ok amadan.net/carlos/platform.git/launchctx 0.012s
? amadan.net/carlos/platform.git/launchctx/controlname [no test files]
? amadan.net/carlos/platform.git/launchctx/wireid [no test files]
go vet ./...
go: downloading golang.org/x/tools v0.47.0
go: downloading golang.org/x/mod v0.37.0
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok github.com/carlosframework/platform 318.595s
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 2.670s
ok github.com/carlosframework/platform/cmd/moveprobe 92.197s
ok github.com/carlosframework/platform/cmd/zddprobe 0.712s
ok github.com/carlosframework/platform/internal/activator 251.491s
ok github.com/carlosframework/platform/internal/agentsock 0.017s
ok github.com/carlosframework/platform/internal/alerting 0.003s
ok github.com/carlosframework/platform/internal/analytics 0.019s
ok github.com/carlosframework/platform/internal/appconfig 2.485s
ok github.com/carlosframework/platform/internal/apperr 0.074s
ok github.com/carlosframework/platform/internal/applog 0.126s
ok github.com/carlosframework/platform/internal/awsinv 0.005s
ok github.com/carlosframework/platform/internal/boxchoice 0.004s
ok github.com/carlosframework/platform/internal/boxid 0.789s
? 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.012s
ok github.com/carlosframework/platform/internal/certwarm 0.003s
ok github.com/carlosframework/platform/internal/cgroup 0.714s
ok github.com/carlosframework/platform/internal/changelog 0.317s
ok github.com/carlosframework/platform/internal/claimactivation 0.027s
ok github.com/carlosframework/platform/internal/clamd 0.055s
? github.com/carlosframework/platform/internal/cliflag [no test files]
ok github.com/carlosframework/platform/internal/console 412.166s
? 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.305s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.009s
ok github.com/carlosframework/platform/internal/dbverify 0.005s
ok github.com/carlosframework/platform/internal/dnsrec 0.003s
ok github.com/carlosframework/platform/internal/docsite 0.005s
ok github.com/carlosframework/platform/internal/domains 2.440s
ok github.com/carlosframework/platform/internal/doorkey 0.007s
ok github.com/carlosframework/platform/internal/economics 0.003s
ok github.com/carlosframework/platform/internal/edge 45.009s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.008s
ok github.com/carlosframework/platform/internal/fleetapi 0.135s
ok github.com/carlosframework/platform/internal/gate 1.656s
ok github.com/carlosframework/platform/internal/genselect 0.015s
ok github.com/carlosframework/platform/internal/geo 0.019s
ok github.com/carlosframework/platform/internal/geoip 0.030s
ok github.com/carlosframework/platform/internal/historyreadback 0.156s
ok github.com/carlosframework/platform/internal/host 180.297s
ok github.com/carlosframework/platform/internal/hostactors 0.827s
ok github.com/carlosframework/platform/internal/hostbox 2.719s
ok github.com/carlosframework/platform/internal/hostclaim 0.613s
ok github.com/carlosframework/platform/internal/hostevidence 0.006s
ok github.com/carlosframework/platform/internal/hostexec 5.205s
ok github.com/carlosframework/platform/internal/hostfence 0.034s
ok github.com/carlosframework/platform/internal/hostfiles 10.746s
ok github.com/carlosframework/platform/internal/hostfloor 0.013s
ok github.com/carlosframework/platform/internal/hostguard 1.033s
ok github.com/carlosframework/platform/internal/hostops 1.651s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.003s
ok github.com/carlosframework/platform/internal/hostquarantine 0.003s
ok github.com/carlosframework/platform/internal/hostrelocate 0.490s
ok github.com/carlosframework/platform/internal/hostresolve 0.153s
ok github.com/carlosframework/platform/internal/hostwrite 0.003s
ok github.com/carlosframework/platform/internal/infraview 0.003s
ok github.com/carlosframework/platform/internal/instancectl 5.260s
ok github.com/carlosframework/platform/internal/instanceexec 2.772s
ok github.com/carlosframework/platform/internal/instancefs 0.005s
ok github.com/carlosframework/platform/internal/instancekey 0.003s
ok github.com/carlosframework/platform/internal/instanceupdates 0.008s
ok github.com/carlosframework/platform/internal/layout 1.584s
ok github.com/carlosframework/platform/internal/lbhealth 0.003s
ok github.com/carlosframework/platform/internal/lease 9.836s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.006s
ok github.com/carlosframework/platform/internal/ledger 0.011s
ok github.com/carlosframework/platform/internal/mail 0.169s
ok github.com/carlosframework/platform/internal/maintenance 0.084s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.591s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.093s
ok github.com/carlosframework/platform/internal/metrics 0.009s
ok github.com/carlosframework/platform/internal/moves 21.756s
ok github.com/carlosframework/platform/internal/moves/archive 0.812s
ok github.com/carlosframework/platform/internal/objstore 0.188s
ok github.com/carlosframework/platform/internal/ops 0.188s
ok github.com/carlosframework/platform/internal/park 0.210s
ok github.com/carlosframework/platform/internal/privatefile 0.006s
ok github.com/carlosframework/platform/internal/provision 90.472s
ok github.com/carlosframework/platform/internal/publicrelease 0.012s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 5.777s
ok github.com/carlosframework/platform/internal/relay 7.301s
ok github.com/carlosframework/platform/internal/release 23.002s
ok github.com/carlosframework/platform/internal/rollout 3.662s
ok github.com/carlosframework/platform/internal/rolloutwords 0.004s
ok github.com/carlosframework/platform/internal/rootaws 0.013s
ok github.com/carlosframework/platform/internal/rootparticipation 0.059s
ok github.com/carlosframework/platform/internal/rootstate 0.028s
ok github.com/carlosframework/platform/internal/runs 0.590s
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.539s
ok github.com/carlosframework/platform/internal/seeds 0.011s
ok github.com/carlosframework/platform/internal/sim/hostlife 11.363s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 4.498s
ok github.com/carlosframework/platform/internal/status 0.039s
ok github.com/carlosframework/platform/internal/steering 0.006s
ok github.com/carlosframework/platform/internal/stopevidence 0.259s
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.005s
ok github.com/carlosframework/platform/internal/version 0.002s
ok github.com/carlosframework/platform/internal/vet 1.597s
=== 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.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/18 09:41:48 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18DF965E54B79498, 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.020s
minio contract: PASS
diff --git a/docs/superpowers/notes/claim-trial-inputs/README.md b/docs/superpowers/notes/claim-trial-inputs/README.md| index 043a20787..29c90a22d 100644 |
| --- a/docs/superpowers/notes/claim-trial-inputs/README.md |
| +++ b/docs/superpowers/notes/claim-trial-inputs/README.md |
| @@ -1,8 +1,8 @@ |
| # Claim trial inputs, dev cohort 1 (draft for review) |
| -These are the concrete inputs the runbook's steps 5 to 7 say "the controller supplies and Paul approves" (`docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md`). They were drafted on 2026-10-18 from dev values read with read-only calls, then updated with platform-1e's rulings the same day. Nothing here is signed, and no secret is in any file. A value still open is marked `TO-CONFIRM`; one that waits on a platform fix is marked `BLOCKED`, or `on main 7c1beb2d, ships in v0.28.2 (not yet published)` once the fix is merged and waits only for the release. |
| +These are the concrete inputs the runbook's steps 5 to 7 say "the controller supplies and Paul approves" (`docs/superpowers/plans/2026-10-16-claim-activation-dev-cohort1.md`). They were drafted on 2026-10-18 from dev values read with read-only calls, then updated with platform-1e's rulings the same day. Nothing here is signed, and no secret is in any file. A value still open is marked `TO-CONFIRM`; one that waited on a platform fix was marked `BLOCKED`; those fixes are now on main `7c1beb2d` and published (v0.28.2, tag on 7c1beb2d). |
| -Builder findings from the review of platform-1e's branch `claim-step6-artifacts` (`c38a4ca9`, census ruled; now on main 7c1beb2d, ships in v0.28.2 (not yet published)) were added on 2026-10-18, drafted for Paul after v0.28.2: the console built with `version.Build=v0.28.2`, pointer digests for the console's channel (runbook step 5.0a), the fixed console path, and `publish-identity`'s verbatim inputs. |
| +Builder findings from the review of platform-1e's branch `claim-step6-artifacts` (`c38a4ca9`, census ruled; now on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d)) were added on 2026-10-18, drafted for Paul after v0.28.2: the console built with `version.Build=v0.28.2`, pointer digests for the console's channel (runbook step 5.0a), the fixed console path, and `publish-identity`'s verbatim inputs. |
| Timing: step 5.0 (box identity records) is done. Everything after it, from 5.1 (roster and enrollment) on, waits for v0.28.2, which carries the fixes for gaps 1 and 2, and runs in one signing session (Paul's ruling, 2026-10-18). |
| @@ -37,7 +37,7 @@ Platform main at drafting: `b1118925` (region HA 2b). The box-record verb is on |
| | Console ID | `dev-console` | platform-1e ruling 2026-10-18 | confirmed | |
| | Console enrollment | 32 lowercase hex characters | `hostactors` token rule `^[0-9a-f]{32}$`; chosen once at approval and kept | TO-CONFIRM (generated at approval) | |
| | Console deployment bucket | `carlos-dev-640012953448` | dev deployment bucket | confirmed | |
| -| Floor | `{"min": 1, "min_release": "v0.28.2"}` | `moves.ProtocolVersion` is `1` on main; v0.28.2 is the first release with the gap 1 and 2 fixes, which arming needs | min confirmed; `min_release` v0.28.2 by ruling, final once v0.28.2 is published | |
| +| Floor | `{"min": 1, "min_release": "v0.28.2"}` | `moves.ProtocolVersion` is `1` on main; v0.28.2 is the first release with the gap 1 and 2 fixes, which arming needs | confirmed: v0.28.2 is published (tag on 7c1beb2d, 2026-10-18), so `min_release` is final at v0.28.2 | |
| | Home region | `ie` | step 7 | confirmed | |
| | Release public key | the dev deployment root key, fingerprint `960d03ff` (sha256 of the host.env value) | `CARLOS_RELEASE_PUBKEY` on every dev box | confirmed (public; copy from a box) | |
| @@ -46,16 +46,17 @@ Platform main at drafting: `b1118925` (region HA 2b). The box-record verb is on |
| | Artifact | Value | Status | |
| |---|---|---| |
| | Release for step 5 | v0.28.1, dev only (box-record verb), `3b69c2bd`, published 2026-10-18; on leo, sophie, dennis and the dev console. `carlos-linux-arm64` sha256 `2ae174da29b1d10fdcb009172ba830db5460b62e838bcecc7d9e17535f35adea` (signed `SHA256SUMS.txt`, verified) | confirmed | |
| -| Release for step 6 onwards | v0.28.2 (`claims run` phases `sign-policy` and `publish-identity`, `claims run --out`, `claims install-console`) | on main 7c1beb2d, ships in v0.28.2 (not yet published) | |
| -| Router linux-arm64 sha256 (v0.28.2) | the `carlos-linux-arm64` line of the v0.28.2 release's signed `SHA256SUMS.txt`, read by `publish-identity` from the sums text in its plan. Never typed | TO-CONFIRM when published | |
| -| Dev console build for v0.28.2 | built from the v0.28.2 tag with `-ldflags "-s -w -X github.com/carlosframework/platform/internal/version.Build=v0.28.2"`: the release tag, not the short sha. `publish-identity` reads the stamp and refuses any other; the console's floor report compares it with the identity's version, and the identity is create-only per tag. Shipped as version `<short sha of v0.28.2's commit>` and promoted to `canary/console` after pointer digests are on (runbook 5.0a). `roll-console.sh` can't build it: it stamps the short sha. It must be stripped (`-s -w`): main's bounded ELF check refuses the compressed debug sections of an unstripped build | TO-CONFIRM: built in 5.0a | |
| -| Console account, app and channel | `bab`, `console`, `canary/console` (pointer `apps/bab/console/channels/canary/console.json`) | TO-CONFIRM by runbook 5.0a 1a's read-only check. If the console's pointer is in any other account or channel, that is a STOP: the values are not adapted, it is reported on #250. Flagship's console is `bab`, `canary/console`, and direct-bucket ships default to the ops account. Moving the console to its own account is out of scope for the trial | |
| -| Pointer digests for `bab` | off today; must be on, and `canary/console`'s pointer must carry digests, before `publish-identity`. `carlos channels digests on --account-id bab`, then a fresh console promote (runbook 5.0a, its own Paul's go, outside any roll). It covers every `bab` app on dev; platform-1e accepts that in principle and Paul decides at the go, with 5.0a's listing of every `bab` app's pointers and every writer. A writer older than v0.26.0 is a STOP | TO-DO: 5.0a | |
| -| Console linux-arm64 sha256 (v0.28.2) | read by `publish-identity`: the `canary/console` pointer's signed manifest digest for the console version, then that manifest's `linux-arm64` sha256, then the artefact itself, hashed and stamp-checked. Never typed by hand, and never taken from `SHA256SUMS.txt`: the phase refuses a console sha256 that is any file in the sums | TO-CONFIRM: equals the `sha256sum` of 5.0a's build | |
| -| Router linux-arm64 sha256, v0.28.0 (current, for comparison) | `3ca7c74d5356a3995ecf677d142bc32fafaf790a2cc1bc0b628f3eec1b7ea731`, from the signed dev `control/system/router/stable.json` | confirmed | |
| -| Console executable on sophie | fixed at `/opt/carlos/system/console/console`, with `console.prev` beside it (same bytes at arming), both root:root `0755`, created by `carlos system claims install-console` on sophie from the build 5.0a promoted (`--source /opt/carlos/versions/<CV>/console`). `guard-arm --console` takes this path. Replaces today's `/opt/carlos/versions/26065378/console`, which has no `.prev` | on main 7c1beb2d, ships in v0.28.2 (not yet published) | |
| -| `policy.json` | an armed `hostfloor.Policy` with the floor bytes and a root-signed `moves-protocol` authorization, written byte-exact by `claims run` phase `sign-policy` with `--out` on the signer and read directly; no `jq` or other parser ever touches it | on main 7c1beb2d, ships in v0.28.2 (not yet published) | |
| -| `identity.json` | the signed system identity for v0.28.2 at `control/system/router/releases/v0.28.2.json`, published create-only by `claims run` phase `publish-identity` on the signer and written byte-exact to `--out` as read back; read directly, no `jq` or other parser ever touches it | on main 7c1beb2d, ships in v0.28.2 (not yet published) | |
| +| Release for step 6 onwards | v0.28.2 (`claims run` phases `sign-policy` and `publish-identity`, `claims run --out`, `claims install-console`), tag on `7c1beb2d`. `carlos-linux-arm64` sha256 `7141e037d61b0d95ae554252af1bb9155653a9954ad0dcaffb35c7047850f492`, `carlos-linux-amd64` sha256 `303f6522ac3a03529c3d08b0e1cd2751d94c68293355db3ed67c1a5b9049a808`, both from the signed `SHA256SUMS.txt` (signature verified 2026-10-18 with the README's pinned key: "Signature Verified Successfully"; `sha256sum -c` OK for both). Leo, sophie and dennis read `carlos v0.28.2` (`.prev` v0.28.1) on 2026-10-18 | published (v0.28.2, tag on 7c1beb2d); on every dev box | |
| +| Router linux-arm64 sha256 (v0.28.2) | the `carlos-linux-arm64` line of the v0.28.2 release's signed `SHA256SUMS.txt`, read by `publish-identity` from the sums text in its plan. Never typed. Value: `7141e037d61b0d95ae554252af1bb9155653a9954ad0dcaffb35c7047850f492`, the same as `artifacts.linux-arm64` in dev's signed `control/system/router/stable.json` and `canary.json` (both v0.28.2), whose key `bootstrap/router/v0.28.2/carlos-linux-arm64` is in the bucket (49217698 bytes, the release asset's size) | confirmed 2026-10-18 | |
| +| Dev console build for v0.28.2 | prebuilt on DOCS-T1 at `~/.cache/release-v0.28.2/console-linux-arm64`; use that exact file, never rebuild it. 47055010 bytes, sha256 `0827341051360e888ed4f6df568a77ebb070e6ad16a7c87a2947a02dbd552ff4`. Checked 2026-10-18 without executing it: `file` says `ELF 64-bit LSB executable, ARM aarch64, ... statically linked, ... stripped`; `go version -m` shows `path github.com/carlosframework/platform/cmd/console` and `build -ldflags="-s -w -X github.com/carlosframework/platform/internal/version.Build=v0.28.2"`, the stamp exactly once; its sha256 is not in v0.28.2's `SHA256SUMS.txt`. Ship version `7c1beb2d` (the short sha of v0.28.2's commit); `apps/bab/console/releases/7c1beb2d/` does not exist yet, so the ship is new. Shipped and promoted to `canary/console` in 5.0a, after pointer digests are on | confirmed (built, not shipped) | |
| +| Console account, app and channel | `bab`, `console`, `canary/console` (pointer `apps/bab/console/channels/canary/console.json`, serving `3b69c2bd`) | confirmed read-only 2026-10-18 (5.0a 1a PASS): it is the only current-shape console pointer in the bucket. A legacy account-less copy, `apps/console/channels/canary/console.json`, also exists; that pre-accounts key shape is not read by any runtime path since the read fallback was retired (`internal/release/release.go`), so it is noted, not a STOP. Any other account or channel would have been a STOP. Moving the console to its own account is out of scope for the trial | |
| +| Pointer digests for `bab` | off today; must be on, and `canary/console`'s pointer must carry digests, before `publish-identity`. `carlos channels digests on --account-id bab`, then a fresh console promote (runbook 5.0a, its own Paul's go, outside any roll). It covers every `bab` app on dev; platform-1e accepts that in principle and Paul decides at the go, with 5.0a's listing of every `bab` app's pointers and every writer. A writer older than v0.26.0 is a STOP | TO-DO: 5.0a. Read 2026-10-18: `pointer digests: off for bab`, no marker at `releases/bab/pointer-digests`, all nine `bab` pointers without digests | |
| +| Console linux-arm64 sha256 (v0.28.2) | read by `publish-identity`: the `canary/console` pointer's signed manifest digest for the console version, then that manifest's `linux-arm64` sha256, then the artefact itself, hashed and stamp-checked. Never typed by hand, and never taken from `SHA256SUMS.txt`: the phase refuses a console sha256 that is any file in the sums. Expected value: `0827341051360e888ed4f6df568a77ebb070e6ad16a7c87a2947a02dbd552ff4`, the prebuilt file's | known; `publish-identity` must read the same value after 5.0a's promote | |
| +| `SHA256SUMS.txt` and `SHA256SUMS.txt.sig` (v0.28.2) | `SHA256SUMS.txt`: 704 bytes, ends in a newline, sha256 `9c29b3d305c464cf981afffa0bc51f1654015883c02717477f38357709d46db2`; it lists `carlos_0.28.2_amd64.deb` and `carlos_0.28.2_arm64.deb` and no other deb. `SHA256SUMS.txt.sig`: 89 bytes, sha256 `0fdb855730c857f017cb3ca2908739b4c0695f7e712f155596c63a863edbc6c0`. Both from `https://github.com/carlosframework/releases/releases/download/v0.28.2/`; `publish-identity` carries them verbatim | confirmed 2026-10-18 | |
| +| Router linux-arm64 sha256, v0.28.0 (for comparison) | `3ca7c74d5356a3995ecf677d142bc32fafaf790a2cc1bc0b628f3eec1b7ea731`, from the signed dev `control/system/router/stable.json` | confirmed | |
| +| Console executable on sophie | fixed at `/opt/carlos/system/console/console`, with `console.prev` beside it (same bytes at arming), both root:root `0755`, created by `carlos system claims install-console` on sophie from the build 5.0a promoted (`--source /opt/carlos/versions/7c1beb2d/console`). `guard-arm --console` takes this path. Replaces today's `/opt/carlos/versions/3b69c2bd/console` (read 2026-10-18), which has no `.prev` | on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d) | |
| +| `policy.json` | an armed `hostfloor.Policy` with the floor bytes and a root-signed `moves-protocol` authorization, written byte-exact by `claims run` phase `sign-policy` with `--out` on the signer and read directly; no `jq` or other parser ever touches it | on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d) | |
| +| `identity.json` | the signed system identity for v0.28.2 at `control/system/router/releases/v0.28.2.json`, published create-only by `claims run` phase `publish-identity` on the signer and written byte-exact to `--out` as read back; read directly, no `jq` or other parser ever touches it | on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d) | |
| ## publish-identity's plan |
| @@ -76,7 +77,7 @@ The sums files are downloaded on DOCS-T1 with the signer's CLI, passed to the si |
| ## Gaps found while drafting |
| -platform-1e confirmed gaps 1 and 2 on main on 2026-10-18 and built the fixes, with Paul's go, on branch `claim-step6-artifacts` (census ruled), now on main 7c1beb2d, ships in v0.28.2 (not yet published): (a) the `claims run` phase `sign-policy`, which signs the armed policy for a floor on the trusted host and writes nothing to the bucket; (b) the `claims run` phase `publish-identity`, which publishes the signed system identity (router and console) at `control/system/router/releases/<tag>.json` from the trusted host (not the release workflow); and (c) `claims install-console`, the protected console install with its `.prev`. All ship in v0.28.2, before step 6. |
| +platform-1e confirmed gaps 1 and 2 on main on 2026-10-18 and built the fixes, with Paul's go, on branch `claim-step6-artifacts` (census ruled), now on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d): (a) the `claims run` phase `sign-policy`, which signs the armed policy for a floor on the trusted host and writes nothing to the bucket; (b) the `claims run` phase `publish-identity`, which publishes the signed system identity (router and console) at `control/system/router/releases/<tag>.json` from the trusted host (not the release workflow); and (c) `claims install-console`, the protected console install with its `.prev`. All ship in v0.28.2, before step 6. |
| 1. **No tool signs the armed policy offline.** `guard-arm` (step 6) refuses anything but `mode: "armed"` with a floor and a valid authorization: a root envelope over `{schema 1, purpose "moves-protocol", deployment_bucket, key "control/moves-protocol.json", sha256 of the floor bytes}`. On main, that authorization is signed only inside `hostfloor.Publish`, which writes it to the bucket, and `PublishFloor` (step 7) refuses unless every actor already reports `FloorGuardReady` for that floor digest, which needs the armed policy. The only other producer, `joinroot.go`, reads an already published floor. So step 6 needs a reviewed way to sign the policy without publishing: for example, a `claims run` phase that signs and prints it on the trusted host. Fix: (a) above. |
| 2. **No system identity for any release exists in the dev bucket.** `guard-arm --identity` takes a release-workflow signed pointer with `current.release_tag` and `current.moves_protocol >= 1`, stored at `control/system/router/releases/<tag>.json`. The dev bucket holds only `control/system/router/{canary,stable}.json`, whose payloads carry neither field, and `release.PublishSystemIdentity` has no production caller on main. Fix: (b) above. |
| @@ -87,17 +88,15 @@ platform-1e confirmed gaps 1 and 2 on main on 2026-10-18 and built the fixes, wi |
| TO-CONFIRM: |
| 1. Console enrollment token, 32 lowercase hex characters (generated at approval). |
| -2. v0.28.2 published: the router sha256 from its signed `SHA256SUMS.txt`, the console sha256 (read by `publish-identity` through the digest-signed `canary/console` pointer), and the carlos v0.28.2 CLI sha256 for the signer. This also fixes the floor's `min_release`. |
| -3. The bucket keys the signer needs, confirmed by a `--dry-run` of every phase from the signer. `publish-identity` adds reads under `apps/bab/console/` and one write, `control/system/router/releases/v0.28.2.json` (`signing-host.md`). |
| -4. The console's account, app and channel (`bab`, `console`, `canary/console`) and its ship version `CV`, from 5.0a. |
| +2. The bucket keys the signer needs, confirmed by a `--dry-run` of every phase from the signer. `publish-identity` adds reads under `apps/bab/console/` and one write, `control/system/router/releases/v0.28.2.json` (`signing-host.md`). |
| -TO-CREATE (each with Paul's go): the `carlos-claim-signer` security group (its ID), role, instance profile and instance (`signing-host.md`). |
| +TO-CREATE (with Paul's go to open the signing session; `signing-host.md`, "Create"): the role `carlos-claim-signer` and its inline policy `claim-signer`, the instance profile `carlos-claim-signer`, the security group `carlos-claim-signer` (its ID, `SG`), the instance (its ID, `I`), and the exchange prefix's `<run-id>`. The names are fixed; the three IDs exist only once created. |
| -Known now: v0.28.1 is published and on dev; the carlos v0.28.1 and jq 1.7.1 sha256 values, the AMI, the VPC and the subnet are in `signing-host.md`. |
| +Known now (2026-10-18): v0.28.2 is published and on every dev box; the carlos v0.28.2 and jq 1.7.1 sha256 values, the AMI, the VPC and the subnet are in `signing-host.md`; the console build, its sha256 and its ship version `7c1beb2d` are above. Done or confirmed and so removed from TO-CONFIRM: the v0.28.2 values, the console's account and channel. |
| -TO-DO, its own Paul's go, after v0.28.2 and before the signing session: runbook 5.0a, pointer digests on for `bab` and a fresh promote of the console built with `version.Build=v0.28.2` (gap 4). |
| +TO-DO, its own Paul's go, after v0.28.2 and before the signing session: runbook 5.0a, pointer digests on for `bab` and a fresh promote of the prebuilt console (`version.Build=v0.28.2`, ship version `7c1beb2d`) (gap 4). |
| -On main 7c1beb2d, ships in v0.28.2 (not yet published) (built by platform-1e on branch `claim-step6-artifacts`): |
| +On main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d) (built by platform-1e on branch `claim-step6-artifacts`): |
| 5. `policy.json`: the signed armed policy, from `sign-policy --out` (gap 1). |
| 6. `identity.json`: the signed v0.28.2 system identity, from `publish-identity --out` (gap 2). |
| 7. Sophie's protected console at `/opt/carlos/system/console/console` and its `.prev`, from `install-console` (gap 3; `.prev` equals current at arming). |
diff --git a/docs/superpowers/notes/claim-trial-inputs/identity.template.json b/docs/superpowers/notes/claim-trial-inputs/identity.template.json| index 6e8cd2257..079d39f94 100644 |
| --- a/docs/superpowers/notes/claim-trial-inputs/identity.template.json |
| +++ b/docs/superpowers/notes/claim-trial-inputs/identity.template.json |
| @@ -10,18 +10,18 @@ |
| "artifacts": { |
| "linux-arm64": { |
| "key": "bootstrap/router/v0.28.2/carlos-linux-arm64", |
| - "sha256": "TO-CONFIRM: the carlos-linux-arm64 line of the v0.28.2 release's signed SHA256SUMS.txt" |
| + "sha256": "7141e037d61b0d95ae554252af1bb9155653a9954ad0dcaffb35c7047850f492" |
| } |
| }, |
| "console_artifacts": { |
| "linux-arm64": { |
| "key": "bootstrap/console/v0.28.2/carlos-linux-arm64", |
| - "sha256": "TO-CONFIRM: the console build from runbook 5.0a, read through the canary/console pointer's signed manifest digest" |
| + "sha256": "0827341051360e888ed4f6df568a77ebb070e6ad16a7c87a2947a02dbd552ff4" |
| } |
| }, |
| "source": "release:v0.28.2" |
| }, |
| "spread": "0s" |
| }, |
| - "note": "Shape only, on main 7c1beb2d, ships in v0.28.2 (not yet published). The real file is the root-signed identity ({payload, sig}) that the claims run phase publish-identity publishes create-only at control/system/router/releases/v0.28.2.json and writes byte-exact to --out. The channel is always stable and is read by nothing that checks an identity. No sha256 is typed: publish-identity reads both" |
| + "note": "Shape only, on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d). The real file is the root-signed identity ({payload, sig}) that the claims run phase publish-identity publishes create-only at control/system/router/releases/v0.28.2.json and writes byte-exact to --out. The channel is always stable and is read by nothing that checks an identity. No sha256 is typed: publish-identity reads both. The values shown are the expected ones (2026-10-18): the router from v0.28.2's signed SHA256SUMS.txt, the console from the prebuilt file runbook 5.0a ships" |
| } |
diff --git a/docs/superpowers/notes/claim-trial-inputs/policy.template.json b/docs/superpowers/notes/claim-trial-inputs/policy.template.json| index 386a16c0d..e5f543e9f 100644 |
| --- a/docs/superpowers/notes/claim-trial-inputs/policy.template.json |
| +++ b/docs/superpowers/notes/claim-trial-inputs/policy.template.json |
| @@ -6,5 +6,5 @@ |
| "min": 1, |
| "min_release": "v0.28.2" |
| }, |
| - "authorization": "On main 7c1beb2d, ships in v0.28.2 (not yet published): root-signed envelope of {schema: 1, purpose: \"moves-protocol\", deployment_bucket: \"carlos-dev-640012953448\", key: \"control/moves-protocol.json\", sha256: <sha256 of the exact floor bytes>}, signed on the trusted host by the claims run phase sign-policy, which writes nothing to the bucket and writes the policy byte-exact to --out" |
| + "authorization": "On main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d): root-signed envelope of {schema: 1, purpose: \"moves-protocol\", deployment_bucket: \"carlos-dev-640012953448\", key: \"control/moves-protocol.json\", sha256: <sha256 of the exact floor bytes>}, signed on the trusted host by the claims run phase sign-policy, which writes nothing to the bucket and writes the policy byte-exact to --out" |
| } |
diff --git a/docs/superpowers/notes/claim-trial-inputs/signing-host.md b/docs/superpowers/notes/claim-trial-inputs/signing-host.md| index 24b45cbb2..c2e97744e 100644 |
| --- a/docs/superpowers/notes/claim-trial-inputs/signing-host.md |
| +++ b/docs/superpowers/notes/claim-trial-inputs/signing-host.md |
| @@ -79,7 +79,7 @@ Why each statement: |
| - **ListForNotFound:** without `s3:ListBucket`, S3 answers a missing key with 403 instead of 404, and the runner's first `initialize` reads a roster that doesn't exist yet. |
| - **WriteRosterAndFloor:** these are exactly the runner's write allowlist (`internal/claimactivation/runner.go:89-104`). |
| - **ReadControl:** covers the reads for invitations, box records and floor evidence. Confirm it with a `--dry-run` of every phase from the signer, and widen only on a refusal. |
| -- **ReadConsoleRelease and WriteIdentity** (added 2026-10-18 for step 6.1; on main 7c1beb2d, ships in v0.28.2 (not yet published)): `publish-identity` reads the console's `canary/console` pointer, manifest and artefact under `apps/bab/console/`, and writes one object, the identity at `control/system/router/releases/v0.28.2.json`, create-only. `WriteIdentity` names that exact key, not a prefix: no wildcard, so the role can write no other release's identity. `sign-policy` writes nothing. The runner admits only that one identity key for the phase, whatever IAM allows. platform-1e accepted this scope as proposed on 2026-10-18; Paul approves it together with the signer host. |
| +- **ReadConsoleRelease and WriteIdentity** (added 2026-10-18 for step 6.1; on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d)): `publish-identity` reads the console's `canary/console` pointer, manifest and artefact under `apps/bab/console/`, and writes one object, the identity at `control/system/router/releases/v0.28.2.json`, create-only. `WriteIdentity` names that exact key, not a prefix: no wildcard, so the role can write no other release's identity. `sign-policy` writes nothing. The runner admits only that one identity key for the phase, whatever IAM allows. platform-1e accepted this scope as proposed on 2026-10-18; Paul approves it together with the signer host. |
| **The release-key deny doesn't block this role.** That deny is the inline policy `deny-release-key-reads` on the box roles only (`carlos-dev-host`, `carlos-dev-host-b`). Dev-uk's role is limited by its own eu-west-2 scope. There is no account-wide deny. A policy simulation of this `ReleaseKey` statement returns `allowed` (2026-10-18). Because any role granted `ssm:GetParameter` on that ARN can read the key, the role exists only for the trial and is deleted afterwards. CloudTrail is checked so that every `GetParameter` on `/carlos/release-key` comes from a `carlos-claim-signer` session. |
| @@ -101,7 +101,7 @@ The key goes from the SSM response straight into a `0600` file on tmpfs (`/run`) |
| Known values (2026-10-18): |
| - carlos v0.28.1 `carlos-linux-arm64`: `2ae174da29b1d10fdcb009172ba830db5460b62e838bcecc7d9e17535f35adea`. It comes from the published release's `SHA256SUMS.txt`, whose signature verified with the README's pinned key (`openssl pkeyutl -verify`: "Signature Verified Successfully"). It is the same binary leo and sophie run. |
| - jq 1.7.1 `jq-linux-arm64`: `4dd2d8a0661df0b22f1bb9a1f9830f06b6f3b8f7d91211a1ef5d7c4f06a8b4a5` (1709616 bytes). It was computed on DOCS-T1 from the file downloaded from `github.com/jqlang/jq/releases/download/jq-1.7.1/`, and matches that release's `sha256sum.txt`. |
| -- carlos v0.28.2: TO-CONFIRM when published. The signing session uses it. |
| +- carlos v0.28.2 `carlos-linux-arm64` (the session's CLI): `7141e037d61b0d95ae554252af1bb9155653a9954ad0dcaffb35c7047850f492`, from v0.28.2's `SHA256SUMS.txt` (sha256 `9c29b3d305c464cf981afffa0bc51f1654015883c02717477f38357709d46db2`), whose signature verified with the README's pinned key on 2026-10-18 ("Signature Verified Successfully", `sha256sum -c` OK). It is the binary leo, sophie and dennis run. |
| On DOCS-T1, before launching: |
| 1. Download the carlos CLI `carlos-linux-arm64` (v0.28.2: the session runs 5.1 through 7, and step 6's `sign-policy` and `publish-identity` need v0.28.2), with the release's `SHA256SUMS.txt` and `SHA256SUMS.txt.sig`, from the public release. Verify the signature as the README's "Releasing the platform" verification does, then `sha256sum -c`. Record the sha256. Keep both sums files exactly as downloaded: step 6.1's `publish-identity` plan carries them verbatim. |
| @@ -113,17 +113,46 @@ On the signer, as root: |
| ```bash |
| aws s3 cp s3://carlos-dev-640012953448/claim-signer/<run-id>/carlos-linux-arm64 /usr/local/bin/carlos |
| aws s3 cp s3://carlos-dev-640012953448/claim-signer/<run-id>/jq-linux-arm64 /usr/local/bin/jq |
| -printf '%s %s\n' 2ae174da29b1d10fdcb009172ba830db5460b62e838bcecc7d9e17535f35adea /usr/local/bin/carlos \ |
| +printf '%s %s\n' 7141e037d61b0d95ae554252af1bb9155653a9954ad0dcaffb35c7047850f492 /usr/local/bin/carlos \ |
| 4dd2d8a0661df0b22f1bb9a1f9830f06b6f3b8f7d91211a1ef5d7c4f06a8b4a5 /usr/local/bin/jq | sha256sum -c |
| chmod 0755 /usr/local/bin/carlos /usr/local/bin/jq |
| /usr/local/bin/carlos version |
| ``` |
| -Expected: both `OK`, then `carlos v0.28.2`. The session uses the v0.28.2 binary: replace the carlos sha256 above with v0.28.2's (TO-CONFIRM when published). The v0.28.1 value is kept for reference. |
| +Expected: both `OK`, then `carlos v0.28.2`. The v0.28.1 value above is kept for reference only. |
| -## Create (each part needs Paul's go) |
| +## Create (Paul's go: opening the signing session) |
| -From DOCS-T1, profile `kass`, with the trust and inline policies saved as `signer-trust.json` and `signer-policy.json`, and the root runner's user data as `signer-user-data.sh`: |
| +Paul approves the signer host and its role policy (including the exact identity key) together, at the go that opens the signing session. From DOCS-T1, profile `kass`, in a fresh `mktemp -d` directory. Save the three files below, then run the commands. |
| + |
| +`signer-trust.json`: |
| + |
| +```json |
| +{ |
| + "Version": "2012-10-17", |
| + "Statement": [ |
| + {"Effect": "Allow", "Principal": {"Service": "ec2.amazonaws.com"}, "Action": "sts:AssumeRole"} |
| + ] |
| +} |
| +``` |
| + |
| +`signer-policy.json`: the inline policy `claim-signer` exactly as in "IAM role `carlos-claim-signer`" above, with `ReadConsoleRelease` on `apps/bab/console/*` and `WriteIdentity` on exactly `control/system/router/releases/v0.28.2.json`. Check it before use: |
| + |
| +```bash |
| +python3 -c 'import json,sys;d=json.load(open("signer-policy.json"));w=[s for s in d["Statement"] if s["Sid"]=="WriteIdentity"][0]["Resource"];assert w=="arn:aws:s3:::carlos-dev-640012953448/control/system/router/releases/v0.28.2.json", w;print("ok")' |
| +``` |
| + |
| +`signer-user-data.sh`, the root runner's (Debian ships no SSM agent): |
| + |
| +```sh |
| +#!/bin/sh |
| +set -e |
| +curl -fsSL -o /tmp/ssm.deb https://s3.eu-west-1.amazonaws.com/amazon-ssm-eu-west-1/latest/debian_arm64/amazon-ssm-agent.deb |
| +dpkg -i /tmp/ssm.deb |
| +systemctl enable --now amazon-ssm-agent |
| +``` |
| + |
| +Then: |
| ```bash |
| export AWS_PROFILE=kass AWS_REGION=eu-west-1 |
| @@ -145,7 +174,7 @@ I=$(aws ec2 run-instances --image-id ami-071babd89cea53fa3 --instance-type t4g.s |
| aws ssm start-session --target "$I" |
| ``` |
| -The instance profile can take a few seconds to become usable. If `run-instances` refuses it, wait and retry. |
| +The instance profile can take a few seconds to become usable. If `run-instances` refuses it, wait and retry. Record `SG`, `I` and the session's start time (`date -u +%FT%TZ`, before the key fetch) for teardown and the CloudTrail check. Still to create, with no ID until then: `SG` (security group), `I` (instance) and the exchange `<run-id>` (choose `cohort1-` plus the UTC date and time). |
| ## Teardown, which is also the rollback from any point |
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 17e295072..1d034faa6 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 |
| @@ -1,6 +1,40 @@ |
| # Host claim activation, dev cohort 1: mechanics trial runbook |
| -Draft, first written 2026-10-16, revised 2026-10-17 against main at 26065378. Step 5.0a and step 6 were revised on 2026-10-18 against platform-1e's branch `claim-step6-artifacts` at `c38a4ca9`, and re-checked against main at `7c1beb2d` after it merged (ships in v0.28.2, not yet published). It authorizes nothing. Every change below waits for Paul's go at its own checkpoint. Neither the approved copy quoted in step 8 nor the activation tools' tests authorize running anything. |
| +Draft, first written 2026-10-16, revised 2026-10-17 against main at 26065378. Step 5.0a and step 6 were revised on 2026-10-18 against platform-1e's branch `claim-step6-artifacts` at `c38a4ca9`, and re-checked against main at `7c1beb2d` after it merged (published (v0.28.2, tag on 7c1beb2d)). It authorizes nothing. Every change below waits for Paul's go at its own checkpoint. Neither the approved copy quoted in step 8 nor the activation tools' tests authorize running anything. |
| + |
| +## Go package (for Paul) |
| + |
| +Prepared on 2026-10-18 for platform-1e to present. v0.28.2 is published (tag on `7c1beb2d`) and on leo, sophie and dennis (current, 0 refusing). The dev console is held at `3b69c2bd` until 5.0a. Everything below was checked read-only today; nothing was changed on any box or bucket. |
| + |
| +**v0.28.2 values** |
| +- carlos `linux-arm64` sha256 `7141e037d61b0d95ae554252af1bb9155653a9954ad0dcaffb35c7047850f492`, from the signed `SHA256SUMS.txt` (signature verified with the README's pinned key). It equals the router artefact in dev's signed `stable.json` and `canary.json`. |
| +- carlos `linux-amd64` (the operator CLI for 5.0a) sha256 `303f6522ac3a03529c3d08b0e1cd2751d94c68293355db3ed67c1a5b9049a808`. |
| +- `SHA256SUMS.txt` sha256 `9c29b3d305c464cf981afffa0bc51f1654015883c02717477f38357709d46db2` (704 bytes, lists `carlos_0.28.2_amd64.deb` and `carlos_0.28.2_arm64.deb`); `SHA256SUMS.txt.sig` sha256 `0fdb855730c857f017cb3ca2908739b4c0695f7e712f155596c63a863edbc6c0`. `publish-identity` carries both verbatim. |
| +- Router identity, as `publish-identity` should produce it: `version` and `release_tag` `v0.28.2`, `moves_protocol` `1`, `artifacts.linux-arm64` = `bootstrap/router/v0.28.2/carlos-linux-arm64` with the arm64 sha256 above, `console_artifacts.linux-arm64` = `bootstrap/console/v0.28.2/carlos-linux-arm64` with the console sha256 below. Key `control/system/router/releases/v0.28.2.json` (not yet written). |
| +- Console: the prebuilt `~/.cache/release-v0.28.2/console-linux-arm64`, sha256 `0827341051360e888ed4f6df568a77ebb070e6ad16a7c87a2947a02dbd552ff4`, stripped, `cmd/console`, stamped `version.Build=v0.28.2` once (checked without executing it). Ship version `7c1beb2d`, not shipped yet. Never rebuild it. |
| +- Floor: `{"min": 1, "min_release": "v0.28.2"}`, final. |
| + |
| +**STOPs and open items before the 5.0a go** |
| +1. **STOP:** `~/bin/carlos` on DOCS-T1 is `carlos v0.17.0`, older than v0.26.0. It is on `PATH` behind `~/.local/bin/carlos` (v0.28.0), so it is shadowed today, but a session with another `PATH` order would write pointers without digests. Remove or rename it, or rule it out (5.0a 1d). |
| +2. **OPEN:** writer confirmations on #250 (5.0a 1d): platform-1e, platform-d8 (`zdd-probe4`, `zdd-probe5`), whoever ships `appsdomain-check`, `rollcheck-0261` and `wakecheck`, anyone else with a dev credential, and any CI. Each must answer v0.26.0 or later, or hold off promoting on dev. |
| +3. Noted, not STOPs: legacy account-less copies under `apps/console/`, `apps/helloworld/` and `apps/website/` (no runtime path reads them); the identity's console key `bootstrap/console/v0.28.2/carlos-linux-arm64` is a name only and not in the bucket (nothing in step 6 reads it). |
| + |
| +**Decisions and the go each needs, in order** |
| + |
| +| # | What | Go | State on 2026-10-18 | |
| +|---|---|---|---| |
| +| 1 | Step 2: delete the 267 objects under `apps/bab//` (the script on main) | Paul's go; Paul runs it | not run | |
| +| 2 | Step 4: `CARLOS_POOLS=cohort1` on leo and the disposable app `claimtrial` | approved 2026-10-16; apply after platform-d8 answers | not applied (`CARLOS_POOLS` unset on leo, no `claimtrial` in the bucket) | |
| +| 3 | 5.0a: pointer digests on for all of `bab` on dev (eight apps, nine pointers), then ship and promote the prebuilt console `7c1beb2d` to `canary/console` | one go for both; outside any roll | 1a PASS, 1b listed, 1c PASS, 1d STOP and OPEN rows, 1e as expected, prebuilt console PASS | |
| +| 4 | Open the signing session: create the signer host and its role policy, with read on `apps/bab/console/*` and write on exactly `control/system/router/releases/v0.28.2.json` (`signing-host.md`) | one go for host and policy together | ready; IDs `SG`, `I` and `<run-id>` are created then | |
| +| 5 | 5.1 roster and enrollment | Paul's go | ready once 4 is done; the console enrollment token is generated at approval | |
| +| 6 | Step 6: sign the policy, publish the identity, arm leo, re-run P9, install the protected console, arm sophie, start the guarded console | Paul's go; restarts the dev console | P9 PASS today (09:13Z); re-run at 6.3 | |
| +| 7 | Step 7: readers, floor, home, leo's key, console runtime | Paul's go; `home_region` becomes write-once | ready after 6 | |
| +| 8 | Close the session: shred the key, terminate the signer, delete its role, profile and security group, CloudTrail check | none; always allowed | | |
| + |
| +Later, each with its own go and outside this package: 7a.2 (fence-writer credentials), step 8 (leo's offline window), steps 9 and 10. |
| + |
| +## Scope |
| Dev cohort 1 is a mechanics trial (Paul, 2026-10-16, relayed by platform-1e): |
| - The scope is one box, `carlos-dev-ie-b` (leo-climbing). `carlos-dev-uk` is not part of this trial; it stays a later option. |
| @@ -233,13 +267,13 @@ Re-run P9 right before step 6 (step 6.3), inside the signing session and before |
| ## Blockers |
| -1. **Release.** Resolved: v0.28.0, cut from 26065378 (Plan 14 Parts 2 and 3, the activation tools, e8e961dd), is fully rolled on dev (2026-10-18). Step 1. Two dev-only releases follow, each rolled to dev with Paul's go: v0.28.1 (the box-record verb), rolled 2026-10-18 and used by step 5.0 (done), and v0.28.2 (gap 1 and 2 fixes), which everything past 5.0 waits for. The v0.28.2 dev roll moves the boxes only: leave out step 1's console item, because step 5.0a ships and promotes the dev console's v0.28.2 build after pointer digests are on. |
| -2. **Empty app segment.** 267 objects under `apps/bab//` (P5). Source: leo's app-less `proof*` routes, removed (2026-10-16). Cleanup waits for the e8e961dd release to reach leo and for Paul's approval. Step 2. |
| +1. **Release.** Resolved: v0.28.0, cut from 26065378 (Plan 14 Parts 2 and 3, the activation tools, e8e961dd), is fully rolled on dev (2026-10-18). Step 1. Two dev-only releases follow, each rolled to dev with Paul's go: v0.28.1 (the box-record verb), rolled 2026-10-18 and used by step 5.0 (done), and v0.28.2 (gap 1 and 2 fixes), which everything past 5.0 waits for. The v0.28.2 dev roll moves the boxes only: leave out step 1's console item, because step 5.0a ships and promotes the dev console's v0.28.2 build after pointer digests are on. v0.28.2 was published on 2026-10-18 (tag on `7c1beb2d`) and rolled to leo, sophie and dennis (current, 0 refusing; each reads `carlos v0.28.2`, `.prev` v0.28.1). The dev console is held at `3b69c2bd` on purpose until 5.0a. |
| +2. **Empty app segment.** 267 objects under `apps/bab//` (P5). Source: leo's app-less `proof*` routes, removed (2026-10-16). Cleanup waits for the e8e961dd release to reach leo and for Paul's approval. Step 2. Still open on 2026-10-18: 267 objects under `apps/bab//`. |
| 3. **IAM.** Leo's object-version actions were applied on 2026-10-18 (targeted, `0 to add, 1 to change, 0 to destroy`): the claim's data store lists, reads and deletes object versions in `carlos-dev-ie-640012953448` on the seed and cold-wake paths. The fence-writer role (`carlos-dev-ie-b-fence-writer`, bootstrap user `carlos-dev-ie-b-fence-writer-root`, no access key yet) and the deployment bucket policy were applied on 2026-10-18 from the saved targeted plan (`5 added, 0 changed, 0 destroyed`) and merged as platform-infrastructure#46 (`beb346b`). The bucket policy names that role as the only fence writer. After the apply, wakecheck still served on sophie (200) and leo answered `waking elsewhere` (sophie held the lease), with no AccessDenied in either box's journals. Step 3. |
| 4. **Box identity records.** Resolved 2026-10-18 (step 5.0 done: `control/boxes/leo-climbing.json` and `control/boxes/sophie-knitting.json`). Step 5's enrollment needs each box's signed AWS identity record at `control/boxes/<box>.json`. None exists, and none has ever been written: the publisher (`internal/host/boxrecord.go`, `boxRecordLoop`) runs only with `CARLOS_REGION_HA` on, which is off on every dev box. Leo's and sophie's records must be published before step 5. Paul ruled a reviewed one-off publish, with region HA staying off. |
| The verb `carlos system box publish-record` (branch `box-publish-record`, merging now) ships in v0.28.1, dev only, and is the supported way. It replaces the agent's region-HA-only publisher for this trial; step 5.0 runs it once per box. The record is AWS-signed (the EC2 instance identity document and AWS's signature over it), not signed by the box or the operator, and grants nothing until enrollment reads it. |
| -5. **Signed armed policy and system identity (everything past 5.0).** Step 6's `guard-arm` needs an armed `policy.json` (the floor plus a root-signed `moves-protocol` authorization) and a signed system identity at `control/system/router/releases/<tag>.json`. On main, nothing signs the policy without publishing it, and nothing publishes a system identity; the dev bucket has none. platform-1e confirmed both gaps on 2026-10-18 and built the fixes, with Paul's go, on branch `claim-step6-artifacts` (census ruled), now on main 7c1beb2d, ships in v0.28.2 (not yet published): (a) the `claims run` phase `sign-policy`, which signs the armed policy for a floor on the trusted host and writes nothing to the bucket; (b) the `claims run` phase `publish-identity`, which publishes the release's signed identity (router and console) from the trusted host, not from the release workflow; (c) `claims install-console`, which puts the protected console and its `.prev` at `/opt/carlos/system/console/console` on sophie. All three ship in v0.28.2, so the floor's `min_release` is v0.28.2. `publish-identity` also needs the dev console's channel pointer to carry signed manifest digests and a console built with `version.Build=v0.28.2` (step 5.0a). By Paul's ruling the signing session (5.1 to 7) opens only after v0.28.2, so this blocker gates everything past 5.0. Details in `docs/superpowers/notes/claim-trial-inputs/README.md`. |
| +5. **Signed armed policy and system identity (everything past 5.0).** Step 6's `guard-arm` needs an armed `policy.json` (the floor plus a root-signed `moves-protocol` authorization) and a signed system identity at `control/system/router/releases/<tag>.json`. On main, nothing signs the policy without publishing it, and nothing publishes a system identity; the dev bucket has none. platform-1e confirmed both gaps on 2026-10-18 and built the fixes, with Paul's go, on branch `claim-step6-artifacts` (census ruled), now on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d): (a) the `claims run` phase `sign-policy`, which signs the armed policy for a floor on the trusted host and writes nothing to the bucket; (b) the `claims run` phase `publish-identity`, which publishes the release's signed identity (router and console) from the trusted host, not from the release workflow; (c) `claims install-console`, which puts the protected console and its `.prev` at `/opt/carlos/system/console/console` on sophie. All three ship in v0.28.2, so the floor's `min_release` is v0.28.2. `publish-identity` also needs the dev console's channel pointer to carry signed manifest digests and a console built with `version.Build=v0.28.2` (step 5.0a). By Paul's ruling the signing session (5.1 to 7) opens only after v0.28.2, so this blocker gated everything past 5.0. The code part is resolved: v0.28.2 is published and on every dev box. What remains is 5.0a and the signing session itself. Details in `docs/superpowers/notes/claim-trial-inputs/README.md`. |
| ## Accepted trial gaps |
| @@ -420,7 +454,7 @@ Any other answer is a stop. The `invite-box` dry run in 5.1 then checks the same |
| ### 5.0a Pointer digests and the release-stamped dev console |
| -Builder finding from the review of platform-1e's branch `claim-step6-artifacts` (`c38a4ca9`, now on main 7c1beb2d, ships in v0.28.2 (not yet published)), drafted for Paul after v0.28.2. |
| +Builder finding from the review of platform-1e's branch `claim-step6-artifacts` (`c38a4ca9`, now on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d)), drafted for Paul after v0.28.2. |
| Runs after v0.28.2 is on dev's boxes and checked, and before the signing session opens. Paul's go: separate, for this step alone. It is not part of any roll. The roll notes from v0.26.0 to v0.28.0 say "don't run `carlos channels digests on`" while rolling, so this step runs on its own, with no roll in progress. It changes nothing claim-related: leo's claims stay off and the roster is not touched. |
| @@ -429,11 +463,12 @@ Why it is needed: `publish-identity` (step 6) takes the console's sha256 only fr |
| Scope: the digest marker is per account. The console app lives in account `bab` (`apps/bab/console/`), alongside wakecheck, claimtrial and the other dev test apps. With digests on for `bab`, every upgraded writer signs digests into every `bab` pointer it writes. A box that has verified a pointer with digests refuses later pointers for that channel without them (README, "Pointer digests (#253): writers before readers"). platform-1e accepts digests on for all of `bab` on dev in principle (2026-10-18); Paul decides at this step's go, with step 1's listings in front of him. Moving the console to an account of its own is out of scope for the trial. |
| Values, on DOCS-T1: |
| -- `CARLOS`: the carlos v0.28.2 CLI for DOCS-T1, downloaded from the public release and checked against the release's signed `SHA256SUMS.txt`, the same way `signing-host.md` checks the signer's copy. |
| -- `CV`: the console's ship version, the short sha of v0.28.2's commit. `carlos ship` compares a re-ship with the stored manifest byte for byte and refuses different bytes, so `CV` must not have been shipped for `console` before. If it has, stop and ask. Never make up another version. |
| -- `release.pub`: the dev release public key (fingerprint `960d03ff`), the same file 5.1 stages. |
| +- `CARLOS`: the carlos v0.28.2 CLI for DOCS-T1, `carlos-linux-amd64`, sha256 `303f6522ac3a03529c3d08b0e1cd2751d94c68293355db3ed67c1a5b9049a808`. Download it with `SHA256SUMS.txt` and `SHA256SUMS.txt.sig` from `https://github.com/carlosframework/releases/releases/download/v0.28.2/`, verify the signature as the README's "Releasing the platform" does, then `sha256sum -c --ignore-missing SHA256SUMS.txt`. |
| +- `CONSOLE=~/.cache/release-v0.28.2/console-linux-arm64`: the prebuilt console. Use that exact file; never rebuild it. |
| +- `CV=7c1beb2d`: the console's ship version, the short sha of v0.28.2's commit. `apps/bab/console/releases/7c1beb2d/` does not exist yet (2026-10-18), so the ship is new. `carlos ship` compares a re-ship with the stored manifest byte for byte, so if that prefix appears before 4, stop and ask. Never make up another version. |
| +- `release.pub`: the dev release public key, `gmy7OTRotK+myWXAoJ/MnP+2AUf+LO96/T1KnSeX6UM=` (fingerprint `960d03ff`, read from sophie's host.env on 2026-10-18), the same file 5.1 stages. |
| -**1. Read-only checks.** Every writer that can promote into `bab` on dev must sign digests before the marker goes on. Digest signing first shipped in v0.26.0 (#253). Any writer older than v0.26.0 is a STOP. |
| +**1. Read-only checks.** Every writer that can promote into `bab` on dev must sign digests before the marker goes on. Digest signing first shipped in v0.26.0 (#253). Any writer older than v0.26.0 is a STOP. All of 1a to 1e were run read-only on 2026-10-18 between 09:30Z and 09:45Z with the v0.28.2 CLI; the results are under each check. Re-run them on the day of the go. |
| Set up the read-only environment once (no key): |
| @@ -448,7 +483,17 @@ aws s3 ls --recursive s3://carlos-dev-640012953448/apps/ | awk '{print $4}' | gr |
| "$CARLOS" channels --app console --account-id bab |
| ``` |
| -Pass: the listing shows exactly one key, `apps/bab/console/channels/canary/console.json`, and `carlos channels` shows `canary/console` serving the version the console checks below record. STOP if the console's pointer is in any other account or channel, or if there is more than one: don't adapt the values, report on #250 and wait for platform-1e and Paul. |
| +Pass: the listing shows exactly one key, `apps/bab/console/channels/canary/console.json`, and `carlos channels` shows `canary/console` serving the version 1c records. STOP if the console's pointer is in any other account or channel, or if there is more than one: don't adapt the values, report on #250 and wait for platform-1e and Paul. |
| + |
| +2026-10-18: PASS. |
| + |
| +``` |
| +apps/bab/console/channels/canary/console.json |
| +CHANNEL VERSION PROMOTED TAG DIGESTS |
| +canary/console 3b69c2bd 2026-10-18T05:53:16Z no |
| +``` |
| + |
| +Noted, not a STOP: the bucket also holds legacy account-less copies under `apps/console/`, `apps/helloworld/` and `apps/website/`, including `apps/console/channels/canary/console.json`. That pre-accounts key shape is read by no runtime path since the read fallback was retired (`internal/release/release.go`), and `digests on --account-id bab` does not touch it. |
| **1b. Every `bab` app on dev and its current channel pointers.** This is what digests on for `bab` reaches: |
| @@ -461,7 +506,23 @@ for app in $(aws s3 ls s3://carlos-dev-640012953448/apps/bab/ | awk '$1 == "PRE" |
| done |
| ``` |
| -The first command lists every pointer object; the loop prints, per app, each channel's version, promotion time, tag and whether its pointer carries digests. `grep .` drops the empty `apps/bab//` segment if step 2 has not removed it yet. Record the output for Paul's go. A recent `PROMOTED` time on any channel means a writer is active there; it must appear in 1d. |
| +The first command lists every pointer object; the loop prints, per app, each channel's version, promotion time, tag and whether its pointer carries digests. `grep .` drops the empty `apps/bab//` segment, which is still there (267 objects, step 2 not yet run). Record the output for Paul's go. A recent `PROMOTED` time on any channel means a writer is active there; it must appear in 1d. |
| + |
| +2026-10-18: eight apps, nine pointers, none with digests. `claimtrial` is not there yet (step 4 has not run). |
| + |
| +| App | Channel | Version | Promoted | Digests | |
| +|---|---|---|---|---| |
| +| `appsdomain-check` | `edge` | `adc1` | 2026-10-14T14:19:47Z | no | |
| +| `console` | `canary/console` | `3b69c2bd` | 2026-10-18T05:53:16Z | no | |
| +| `helloworld` | `canary/hello` | `1f4f324` | 2026-08-02T06:08:40Z | no | |
| +| `helloworld` | `stable` | `1f4f324` | 2026-08-02T06:05:11Z | no | |
| +| `rollcheck-0261` | `edge` | `r1` | 2026-10-13T14:04:52Z | no | |
| +| `wakecheck` | `edge` | `wc4` | 2026-10-13T15:41:49Z | no | |
| +| `website` | `canary/website` | `b5433cc` | 2026-08-02T10:13:23Z | no | |
| +| `zdd-probe4` | `edge` | `zdd-4` | 2026-10-13T20:50:19Z | no | |
| +| `zdd-probe5` | `edge` | `zdd-5` | 2026-10-14T05:12:07Z | no | |
| + |
| +Promotions since 2026-10-13: the console (the v0.28.1 roll), `appsdomain-check`, `rollcheck-0261`, `wakecheck`, `zdd-probe4` and `zdd-probe5`. Their writers are in 1d. |
| **1c. The dev console is on v0.28.x:** |
| @@ -470,42 +531,58 @@ curl -sI https://platform.dev.carlosframework.com/ | grep -i x-carlos-version |
| $TMPDIR/cohort1/ssm.sh eu-west-1 i-05498eada6f0afd23 'readlink /proc/$(systemctl show -p MainPID --value console.service)/exe' |
| ``` |
| -Pass: the header names a v0.28.x commit (`26065378` for v0.28.0, `3b69c2bd` for v0.28.1, or v0.28.2's), and the running executable is `/opt/carlos/versions/<that version>/console`. Expected today: `3b69c2bd`. Record it as the rollback version. Promotes made through the console are signed by the console, which reads the marker itself, so this check covers every console-mode CLI and CI job. |
| +Pass: the header names a v0.28.x commit (`26065378` for v0.28.0, `3b69c2bd` for v0.28.1, or `7c1beb2d` for v0.28.2), and the running executable is `/opt/carlos/versions/<that version>/console`. Record it as the rollback version. Promotes made through the console are signed by the console, which reads the marker itself, so this check covers every console-mode CLI and CI job. |
| + |
| +2026-10-18: PASS. `x-carlos-version: 3b69c2bd` (v0.28.1, held there on purpose until this step), running `/opt/carlos/versions/3b69c2bd/console`, `console.service` active. Rollback version: `3b69c2bd`. |
| **1d. Every session or CI job that promotes into dev `bab`.** Each one is checked, and any writer older than v0.26.0 is a STOP: |
| -| Writer | How it promotes | Check | |
| -|---|---|---| |
| -| The dev console | console-mode promotes, rollbacks and fast-tracks, including any CLI or CI job that goes through `platform.dev.carlosframework.com` (the console signs those pointers and reads the marker itself) | 1c | |
| -| Operator sessions on DOCS-T1 (Paul, and the agent sessions running this runbook) | direct-bucket: `ship-app.sh`, `carlos promote`, `carlos rollback` | `"$CARLOS" version` prints `carlos v0.28.2` (it is the `CARLOS_BIN` for 4 below); `carlos version` on `PATH` prints v0.26.0 or later (P3 saw v0.27.2 on 2026-10-17) | |
| -| platform-1e | direct-bucket, for the trial's `claimtrial` (step 4) and any other trial ship | asks itself; `carlos version` v0.26.0 or later | |
| -| platform-d8 (H2) | direct-bucket ships of its zero-downtime test apps | ask on #250 | |
| -| Box CLIs on leo, sophie and dennis | only if someone promotes from a box | P3's box line: v0.28.2 after the roll | |
| -| Any other agent or person with `kass` or another dev credential | direct-bucket | ask on #250 | |
| -| CI | none known. The platform repo's own CI (`.amadan/ci.d/`: `10-gate`, `20-cross`, `30-minio-contract`) does not deploy to dev: nothing on main names the dev bucket or the dev console in CI. Any CI job elsewhere that does is added here | ask on #250 | |
| +| Writer | How it promotes | Check | 2026-10-18 | |
| +|---|---|---|---| |
| +| The dev console | console-mode promotes, rollbacks and fast-tracks, including any CLI or CI job that goes through `platform.dev.carlosframework.com` | 1c | PASS, v0.28.1 | |
| +| Operator sessions on DOCS-T1 (Paul, and the agent sessions running this runbook) | direct-bucket: `ship-app.sh`, `carlos promote`, `carlos rollback` | `"$CARLOS" version`; `carlos version`; `which -a carlos` | `"$CARLOS" version`: `carlos v0.28.2`, PASS. `carlos` on `PATH` is `~/.local/bin/carlos`, `carlos v0.28.0`, PASS. **STOP:** a second CLI on `PATH`, `~/bin/carlos`, is `carlos v0.17.0`. `~/.local/bin` comes first, so it is shadowed today, but any session with a different `PATH` order, or a script that calls it by path, would write pointers without digests. Paul removes or renames it, or rules it out, before the go | |
| +| platform-1e | direct-bucket, for the trial's `claimtrial` (step 4) and any other trial ship | `carlos version` v0.26.0 or later | OPEN: platform-1e confirms | |
| +| platform-d8 (H2) | direct-bucket ships of its zero-downtime test apps (`zdd-probe4`, `zdd-probe5`) | ask on #250 | OPEN: ask | |
| +| Whoever ships `appsdomain-check`, `rollcheck-0261` and `wakecheck` | direct-bucket | ask on #250 | OPEN: ask | |
| +| Box CLIs on leo, sophie and dennis | only if someone promotes from a box | `/opt/carlos/carlos version` | PASS: all three `carlos v0.28.2`, `.prev` `carlos v0.28.1` | |
| +| Any other agent or person with `kass` or another dev credential | direct-bucket | ask on #250 | OPEN: ask | |
| +| CI | none known. The platform repo's own CI (`.amadan/ci.d/`: `10-gate`, `20-cross`, `30-minio-contract`) does not deploy to dev | ask on #250 | OPEN: ask | |
| -Ask on #250 and wait for a clear answer from each writer that is asked: its `carlos version` is v0.26.0 or later, or it will not promote on dev until this step is done. Any writer from 1b's recent promotions that is missing from this table is found and checked before the go. |
| +On DOCS-T1 the other `carlos` files found are test fixtures under `~/t/` and old release copies under `~/t/rel020/` and `~/t/rel021/`; none is on `PATH`. Ask on #250 and wait for a clear answer from each writer marked OPEN: its `carlos version` is v0.26.0 or later, or it will not promote on dev until this step is done. The go needs every row PASS. |
| **1e. The digest state before:** |
| ```bash |
| "$CARLOS" channels digests --account-id bab |
| +aws s3 ls s3://carlos-dev-640012953448/releases/bab/pointer-digests |
| ``` |
| -Expected: `pointer digests: off for bab`, then a table of the `bab` channels without digests, including `bab console canary/console <rollback version> no`. |
| +Expected: `pointer digests: off for bab`, then a table of the `bab` channels without digests, and no marker object. |
| -**2. Build the console (local only).** From a clean checkout at the v0.28.2 tag: |
| +2026-10-18: as expected. `pointer digests: off for bab`, all nine pointers of 1b listed with `no`, and no `releases/bab/pointer-digests` object. |
| + |
| +**2. Check the prebuilt console (local, read-only; never execute or rebuild it):** |
| ```bash |
| -CV=$(git rev-parse --short 'v0.28.2^{commit}') |
| -CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build \ |
| - -ldflags "-s -w -X github.com/carlosframework/platform/internal/version.Build=v0.28.2" \ |
| - -o console-linux-arm64 ./cmd/console |
| -go version -m console-linux-arm64 | grep -- -ldflags |
| -sha256sum console-linux-arm64 |
| +sha256sum "$CONSOLE" |
| +file "$CONSOLE" |
| +go version -m "$CONSOLE" | grep -E 'path|-ldflags' |
| +go version -m "$CONSOLE" | grep -o 'internal/version.Build=[^ "]*' | sort | uniq -c |
| +grep -c "$(sha256sum "$CONSOLE" | cut -d' ' -f1)" SHA256SUMS.txt |
| +``` |
| + |
| +Expected, as read on 2026-10-18 (PASS): |
| + |
| +``` |
| +0827341051360e888ed4f6df568a77ebb070e6ad16a7c87a2947a02dbd552ff4 /home/paulca/.cache/release-v0.28.2/console-linux-arm64 |
| +.../console-linux-arm64: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, Go BuildID=..., stripped |
| + path github.com/carlosframework/platform/cmd/console |
| + build -ldflags="-s -w -X github.com/carlosframework/platform/internal/version.Build=v0.28.2" |
| + 1 internal/version.Build=v0.28.2 |
| +0 |
| ``` |
| -Expected: the `-ldflags` line holds `-X github.com/carlosframework/platform/internal/version.Build=v0.28.2` exactly once, and no other `version.Build`. `publish-identity` refuses an unstamped console, one stamped twice, or one stamped with anything but the tag. Keep `-s -w`: main at `7c1beb2d` runs a bounded ELF check (`release.CheckELFBounds`) before it reads the stamp, and it refuses compressed sections, which an unstripped Go build's debug sections are. Don't use `roll-console.sh`: it stamps the short sha. |
| +The stamp is the release tag exactly once, the file is stripped (main's bounded ELF check refuses an unstripped build's compressed debug sections), the main package is `cmd/console` (not the CLI), and its sha256 is not a file in the release's sums. A different sha256 on the day is a STOP. |
| **3. Turn digests on for `bab`.** The step's one go covers 3 and 4 together. |
| @@ -517,17 +594,18 @@ CARLOS_RELEASE_KEY=$(aws ssm get-parameter --name /carlos/release-key --with-dec |
| The key is read the way `ship-app.sh` reads it, and never printed. Expected, verbatim from main: `pointer digests on for bab. Upgraded writers sign digests from now on`, then `pointer digests: on for bab since <time>`, then the same table as in 1e. Existing pointers get digests at their next promote. |
| -**4. Promote the release-stamped console.** |
| +**4. Ship and promote the prebuilt console.** |
| ```bash |
| -CARLOS_BIN=$CARLOS platform-infrastructure/scripts/ship-app.sh kass carlos-dev-640012953448 console "$CV" canary/console binary console-linux-arm64 |
| +CARLOS_BIN=$CARLOS platform-infrastructure/scripts/ship-app.sh kass carlos-dev-640012953448 console 7c1beb2d canary/console binary "$CONSOLE" |
| ``` |
| Sophie stages, adopts and restarts `console.service` on its own, in about 20 seconds, so the dev console is briefly down. |
| Expected: |
| -- `x-carlos-version` (as in 1c) shows `$CV`; |
| -- the `readlink` from 1c shows `/opt/carlos/versions/$CV/console`. That path is `install-console`'s `--source` in step 6; |
| +- `x-carlos-version` (as in 1c) shows `7c1beb2d`; |
| +- the `readlink` from 1c shows `/opt/carlos/versions/7c1beb2d/console`. That path is `install-console`'s `--source` in step 6; |
| +- `"$CARLOS" channels --app console --account-id bab` shows `canary/console 7c1beb2d ... yes`; |
| - `channels digests --account-id bab` (as in 1e) no longer lists `console canary/console`, and no row says `written after digests were turned on`. Such a row means an old writer is still in use: stop and report on #250; |
| - wakecheck still answers 200 through DNS. |
| @@ -535,26 +613,26 @@ Finish this step before the signing session opens. Its `GetParameter` reads come |
| Rollback: |
| - **Before 4** (only the marker is written): run 3 again with `off` in place of `on`. No box has seen a digest yet, so this is a full undo. Expected: `pointer digests off for bab. Boxes that have already seen digests keep refusing pointers without them`. |
| -- **After 4:** leave digests on. Sophie has verified a `canary/console` pointer with digests and refuses later pointers for that channel without them, so with digests off the next console promote would not be adopted. To back out the console build, promote the recorded rollback version with the same v0.28.2 CLI while digests stay on. That pointer carries digests, so sophie accepts it: |
| +- **After 4:** leave digests on. Sophie has verified a `canary/console` pointer with digests and refuses later pointers for that channel without them, so with digests off the next console promote would not be adopted. To back out the console build, promote `3b69c2bd` again with the same v0.28.2 CLI while digests stay on. That pointer carries digests, so sophie accepts it: |
| ```bash |
| export AWS_PROFILE=kass AWS_REGION=eu-west-1 CARLOS_DEPLOYMENT_BUCKET=carlos-dev-640012953448 |
| CARLOS_RELEASE_KEY=$(aws ssm get-parameter --name /carlos/release-key --with-decryption --query Parameter.Value --output text) \ |
| - "$CARLOS" promote -app console <rollback version> canary/console |
| + "$CARLOS" promote -app console 3b69c2bd canary/console |
| ``` |
| - Then check `x-carlos-version` and the `readlink` as in 1c. `carlos channels digests off` is only for a broken writer (README), and it does not clear boxes that have already seen digests. |
| + Then check `x-carlos-version` and the `readlink` as in 1c. `carlos channels digests off` is only for a broken writer (README), and it does not clear boxes that have already seen digests. A rollback after 4 means the signing session cannot start: `publish-identity` needs the v0.28.2-stamped console running. |
| ## The signing session: 5.1, 6 and 7 |
| Paul's ruling, 2026-10-18: the trusted signing host is created once, after v0.28.2 is on dev, for one session that covers 5.1, step 6 and step 7, so the release key is on a host only once. The trial waits for v0.28.2 before anything past 5.0. |
| -Order of work: |
| -1. **Open the session,** only once 5.0a has passed: create the signer (TO-CREATE, Paul's go), install the verified tools, and fetch the key into tmpfs (`signing-host.md`, "Create" and "Getting the key there"). |
| -2. **5.1** roster and enrollment. |
| -3. **Step 6:** arm leo's guard and start the guarded console. |
| -4. **Step 7:** readers, floor, home and leo's key. |
| -5. **Close the session:** shred the key, terminate the signer, delete its role, profile and security group, and run the CloudTrail check ("Closing the signing session", after step 7). |
| +Order of work, each block with its own Paul's go and its stop points: |
| +1. **Open the session.** Paul's go: create the signer host and its role policy (`signing-host.md`, "Create", including write on exactly `control/system/router/releases/v0.28.2.json`). Only once 5.0a has passed and, in the runbook's order, steps 2 and 4 are done (neither had run on 2026-10-18). Create the signer, install the verified tools (carlos v0.28.2 `7141e037...`, jq 1.7.1 `4dd2d8a0...`), then fetch the key into tmpfs (`signing-host.md`, "Getting the key there"). Record the session's start time before the key fetch. Stop points: a checksum mismatch, `carlos version` not `carlos v0.28.2`, or a key file that is not root `600`. |
| +2. **5.1 roster and enrollment.** Paul's go: once for 5.1. Stop points: any dry run or apply refused; `inspect.json` not listing `leo-climbing` (pool `cohort1`, instance `i-046c7fe43620944bc`), `sophie-knitting` and the console; a staged file without `staged`. |
| +3. **Step 6.** Paul's go: once for step 6 (it restarts the dev console). In order: 6.1 `sign-policy` and `publish-identity` on the signer; 6.2 `guard-arm` on leo; 6.3 the P9 re-run from DOCS-T1, then `install-console`, `guard-arm --console`, `console-config`, the restart and `console-report` on sophie. Stop points: any refusal; an identity value other than step 6.1's expected values (a wrong published identity cannot be replaced); any P9 `SET` line or console-mail role policy; `console.service` not `active`. |
| +4. **Step 7.** Paul's go: once for step 7 (`home_region` becomes write-once). Readers re-checked (P3), then floor, home, leo's key and the console runtime. Stop points: any reader below v0.28.2; the `jq -e` roster check not `true`; a refused report that a fresh box report does not clear. |
| +5. **Close the session.** No go needed; always allowed, and done at any stop. Shred the key, terminate the signer, remove the exchange objects, delete its role, profile and security group, then the CloudTrail check ("Closing the signing session", after step 7). Anything unexpected in CloudTrail is reported on #250 before any further step. |
| Nothing else touches the signer between opening and closing: no other work, no other users, no second instance. Each of 5.1, 6 and 7 still has its own Paul's go inside the session. A stop at any point ends the session (see "Stop and hold"). |
| @@ -575,7 +653,7 @@ For commands that write, add --dry-run to validate and print the planned operati |
| Run signing phases on the trusted operator host. Run box installers as root. |
| ``` |
| -On main 7c1beb2d, ships in v0.28.2 (not yet published): the help changes in three places, quoted from main's `internal/host/activation_command.go` at `7c1beb2d`: |
| +On main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d): the help changes in three places, quoted from main's `internal/host/activation_command.go` at `7c1beb2d`: |
| ``` |
| run --plan FILE --signing-key FILE --public-key K --aws-region R [--out FILE] |
| @@ -713,7 +791,7 @@ On failure: hold. A partly applied phase is resumed from the latest authenticate |
| ## Step 6. Arm leo's guard and start the guarded console |
| -Inside the signing session, after 5.1. Waits for v0.28.2 on dev and for 5.0a. Everything this step adds is on main 7c1beb2d, ships in v0.28.2 (not yet published): the `claims run` phases `sign-policy` and `publish-identity`, `claims run --out`, and `claims install-console`. Never hand-make any of their files. The builder findings from the review of that branch (the release-tag stamp, 5.0a, the fixed console path and the verbatim identity inputs) are drafted here for Paul after v0.28.2. |
| +Inside the signing session, after 5.1. Waits for v0.28.2 on dev and for 5.0a. Everything this step adds is on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d): the `claims run` phases `sign-policy` and `publish-identity`, `claims run --out`, and `claims install-console`. Never hand-make any of their files. The builder findings from the review of that branch (the release-tag stamp, 5.0a, the fixed console path and the verbatim identity inputs) are drafted here for Paul after v0.28.2. |
| Paul's go: once for step 6. It restarts `console.service` on sophie, which briefly interrupts the dev console. |
| @@ -752,7 +830,7 @@ Expected: the dry run, then the apply, succeed; `writes` is empty, because the p |
| | `identity.sha256sums_sig` | the exact text of `SHA256SUMS.txt.sig` | the same release, same path with `.sig` | |
| | `identity.console.account` | `bab` | the console app's account, checked in 5.0a 1a (a STOP if it differs) | |
| | `identity.console.channel` | `canary/console` | the channel 5.0a promoted to, checked in 5.0a 1a (a STOP if it differs) | |
| -| `identity.console.version` | `$CV` | the console's ship version from 5.0a (the short sha of v0.28.2's commit) | |
| +| `identity.console.version` | `7c1beb2d` | the console's ship version from 5.0a (the short sha of v0.28.2's commit) | |
| | `identity.console.app` | `console` | the console app | |
| | `identity.release_tag` | `v0.28.2` | the release tag | |
| | `identity.moves_protocol` | `1` | `moves.ProtocolVersion` on main, the floor's `min` | |
| @@ -760,7 +838,7 @@ Expected: the dry run, then the apply, succeed; `writes` is empty, because the p |
| Verbatim means the two sums files reach the plan as JSON strings holding their bytes unchanged. Download them on DOCS-T1 with the signer's CLI (`signing-host.md`), pass them to the signer through the exchange prefix with `aws s3 cp`, and read them with `jq --rawfile`. Never retype, trim or re-save them. The phase verifies `SHA256SUMS.txt` against its signature with the vendor release key the carlos binary embeds, so one changed byte is refused. It also checks that the list is v0.28.2's own: it must name `carlos_0.28.2_amd64.deb` and `carlos_0.28.2_arm64.deb`, and no other `carlos_*.deb`, so another release's genuine list is refused under this tag. The console values are copied from 5.0a's record, not from memory. No sha256 is typed anywhere: the router's comes from the signed sums (`carlos-linux-arm64`), and the console's from the channel pointer's signed manifest digest, the manifest and the artefact. The console's sha256 may not be any file listed in the sums. |
| ```bash |
| -CV=<the console ship version recorded in 5.0a> |
| +CV=7c1beb2d |
| jq -n --rawfile sums SHA256SUMS.txt --rawfile sig SHA256SUMS.txt.sig --arg cv "$CV" \ |
| '{identity:{release_tag:"v0.28.2",moves_protocol:1,sha256sums:$sums,sha256sums_sig:$sig, |
| console:{account:"bab",app:"console",channel:"canary/console",version:$cv}}}' > identity-phase.json |
| @@ -770,7 +848,7 @@ jq '{identity_key, release}' publish-identity-result.json |
| Expected: |
| - the dry run, then the apply, succeed, and `writes` lists one create-only put of `control/system/router/releases/v0.28.2.json`; |
| -- `identity_key` is that key, and `release` shows `version` and `release_tag` `v0.28.2`, `moves_protocol` `1`, `artifacts.linux-arm64.sha256` equal to the `carlos-linux-arm64` line of `SHA256SUMS.txt`, and `console_artifacts.linux-arm64.sha256` equal to the `sha256sum` of 5.0a's build; |
| +- `identity_key` is that key, and `release` shows `version` and `release_tag` `v0.28.2`, `moves_protocol` `1`, `artifacts.linux-arm64` `{"key": "bootstrap/router/v0.28.2/carlos-linux-arm64", "sha256": "7141e037d61b0d95ae554252af1bb9155653a9954ad0dcaffb35c7047850f492"}` (the `carlos-linux-arm64` line of `SHA256SUMS.txt`), and `console_artifacts.linux-arm64` `{"key": "bootstrap/console/v0.28.2/carlos-linux-arm64", "sha256": "0827341051360e888ed4f6df568a77ebb070e6ad16a7c87a2947a02dbd552ff4"}` (5.0a's prebuilt console). Any other value is a STOP. The console key is a name only: nothing in step 6 reads it, and it is not in the bucket; |
| - `identity.json` is the published object's bytes as read back, the same file `aws s3 cp` of that key would give. |
| The signer's role may write exactly one identity object: the key `control/system/router/releases/v0.28.2.json`, an exact key and not a prefix (`signing-host.md`, statement `WriteIdentity`). platform-1e accepted that scope on 2026-10-18; Paul approves it together with the signer host. The runner also admits only that key for the phase. |
| @@ -800,7 +878,7 @@ set +a |
| ### 6.3 Install the protected console, arm sophie and start the guarded console |
| -The console path is fixed: `/opt/carlos/system/console/console`, with `console.prev` beside it, both created by `carlos system claims install-console` on sophie (on main 7c1beb2d, ships in v0.28.2 (not yet published)). Its `--source` is the console build 5.0a promoted, at `/opt/carlos/versions/<CV>/console`, the path 5.0a's `readlink` showed. |
| +The console path is fixed: `/opt/carlos/system/console/console`, with `console.prev` beside it, both created by `carlos system claims install-console` on sophie (on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d)). Its `--source` is the console build 5.0a promoted, at `/opt/carlos/versions/7c1beb2d/console`, the path 5.0a's `readlink` showed. |
| First, from DOCS-T1, re-run P9 (sophie's console mail is off). Any `SET` line or a console-mail role policy is a STOP: close the session. |
| @@ -822,7 +900,7 @@ set +a |
| PUB=$(cat release.pub) |
| CID=$(cat console-id) |
| REV=$(cat rev) |
| -CONSOLE_SOURCE=/opt/carlos/versions/<CV>/console |
| +CONSOLE_SOURCE=/opt/carlos/versions/7c1beb2d/console |
| CONSOLE_BINARY=/opt/carlos/system/console/console |
| /opt/carlos/carlos system claims install-console --identity /root/claim-trial/identity.json --source "$CONSOLE_SOURCE" \ |
| --bucket carlos-dev-640012953448 --aws-region eu-west-1 --public-key "$PUB" --dry-run |
| @@ -1755,6 +1833,6 @@ For platform-1e: |
| 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: `carlos system box publish-record` ships in v0.28.1, dev only (step 5.0). The v0.28.1 dev roll comes before step 5. |
| -6. Answered 2026-10-18: platform-1e builds the armed policy signing phase and the published system identity with the protected console install, in v0.28.2 (blocker 5). Built on branch `claim-step6-artifacts` (census ruled), on main 7c1beb2d, ships in v0.28.2 (not yet published): `sign-policy`, `publish-identity` and `install-console`. Step 6 waits for it, and for 5.0a; step 5.0 did not. |
| +6. Answered 2026-10-18: platform-1e builds the armed policy signing phase and the published system identity with the protected console install, in v0.28.2 (blocker 5). Built on branch `claim-step6-artifacts` (census ruled), on main 7c1beb2d, published (v0.28.2, tag on 7c1beb2d): `sign-policy`, `publish-identity` and `install-console`. Step 6 waits for it, and for 5.0a; step 5.0 did not. |
| 7. Still open in `docs/superpowers/notes/claim-trial-inputs/README.md`: the console enrollment token, the v0.28.1 and v0.28.2 artifacts, and the signing host values. Namespace `platform`, sophie's pool `console`, console ID `dev-console` and operator `paul@keymail.dev` are confirmed. |
| 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. |