carlos / platform Public

Merge remote-tracking branch 'origin/main' into moves-offline

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev d225ce49e1bb9daba358c75c7382d15478454bc2 parent e240df0parent 57569bf
3 files changed, +423 −0
  • docs/site/changelog-links.json +41 −0
  • docs/site/changelog.json +381 −0
  • docs/site/people.json +1 −0

CI passed — run details

CI log
=== gate ===
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 ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok  	github.com/carlosframework/platform	330.599s
?   	github.com/carlosframework/platform/cmd/changelog	[no test files]
ok  	github.com/carlosframework/platform/cmd/console	2.863s
ok  	github.com/carlosframework/platform/cmd/moveprobe	92.263s
ok  	github.com/carlosframework/platform/cmd/zddprobe	0.707s
ok  	github.com/carlosframework/platform/internal/activator	251.906s
ok  	github.com/carlosframework/platform/internal/agentsock	0.019s
ok  	github.com/carlosframework/platform/internal/alerting	0.003s
ok  	github.com/carlosframework/platform/internal/analytics	0.025s
ok  	github.com/carlosframework/platform/internal/appconfig	2.502s
ok  	github.com/carlosframework/platform/internal/apperr	0.072s
ok  	github.com/carlosframework/platform/internal/applog	0.140s
ok  	github.com/carlosframework/platform/internal/awsinv	0.004s
ok  	github.com/carlosframework/platform/internal/boxchoice	0.004s
ok  	github.com/carlosframework/platform/internal/boxid	0.696s
?   	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.014s
ok  	github.com/carlosframework/platform/internal/certwarm	0.004s
ok  	github.com/carlosframework/platform/internal/cgroup	0.708s
ok  	github.com/carlosframework/platform/internal/changelog	0.334s
ok  	github.com/carlosframework/platform/internal/claimactivation	0.818s
ok  	github.com/carlosframework/platform/internal/clamd	0.056s
?   	github.com/carlosframework/platform/internal/cliflag	[no test files]
ok  	github.com/carlosframework/platform/internal/console	416.967s
?   	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.585s
ok  	github.com/carlosframework/platform/internal/dbdoor/dbdoortest	0.012s
ok  	github.com/carlosframework/platform/internal/dbverify	0.005s
ok  	github.com/carlosframework/platform/internal/dnsrec	0.002s
ok  	github.com/carlosframework/platform/internal/docsite	0.008s
ok  	github.com/carlosframework/platform/internal/domains	2.433s
ok  	github.com/carlosframework/platform/internal/doorkey	0.007s
ok  	github.com/carlosframework/platform/internal/economics	0.005s
ok  	github.com/carlosframework/platform/internal/edge	45.199s
?   	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.162s
ok  	github.com/carlosframework/platform/internal/gate	1.657s
ok  	github.com/carlosframework/platform/internal/genselect	0.015s
ok  	github.com/carlosframework/platform/internal/geo	0.015s
ok  	github.com/carlosframework/platform/internal/geoip	0.030s
ok  	github.com/carlosframework/platform/internal/historyreadback	0.191s
ok  	github.com/carlosframework/platform/internal/host	191.280s
ok  	github.com/carlosframework/platform/internal/hostactors	6.606s
ok  	github.com/carlosframework/platform/internal/hostactors/awsmembership	0.012s
ok  	github.com/carlosframework/platform/internal/hostbox	2.831s
ok  	github.com/carlosframework/platform/internal/hostclaim	0.616s
ok  	github.com/carlosframework/platform/internal/hostenv	0.012s
ok  	github.com/carlosframework/platform/internal/hostevidence	0.012s
ok  	github.com/carlosframework/platform/internal/hostexec	5.051s
ok  	github.com/carlosframework/platform/internal/hostfence	0.039s
ok  	github.com/carlosframework/platform/internal/hostfiles	10.444s
ok  	github.com/carlosframework/platform/internal/hostfloor	0.021s
ok  	github.com/carlosframework/platform/internal/hostguard	1.029s
ok  	github.com/carlosframework/platform/internal/hostops	1.648s
?   	github.com/carlosframework/platform/internal/hostops/fencerelease	[no test files]
ok  	github.com/carlosframework/platform/internal/hostops/internal/fencerelease	0.012s
ok  	github.com/carlosframework/platform/internal/hostquarantine	0.013s
ok  	github.com/carlosframework/platform/internal/hostrelocate	0.499s
ok  	github.com/carlosframework/platform/internal/hostresolve	0.163s
ok  	github.com/carlosframework/platform/internal/hostwrite	0.011s
ok  	github.com/carlosframework/platform/internal/infraview	0.013s
ok  	github.com/carlosframework/platform/internal/instancectl	5.224s
ok  	github.com/carlosframework/platform/internal/instanceexec	2.753s
ok  	github.com/carlosframework/platform/internal/instancefs	0.020s
ok  	github.com/carlosframework/platform/internal/instancekey	0.007s
ok  	github.com/carlosframework/platform/internal/instanceupdates	0.008s
ok  	github.com/carlosframework/platform/internal/layout	1.572s
ok  	github.com/carlosframework/platform/internal/lbhealth	0.007s
ok  	github.com/carlosframework/platform/internal/lease	9.913s
ok  	github.com/carlosframework/platform/internal/lease/leasetest	0.427s
ok  	github.com/carlosframework/platform/internal/ledger	0.032s
ok  	github.com/carlosframework/platform/internal/mail	0.210s
ok  	github.com/carlosframework/platform/internal/maintenance	0.083s
ok  	github.com/carlosframework/platform/internal/maintenanceexec	5.535s
ok  	github.com/carlosframework/platform/internal/maintenanceguard	0.073s
ok  	github.com/carlosframework/platform/internal/metrics	0.006s
ok  	github.com/carlosframework/platform/internal/moves	21.190s
ok  	github.com/carlosframework/platform/internal/moves/archive	0.827s
ok  	github.com/carlosframework/platform/internal/objstore	0.200s
ok  	github.com/carlosframework/platform/internal/ops	0.181s
ok  	github.com/carlosframework/platform/internal/park	0.211s
ok  	github.com/carlosframework/platform/internal/privatefile	0.008s
ok  	github.com/carlosframework/platform/internal/provision	36.538s
ok  	github.com/carlosframework/platform/internal/publicrelease	0.008s
?   	github.com/carlosframework/platform/internal/regionname	[no test files]
ok  	github.com/carlosframework/platform/internal/registry	5.515s
ok  	github.com/carlosframework/platform/internal/relay	7.252s
ok  	github.com/carlosframework/platform/internal/release	24.343s
ok  	github.com/carlosframework/platform/internal/rollout	3.817s
ok  	github.com/carlosframework/platform/internal/rolloutwords	0.003s
ok  	github.com/carlosframework/platform/internal/rootaws	0.008s
ok  	github.com/carlosframework/platform/internal/rootparticipation	0.058s
ok  	github.com/carlosframework/platform/internal/rootstate	0.026s
ok  	github.com/carlosframework/platform/internal/runs	0.562s
ok  	github.com/carlosframework/platform/internal/s3compat	0.006s
ok  	github.com/carlosframework/platform/internal/safefile	0.004s
ok  	github.com/carlosframework/platform/internal/schedule	2.538s
ok  	github.com/carlosframework/platform/internal/seeds	0.011s
ok  	github.com/carlosframework/platform/internal/sim/hostlife	10.049s
ok  	github.com/carlosframework/platform/internal/sim/litestreamfacts	4.341s
ok  	github.com/carlosframework/platform/internal/status	0.066s
ok  	github.com/carlosframework/platform/internal/steering	0.006s
ok  	github.com/carlosframework/platform/internal/stopevidence	0.308s
ok  	github.com/carlosframework/platform/internal/svcrole	0.002s
ok  	github.com/carlosframework/platform/internal/telemetry	0.005s
ok  	github.com/carlosframework/platform/internal/termfence	0.004s
ok  	github.com/carlosframework/platform/internal/tunnelclient	0.004s
ok  	github.com/carlosframework/platform/internal/unixdial	0.003s
ok  	github.com/carlosframework/platform/internal/updatewords	0.008s
ok  	github.com/carlosframework/platform/internal/usage	0.005s
ok  	github.com/carlosframework/platform/internal/version	0.002s
ok  	github.com/carlosframework/platform/internal/vet	1.562s
=== 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: 49807522 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.026s
=== RUN   TestT4StorageProbeMinio
2026/10/20 14:52:14 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18E04478086E2A7E, 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.023s
minio contract: PASS
diff --git a/docs/site/changelog-links.json b/docs/site/changelog-links.json
index 6aad62c18..3082e8c6a 100644
--- a/docs/site/changelog-links.json
+++ b/docs/site/changelog-links.json
@@ -1,5 +1,46 @@
{
"//": "For the changelog: each release-note bullet's bold lead, mapped to the branches behind it. Kept by hand, one release at a time, as step 10 of the release recipe in the README. go run ./cmd/changelog fails on a lead no bullet has, or a branch that did not land in that release.",
+ "v0.28.4": {
+ "Console invites now arrive.": [
+ "design-console-invite-delivery"
+ ],
+ "An account can have 20 invites waiting at most, and send 20 an hour.": [
+ "design-console-invite-delivery"
+ ],
+ "Console email can switch itself on.": [
+ "design-console-invite-delivery"
+ ],
+ "Sending also needs a grant that is off by default.": [
+ "design-console-invite-delivery"
+ ],
+ "With `CARLOS_HOST_CLAIM` on, the console sends no email.": [
+ "design-console-invite-delivery"
+ ],
+ "`carlos system install-channel --policy` now also takes `--identity`.": [
+ "claim-untagged-pointer"
+ ]
+ },
+ "v0.28.3": {
+ "`carlos system install-channel --policy` prepares a box that is already running for host claims.": [
+ "claim-prev-rehearsal"
+ ]
+ },
+ "v0.28.2": {
+ "Three new `carlos system claims` commands prepare a box for host claims.": [
+ "claim-step6-artifacts"
+ ]
+ },
+ "v0.28.1": {
+ "A box can publish its identity record by hand.": [
+ "box-publish-record"
+ ],
+ "A box that has not reported for a day drops out of status.": [
+ "region-ha-2b-build"
+ ],
+ "Each box gets an idle join unit.": [
+ "region-ha-2b-build"
+ ]
+ },
"v0.28.0": {
"`carlos run` runs one of your app's commands against one instance.": [
"carlos-run"
diff --git a/docs/site/changelog.json b/docs/site/changelog.json
index d2b0bf5bd..a15fa98c9 100644
--- a/docs/site/changelog.json
+++ b/docs/site/changelog.json
@@ -2,6 +2,387 @@
"//": "Generated by go run ./cmd/changelog from git, the published release notes and Amadan. Do not edit; regenerate.",
"repo": "https://amadan.net/carlos/platform",
"releases": [
+ {
+ "tag": "v0.28.4",
+ "date": "2026-10-18",
+ "sha": "f3bf1214ab92a47ecb626400e7bd1b35cd7a112c",
+ "published": true,
+ "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.4",
+ "notes": {
+ "form": "bullets",
+ "sections": [
+ {
+ "title": "",
+ "bullets": [
+ {
+ "md": "**Console invites now arrive.** Before this release, an invite to anyone but yourself never reached them. The console now delivers the link to the invitee's Keymail inbox, or by email where console email is on. If neither works, it shows you the link to pass on yourself.",
+ "branches": [
+ "design-console-invite-delivery"
+ ]
+ },
+ {
+ "md": "**An account can have 20 invites waiting at most, and send 20 an hour.** An invite emailed to an address that isn't a Keymail address can't be accepted yet.",
+ "branches": [
+ "design-console-invite-delivery"
+ ]
+ },
+ {
+ "md": "**Nothing changes in the CLI.**"
+ }
+ ]
+ },
+ {
+ "title": "For operators",
+ "bullets": [
+ {
+ "md": "**Roll the boxes first, then the console.**"
+ },
+ {
+ "md": "**Coming from v0.28.2, read the [v0.28.3 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.28.3) first.** They all still apply."
+ },
+ {
+ "md": "**Console email can switch itself on.** A console with `CARLOS_MAIL_REGION` set and a sending address (`CARLOS_CONSOLE_MAIL_FROM`, or one made from `CARLOS_MAIL_PLATFORM_SUFFIX`) creates an SES identity and DNS records for that address's domain the first time it starts. It sends nothing until SES has verified the domain.",
+ "branches": [
+ "design-console-invite-delivery"
+ ]
+ },
+ {
+ "md": "**Sending also needs a grant that is off by default.** The region-host module's `console_mail_from` and `console_mail_region` add an `ses:SendEmail` grant to the host role. Leave them unset until that grant's security review is done. Without it, invites fall back to Keymail or the link.",
+ "branches": [
+ "design-console-invite-delivery"
+ ]
+ },
+ {
+ "md": "**With `CARLOS_HOST_CLAIM` on, the console sends no email.** Invites then go by Keymail, or the owner passes the link on.",
+ "branches": [
+ "design-console-invite-delivery"
+ ]
+ },
+ {
+ "md": "**`carlos system install-channel --policy` now also takes `--identity`.** The two go together. The published release identity stands in for the channel's release tag, which the channel only carries once a floor is published.",
+ "branches": [
+ "claim-untagged-pointer"
+ ],
+ "docs": [
+ "/docs/cli#carlos-system"
+ ]
+ },
+ {
+ "md": "**Every dormant switch stays off.** Leave `CARLOS_SWAP`, `CARLOS_MOVES_PHASE1`, `CARLOS_HOST_CLAIM`, `CARLOS_HOST_CLAIM_ORIGINS`, `CARLOS_HOST_CLAIM_RETIRED_LOCATIONS`, `CARLOS_CONSOLE_ID`, `CARLOS_REGION_HA`, `CONSOLE_APP_REGIONS`, `CARLOS_TEMPORARY_APPS` and `CARLOS_REQUIRE_POINTER_DIGEST` unset, don't put `CARLOS_BOX_REFERENCE=group` in any host.env, and don't run `carlos channels digests on`.",
+ "docs": [
+ "/docs/cli#carlos-channels-digests"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "changes": [
+ {
+ "sha": "f3bf1214ab92a47ecb626400e7bd1b35cd7a112c",
+ "date": "2026-10-18",
+ "subject": "claim-untagged-pointer: install-channel --policy takes --identity (the published release identity) so an untagged channel pointer works; the activation witness has no hand-made input on the trial's path",
+ "branch": "claim-untagged-pointer",
+ "branch_url": "https://amadan.net/carlos/platform/-/branch/claim-untagged-pointer",
+ "commits": 6,
+ "docs": [
+ "/docs/cli#boxes-a-region-s-group-launches"
+ ],
+ "credit": [
+ {
+ "person": "Paul Campbell",
+ "agents": [
+ "claude"
+ ]
+ }
+ ]
+ },
+ {
+ "sha": "91a651b3c5a0837445c1a5bc738aafe340928510",
+ "date": "2026-10-18",
+ "subject": "spec: console invite delivery by Keymail federation, then email",
+ "branch": "design-console-invite-delivery",
+ "branch_url": "https://amadan.net/carlos/platform/-/branch/design-console-invite-delivery",
+ "commits": 20,
+ "discussions": [
+ {
+ "id": 216,
+ "title": "Mail: a member can adopt another party's verified SES domain; sending-domain claims never expire",
+ "state": "open"
+ },
+ {
+ "id": 250,
+ "title": "Host floor guard: fix these before anyone runs guard-arm (Opus review of Plans 8/8b)",
+ "state": "open"
+ }
+ ],
+ "credit": [
+ {
+ "person": "Paul Campbell",
+ "agents": [
+ "claude"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "tag": "v0.28.3",
+ "date": "2026-10-18",
+ "sha": "50f5b26845fb0a23109078654ec5d59b3723d9c4",
+ "published": true,
+ "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.3",
+ "notes": {
+ "form": "bullets",
+ "sections": [
+ {
+ "title": "",
+ "bullets": [
+ {
+ "md": "**Nothing changes for people using the CLI.**"
+ }
+ ]
+ },
+ {
+ "title": "For operators",
+ "bullets": [
+ {
+ "md": "**Roll the boxes first, then the console.**"
+ },
+ {
+ "md": "**Coming from v0.28.1, read the [v0.28.2 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.28.2) first.** They all still apply."
+ },
+ {
+ "md": "**`carlos system install-channel --policy` prepares a box that is already running for host claims.** It puts the box's current release in both its copies, so the guard can be armed before a floor is published. That replaces the box's rollback copy, and the command says so. Nothing runs it on its own, and host claims stay off.",
+ "branches": [
+ "claim-prev-rehearsal"
+ ],
+ "docs": [
+ "/docs/cli#carlos-system"
+ ]
+ },
+ {
+ "md": "**Every dormant switch stays off.** Leave `CARLOS_SWAP`, `CARLOS_MOVES_PHASE1`, `CARLOS_HOST_CLAIM`, `CARLOS_HOST_CLAIM_ORIGINS`, `CARLOS_HOST_CLAIM_RETIRED_LOCATIONS`, `CARLOS_CONSOLE_ID`, `CARLOS_REGION_HA`, `CONSOLE_APP_REGIONS`, `CARLOS_TEMPORARY_APPS` and `CARLOS_REQUIRE_POINTER_DIGEST` unset, don't put `CARLOS_BOX_REFERENCE=group` in any host.env, and don't run `carlos channels digests on`.",
+ "docs": [
+ "/docs/cli#carlos-channels-digests"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "changes": [
+ {
+ "sha": "50f5b26845fb0a23109078654ec5d59b3723d9c4",
+ "date": "2026-10-18",
+ "subject": "claim-prev-rehearsal: install-channel --policy arms an updater-installed box; the activation witness starts from a box the platform made and rehearses steps 6 and 7",
+ "branch": "claim-prev-rehearsal",
+ "branch_url": "https://amadan.net/carlos/platform/-/branch/claim-prev-rehearsal",
+ "commits": 7,
+ "docs": [
+ "/docs/cli#boxes-a-region-s-group-launches"
+ ],
+ "credit": [
+ {
+ "person": "Paul Campbell",
+ "agents": [
+ "claude"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "tag": "v0.28.2",
+ "date": "2026-10-18",
+ "sha": "7c1beb2da18da1a659e57a4514aee8abe2146d2d",
+ "published": true,
+ "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.2",
+ "notes": {
+ "form": "bullets",
+ "sections": [
+ {
+ "title": "",
+ "bullets": [
+ {
+ "md": "**Nothing changes for people using the CLI.**"
+ }
+ ]
+ },
+ {
+ "title": "For operators",
+ "bullets": [
+ {
+ "md": "**Roll the boxes first, then the console.**"
+ },
+ {
+ "md": "**Coming from v0.28.0, read the [v0.28.1 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.28.1) first.** They all still apply."
+ },
+ {
+ "md": "**Three new `carlos system claims` commands prepare a box for host claims.** `run` gains two phases, `sign-policy` and `publish-identity`, which make the files `carlos system guard-arm` needs, and `install-console` puts a protected copy of the console where the guard expects it. Nothing runs them on its own, and host claims stay off.",
+ "branches": [
+ "claim-step6-artifacts"
+ ],
+ "docs": [
+ "/docs/cli#carlos-system-claims",
+ "/docs/cli#carlos-system"
+ ]
+ },
+ {
+ "md": "**Every dormant switch stays off.** Leave `CARLOS_SWAP`, `CARLOS_MOVES_PHASE1`, `CARLOS_HOST_CLAIM`, `CARLOS_HOST_CLAIM_ORIGINS`, `CARLOS_HOST_CLAIM_RETIRED_LOCATIONS`, `CARLOS_CONSOLE_ID`, `CARLOS_REGION_HA`, `CONSOLE_APP_REGIONS`, `CARLOS_TEMPORARY_APPS` and `CARLOS_REQUIRE_POINTER_DIGEST` unset, don't put `CARLOS_BOX_REFERENCE=group` in any host.env, and don't run `carlos channels digests on`.",
+ "docs": [
+ "/docs/cli#carlos-channels-digests"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "changes": [
+ {
+ "sha": "7c1beb2da18da1a659e57a4514aee8abe2146d2d",
+ "date": "2026-10-18",
+ "subject": "claim-step6-artifacts: claims run sign-policy and publish-identity, --out byte-exact files, claims install-console (dev cohort-1 trial step 6)",
+ "branch": "claim-step6-artifacts",
+ "branch_url": "https://amadan.net/carlos/platform/-/branch/claim-step6-artifacts",
+ "commits": 9,
+ "docs": [
+ "/docs/cli#carlos-system-claims"
+ ],
+ "credit": [
+ {
+ "person": "Paul Campbell",
+ "agents": [
+ "claude"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "tag": "v0.28.1",
+ "date": "2026-10-18",
+ "sha": "3b69c2bd60edaecb04771d4cd85792e326010cc0",
+ "published": true,
+ "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.1",
+ "notes": {
+ "form": "bullets",
+ "sections": [
+ {
+ "title": "",
+ "bullets": [
+ {
+ "md": "**Nothing changes for people using the CLI.**"
+ }
+ ]
+ },
+ {
+ "title": "For operators",
+ "bullets": [
+ {
+ "md": "**Roll the boxes first, then the console.**"
+ },
+ {
+ "md": "**Coming from v0.27.x, read the [v0.28.0 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.28.0) first.** They all still apply."
+ },
+ {
+ "md": "**A box can publish its identity record by hand.** `systemd-run --wait --pipe -p EnvironmentFile=/etc/carlos/host.env -p User=carlos /opt/carlos/carlos system box publish-record` writes the box's AWS-signed identity record to the deployment bucket once. It never replaces or deletes a record, and it refuses to run as root or on a fleet box. Nothing runs it on its own.",
+ "branches": [
+ "box-publish-record"
+ ]
+ },
+ {
+ "md": "**A box that has not reported for a day drops out of status.** `carlos status --live`, the console's box list and the promote list leave out a box whose report has not been written for 24 hours. Before, it stayed in the list as stale. Fleet boxes are listed as before.",
+ "branches": [
+ "region-ha-2b-build"
+ ],
+ "docs": [
+ "/docs/cli#carlos-status"
+ ]
+ },
+ {
+ "md": "**Each box gets an idle join unit.** `carlos-system-join.path` is installed and enabled at the roll. Nothing touches the file it watches until region HA is turned on, so it never starts its service.",
+ "branches": [
+ "region-ha-2b-build"
+ ]
+ },
+ {
+ "md": "**Every dormant switch stays off.** Leave `CARLOS_SWAP`, `CARLOS_MOVES_PHASE1`, `CARLOS_HOST_CLAIM`, `CARLOS_HOST_CLAIM_ORIGINS`, `CARLOS_HOST_CLAIM_RETIRED_LOCATIONS`, `CARLOS_CONSOLE_ID`, `CARLOS_REGION_HA`, `CONSOLE_APP_REGIONS`, `CARLOS_TEMPORARY_APPS` and `CARLOS_REQUIRE_POINTER_DIGEST` unset, don't put `CARLOS_BOX_REFERENCE=group` in any host.env, and don't run `carlos channels digests on`.",
+ "docs": [
+ "/docs/cli#carlos-channels-digests"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "changes": [
+ {
+ "sha": "3b69c2bd60edaecb04771d4cd85792e326010cc0",
+ "date": "2026-10-18",
+ "subject": "box-publish-record",
+ "branch": "box-publish-record",
+ "branch_url": "https://amadan.net/carlos/platform/-/branch/box-publish-record",
+ "commits": 1,
+ "docs": [
+ "/docs/cli#a-box-s-identity-record"
+ ],
+ "credit": [
+ {
+ "person": "Paul Campbell",
+ "agents": [
+ "claude"
+ ]
+ }
+ ]
+ },
+ {
+ "sha": "b11189254fcf542ba99a428e63742c0aa81f069e",
+ "date": "2026-10-18",
+ "subject": "region HA 2b: the joining and enrolment plan and its copy record",
+ "branch": "region-ha-2b-build",
+ "branch_url": "https://amadan.net/carlos/platform/-/branch/region-ha-2b-build",
+ "commits": 32,
+ "discussions": [
+ {
+ "id": 275,
+ "title": "carlos binary doubled to 74.5 MB: the EC2 SDK client via internal/awsinv",
+ "state": "closed"
+ }
+ ],
+ "docs": [
+ "/docs/cli#boxes-a-region-s-group-launches"
+ ],
+ "credit": [
+ {
+ "person": "Paul Campbell",
+ "agents": [
+ "claude"
+ ]
+ }
+ ]
+ },
+ {
+ "sha": "04819f9b42ed6767d816bdfecd53490407ee20bb",
+ "date": "2026-10-17",
+ "subject": "changelog-v0.28.0: release step 10 for v0.28.0, plus the darwin/windows vet fix for claimunit_inputs_test.go",
+ "branch": "changelog-v0.28.0",
+ "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-v0.28.0",
+ "commits": 2,
+ "credit": [
+ {
+ "person": "Paul Campbell",
+ "agents": [
+ "claude"
+ ]
+ }
+ ]
+ }
+ ]
+ },
{
"tag": "v0.28.0",
"date": "2026-10-17",
diff --git a/docs/site/people.json b/docs/site/people.json
index 918907637..ded9bed1e 100644
--- a/docs/site/people.json
+++ b/docs/site/people.json
@@ -3,6 +3,7 @@
"paul@tito.io": "Paul Campbell",
"paul@rslw.com": "Paul Campbell",
"paul@keymail.dev": "Paul Campbell",
+ "paulmartinbernardcampbell@gmail.com": "Paul Campbell",
"bill@tito.io": "Bill Horsman",
"bill@logicalcobwebs.com": "Bill Horsman",
"bill@keymail.dev": "Bill Horsman",