carlos / platform Public
File too large to show in full — download it above (showing a truncated preview below).
| 1 | { |
| 2 | "//": "Generated by go run ./cmd/changelog from git, the published release notes and Amadan. Do not edit; regenerate.", |
| 3 | "repo": "https://amadan.net/carlos/platform", |
| 4 | "releases": [ |
| 5 | { |
| 6 | "tag": "v0.28.7", |
| 7 | "date": "2026-10-21", |
| 8 | "sha": "771ca01b6be00cec299a8e265c34136daa1fe0d1", |
| 9 | "published": true, |
| 10 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.7", |
| 11 | "notes": { |
| 12 | "form": "bullets", |
| 13 | "sections": [ |
| 14 | { |
| 15 | "title": "", |
| 16 | "bullets": [ |
| 17 | { |
| 18 | "md": "**`carlos logs` now shows each run.** It shows when each `carlos run` started, who asked for it and how it ended. The command's output is not kept there.", |
| 19 | "branches": [ |
| 20 | "run-lifecycle-logs-325" |
| 21 | ], |
| 22 | "docs": [ |
| 23 | "/docs/cli#carlos-logs", |
| 24 | "/docs/cli#carlos-run" |
| 25 | ] |
| 26 | }, |
| 27 | { |
| 28 | "md": "**An app can ask for one uploaded object to be scanned.** Where scanning is enabled for the deployment and an operator has granted the store, the app requests a scan with an app-scoped `service` credential and polls for the result, or receives a signed callback. See [Receiving scan results](https://carlosframework.com/docs/scan-callbacks).", |
| 29 | "branches": [ |
| 30 | "scan-demand-revival" |
| 31 | ] |
| 32 | }, |
| 33 | { |
| 34 | "md": "**The console's account switcher has a search box.** It helps when you belong to many accounts.", |
| 35 | "branches": [ |
| 36 | "console-switcher-filter" |
| 37 | ] |
| 38 | } |
| 39 | ] |
| 40 | }, |
| 41 | { |
| 42 | "title": "For operators", |
| 43 | "bullets": [ |
| 44 | { |
| 45 | "md": "**Roll the boxes first, then the console.** Coming from v0.28.4, read the [v0.28.5 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.28.5) first. Coming from v0.28.5, upgrade the console with `carlos system claims install-console --upgrade` as the [v0.28.6 notes](https://github.com/carlosframework/releases/releases/tag/v0.28.6) describe.", |
| 46 | "docs": [ |
| 47 | "/docs/cli#carlos-system-claims" |
| 48 | ] |
| 49 | }, |
| 50 | { |
| 51 | "md": "**An offline move can copy most of its data before the instance goes offline.** Run `carlos move offline stage --host <host> --to <region>` while the instance keeps serving. It copies the instance's replica to the target region, and running it again copies only what is new. `start` then takes the instance offline as before, and the seal copies only what changed since the last stage. Until `start`, `abort` removes the staged copy and the instance is never offline. While a move is staged, the instance refuses `carlos run` and deletion, and no other instance can move offline.", |
| 52 | "branches": [ |
| 53 | "moves-offline-precopy" |
| 54 | ], |
| 55 | "docs": [ |
| 56 | "/docs/cli#carlos-move", |
| 57 | "/docs/cli#carlos-run" |
| 58 | ] |
| 59 | }, |
| 60 | { |
| 61 | "md": "**Every box in both regions must run this release before `stage` works.** Each box now publishes `offline-stage-1`, and `stage` refuses while any box in either region lacks it.", |
| 62 | "branches": [ |
| 63 | "moves-offline-precopy" |
| 64 | ] |
| 65 | }, |
| 66 | { |
| 67 | "md": "**Moves and replica copies now run eight object copies at once.** Before, they copied one object at a time, so a large replica took minutes to copy while the instance was offline.", |
| 68 | "branches": [ |
| 69 | "moves-offline-precopy" |
| 70 | ] |
| 71 | }, |
| 72 | { |
| 73 | "md": "**On-demand scanning needs `CARLOS_SCAN_WEBHOOK_KEY` only for callbacks.** Polling works without it. To rotate it, keep the old key in `CARLOS_SCAN_WEBHOOK_KEY_PREVIOUS` and run `carlos system antivirus rotate-webhook-key`. Apps whose delivered secret changes restart.", |
| 74 | "branches": [ |
| 75 | "scan-demand-revival" |
| 76 | ], |
| 77 | "docs": [ |
| 78 | "/docs/cli#carlos-system" |
| 79 | ] |
| 80 | }, |
| 81 | { |
| 82 | "md": "**Every dormant switch stays off.** Leave `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`, `CARLOS_REQUIRE_POINTER_DIGEST` and `CARLOS_PLAN_CATALOG` unset, don't put `CARLOS_BOX_REFERENCE=group` in any host.env, and don't run `carlos channels digests on`. Keep `CARLOS_SWAP` as it is: a box armed for zero-downtime deploys stays armed.", |
| 83 | "docs": [ |
| 84 | "/docs/cli#carlos-channels-digests" |
| 85 | ] |
| 86 | } |
| 87 | ] |
| 88 | } |
| 89 | ] |
| 90 | }, |
| 91 | "changes": [ |
| 92 | { |
| 93 | "sha": "771ca01b6be00cec299a8e265c34136daa1fe0d1", |
| 94 | "date": "2026-10-21", |
| 95 | "subject": "moves-offline-precopy: carlos move offline stage (pre-copy while serving) and parallel mirror copies", |
| 96 | "branch": "moves-offline-precopy", |
| 97 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-offline-precopy", |
| 98 | "commits": 10, |
| 99 | "docs": [ |
| 100 | "/docs/cli#carlos-move" |
| 101 | ], |
| 102 | "credit": [ |
| 103 | { |
| 104 | "person": "Paul Campbell", |
| 105 | "agents": [ |
| 106 | "claude" |
| 107 | ] |
| 108 | } |
| 109 | ] |
| 110 | }, |
| 111 | { |
| 112 | "sha": "f550afa21b8098460cbcf0bac2cac6748e52b802", |
| 113 | "date": "2026-10-21", |
| 114 | "subject": "spec: plans, caps and packs for the first paid launch (draft)", |
| 115 | "branch": "design-plans-and-caps", |
| 116 | "branch_url": "https://amadan.net/carlos/platform/-/branch/design-plans-and-caps", |
| 117 | "commits": 15, |
| 118 | "discussions": [ |
| 119 | { |
| 120 | "id": 280, |
| 121 | "title": "Root trusts service-writable hostguard and health records under /data (claim root paths)", |
| 122 | "state": "open" |
| 123 | } |
| 124 | ], |
| 125 | "docs": [ |
| 126 | "/docs/cli#carlos-accounts-plan", |
| 127 | "/docs/plans#turning-plans-on", |
| 128 | "/docs/plans#the-catalog", |
| 129 | "/docs/plans#assigning-a-plan", |
| 130 | "/docs/plans#sponsored-accounts" |
| 131 | ], |
| 132 | "credit": [ |
| 133 | { |
| 134 | "person": "Paul Campbell", |
| 135 | "agents": [ |
| 136 | "claude" |
| 137 | ] |
| 138 | } |
| 139 | ] |
| 140 | }, |
| 141 | { |
| 142 | "sha": "aaa6a9498092d0e24910991127b45a9b21cdf7b4", |
| 143 | "date": "2026-10-21", |
| 144 | "subject": "root tests: the carlos binary is built once per test run, not once per test", |
| 145 | "branch": "test-suite-speed", |
| 146 | "branch_url": "https://amadan.net/carlos/platform/-/branch/test-suite-speed", |
| 147 | "commits": 3, |
| 148 | "discussions": [ |
| 149 | { |
| 150 | "id": 291, |
| 151 | "title": "Test suite speed: where the CI gate's 375 seconds go, and a ranked plan", |
| 152 | "state": "open" |
| 153 | } |
| 154 | ], |
| 155 | "credit": [ |
| 156 | { |
| 157 | "person": "Paul Campbell", |
| 158 | "agents": [ |
| 159 | "claude" |
| 160 | ] |
| 161 | } |
| 162 | ] |
| 163 | }, |
| 164 | { |
| 165 | "sha": "512baa591dc275b5b3a01a353d6993fb19509a0b", |
| 166 | "date": "2026-10-21", |
| 167 | "subject": "Prompts:", |
| 168 | "branch": "test-suite-debt", |
| 169 | "branch_url": "https://amadan.net/carlos/platform/-/branch/test-suite-debt", |
| 170 | "commits": 4, |
| 171 | "discussions": [ |
| 172 | { |
| 173 | "id": 226, |
| 174 | "title": "Root package tests read the operator's real ~/.carlos/config (TestShipVerbAPIMode aborts the package)", |
| 175 | "state": "open" |
| 176 | }, |
| 177 | { |
| 178 | "id": 258, |
| 179 | "title": "Root CLI tests read the operator's real ~/.carlos/config when TMPDIR is under HOME", |
| 180 | "state": "open" |
| 181 | }, |
| 182 | { |
| 183 | "id": 263, |
| 184 | "title": "Hibernating instances: keep 7 days of snapshot history like awake ones", |
| 185 | "state": "closed" |
| 186 | }, |
| 187 | { |
| 188 | "id": 266, |
| 189 | "title": "Flaky: sim/litestreamfacts TestGate_AnchoredLineageThroughStore under load", |
| 190 | "state": "open" |
| 191 | }, |
| 192 | { |
| 193 | "id": 274, |
| 194 | "title": "Flaky CI test: stopevidence TestFDIdentityFindsAHardLinkHeldByAChild", |
| 195 | "state": "open" |
| 196 | } |
| 197 | ], |
| 198 | "credit": [ |
| 199 | { |
| 200 | "person": "Paul Campbell", |
| 201 | "agents": [ |
| 202 | "claude" |
| 203 | ] |
| 204 | } |
| 205 | ] |
| 206 | }, |
| 207 | { |
| 208 | "sha": "f54aa2fc50b8481b9ba4b6bfe09a21bc7c7172e2", |
| 209 | "date": "2026-10-21", |
| 210 | "subject": "carlos run: a run's start and end reach carlos logs (#325)", |
| 211 | "branch": "run-lifecycle-logs-325", |
| 212 | "branch_url": "https://amadan.net/carlos/platform/-/branch/run-lifecycle-logs-325", |
| 213 | "commits": 5, |
| 214 | "discussions": [ |
| 215 | { |
| 216 | "id": 325, |
| 217 | "title": "Run a one-off command with one instance's delivered config (carlos exec)", |
| 218 | "state": "closed" |
| 219 | } |
| 220 | ], |
| 221 | "docs": [ |
| 222 | "/docs/cli#carlos-run" |
| 223 | ], |
| 224 | "credit": [ |
| 225 | { |
| 226 | "person": "Paul Campbell", |
| 227 | "agents": [ |
| 228 | "claude" |
| 229 | ] |
| 230 | } |
| 231 | ] |
| 232 | }, |
| 233 | { |
| 234 | "sha": "3d444a1b63c6e853527292cd8845f1347fdbb544", |
| 235 | "date": "2026-10-21", |
| 236 | "subject": "Merge reviewed on-demand object scanning revival", |
| 237 | "branch": "scan-demand-revival", |
| 238 | "branch_url": "https://amadan.net/carlos/platform/-/branch/scan-demand-revival", |
| 239 | "commits": 1, |
| 240 | "docs": [ |
| 241 | "/docs/cli#carlos-store-scan", |
| 242 | "/docs/cli#deployment-wide-object-scanning", |
| 243 | "/docs/scan-callbacks#asking-for-a-scan", |
| 244 | "/docs/scan-callbacks#the-states", |
| 245 | "/docs/scan-callbacks#callbacks-take-a-path" |
| 246 | ], |
| 247 | "credit": [ |
| 248 | { |
| 249 | "person": "Paul Campbell", |
| 250 | "agents": [ |
| 251 | "claude" |
| 252 | ] |
| 253 | } |
| 254 | ] |
| 255 | }, |
| 256 | { |
| 257 | "sha": "ce8c425ae5930e1c2807018bde1880b93b0947cd", |
| 258 | "date": "2026-10-20", |
| 259 | "subject": "console: searchable, scrolling account switcher", |
| 260 | "branch": "console-switcher-filter", |
| 261 | "branch_url": "https://amadan.net/carlos/platform/-/branch/console-switcher-filter", |
| 262 | "commits": 2, |
| 263 | "discussions": [ |
| 264 | { |
| 265 | "id": 280, |
| 266 | "title": "Root trusts service-writable hostguard and health records under /data (claim root paths)", |
| 267 | "state": "open" |
| 268 | } |
| 269 | ], |
| 270 | "credit": [ |
| 271 | { |
| 272 | "person": "Paul Campbell", |
| 273 | "agents": [ |
| 274 | "claude" |
| 275 | ] |
| 276 | } |
| 277 | ] |
| 278 | } |
| 279 | ] |
| 280 | }, |
| 281 | { |
| 282 | "tag": "v0.28.6", |
| 283 | "date": "2026-10-20", |
| 284 | "sha": "e0986eabc5bc2a7ae5e17e58b19c9a6b92beecfe", |
| 285 | "published": true, |
| 286 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.6", |
| 287 | "notes": { |
| 288 | "form": "bullets", |
| 289 | "sections": [ |
| 290 | { |
| 291 | "title": "", |
| 292 | "bullets": [ |
| 293 | { |
| 294 | "md": "**Nothing changes for people deploying apps with the CLI.**" |
| 295 | } |
| 296 | ] |
| 297 | }, |
| 298 | { |
| 299 | "title": "For operators", |
| 300 | "bullets": [ |
| 301 | { |
| 302 | "md": "**Roll the boxes first, then the console.**" |
| 303 | }, |
| 304 | { |
| 305 | "md": "**Coming from v0.28.4, read the [v0.28.5 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.28.5) first.** They all still apply, including the one update by hand for a box whose guard is armed on v0.28.4." |
| 306 | }, |
| 307 | { |
| 308 | "md": "**A guard-armed box's protected console can now be replaced.** Once the box's router is on this release, run `carlos system claims install-console --upgrade --from <sha256>` as root, where the sha256 is the console that is running now. It refuses unless that build is what the box holds, then installs the new console and keeps the old one as `console.prev`. No hand recovery is needed. A box upgraded this way can't be armed again with `carlos system guard-arm` until `install-console` has been run without `--upgrade`, because `guard-arm` expects both copies to be the same build.", |
| 309 | "branches": [ |
| 310 | "install-console-upgrade" |
| 311 | ], |
| 312 | "docs": [ |
| 313 | "/docs/cli#carlos-system-claims", |
| 314 | "/docs/cli#carlos-system" |
| 315 | ] |
| 316 | }, |
| 317 | { |
| 318 | "md": "**A nested instance's `config.env` is written as soon as its directory appears.** Before, a move could leave the instance without it for up to an hour.", |
| 319 | "branches": [ |
| 320 | "moves-offline-fixes" |
| 321 | ] |
| 322 | }, |
| 323 | { |
| 324 | "md": "**Each offline move step now sees a current box report.** While a move is running, the source boxes and the sealing box report again every 15 seconds. A move takes under a minute of downtime when its steps run back to back. A step that meets a stale report now says the report is not current and to try again. Before, `flip` could answer that a process was still running.", |
| 325 | "branches": [ |
| 326 | "moves-offline-fixes" |
| 327 | ] |
| 328 | }, |
| 329 | { |
| 330 | "md": "**A source box's scheduler leaves a moved instance alone.** After `open`, it no longer writes a stray token file into the instance it gave up.", |
| 331 | "branches": [ |
| 332 | "moves-offline-fixes" |
| 333 | ] |
| 334 | }, |
| 335 | { |
| 336 | "md": "**Every dormant switch stays off.** Leave `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`. Keep `CARLOS_SWAP` as it is: a box armed for zero-downtime deploys stays armed.", |
| 337 | "docs": [ |
| 338 | "/docs/cli#carlos-channels-digests" |
| 339 | ] |
| 340 | } |
| 341 | ] |
| 342 | } |
| 343 | ] |
| 344 | }, |
| 345 | "changes": [ |
| 346 | { |
| 347 | "sha": "e0986eabc5bc2a7ae5e17e58b19c9a6b92beecfe", |
| 348 | "date": "2026-10-20", |
| 349 | "subject": "moves-offline-fixes: harness Run 9 defects. Config sync writes a nested row's config.env as soon as its instance directory appears, keeping it pending until delivered (6); each offline door step sees a current report: source boxes and the sealer refresh reports every 15 s while a move is active without renewing the tombstone, and a stale report answers MV-O178 (7); a source box's scheduler leaves a held or moved host alone, excluding it before the batch limit (8). Astra reviewed (two rounds); census-ruling-moves-offline-fixes (platform-1c); MV-O178 approved by Paul.", |
| 350 | "branch": "moves-offline-fixes", |
| 351 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-offline-fixes", |
| 352 | "commits": 9, |
| 353 | "credit": [ |
| 354 | { |
| 355 | "person": "Paul Campbell", |
| 356 | "agents": [ |
| 357 | "claude" |
| 358 | ] |
| 359 | } |
| 360 | ] |
| 361 | }, |
| 362 | { |
| 363 | "sha": "2185035698a1111c487651bddb1bf2500cd92ccc", |
| 364 | "date": "2026-10-20", |
| 365 | "subject": "install-console --upgrade --from <sha256>: replace a guard-armed box's protected console", |
| 366 | "branch": "install-console-upgrade", |
| 367 | "branch_url": "https://amadan.net/carlos/platform/-/branch/install-console-upgrade", |
| 368 | "commits": 4, |
| 369 | "docs": [ |
| 370 | "/docs/cli#carlos-system-claims" |
| 371 | ], |
| 372 | "credit": [ |
| 373 | { |
| 374 | "person": "Paul Campbell", |
| 375 | "agents": [ |
| 376 | "claude" |
| 377 | ] |
| 378 | } |
| 379 | ] |
| 380 | } |
| 381 | ] |
| 382 | }, |
| 383 | { |
| 384 | "tag": "v0.28.5", |
| 385 | "date": "2026-10-20", |
| 386 | "sha": "54ae7fb93820f37f123bbdcbcb57f4f2efb25dc9", |
| 387 | "published": true, |
| 388 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.5", |
| 389 | "notes": { |
| 390 | "form": "bullets", |
| 391 | "sections": [ |
| 392 | { |
| 393 | "title": "", |
| 394 | "bullets": [ |
| 395 | { |
| 396 | "md": "**Nothing changes for people deploying apps with the CLI.**" |
| 397 | } |
| 398 | ] |
| 399 | }, |
| 400 | { |
| 401 | "title": "For operators", |
| 402 | "bullets": [ |
| 403 | { |
| 404 | "md": "**Roll the boxes first, then the console.**" |
| 405 | }, |
| 406 | { |
| 407 | "md": "**Coming from v0.28.3, read the [v0.28.4 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.28.4) first.** They all still apply." |
| 408 | }, |
| 409 | { |
| 410 | "md": "**`carlos move offline` moves one instance to another region, with planned downtime.** It is for operators, works only while host claims and Phase 1 moves are off, and takes one step per command: `start`, `seal`, `flip`, `open`, then `finish`. The instance is offline from `start` until `open`. Until `open`, `abort` puts it back where it was with nothing lost.", |
| 411 | "branches": [ |
| 412 | "moves-offline" |
| 413 | ], |
| 414 | "docs": [ |
| 415 | "/docs/cli#carlos-move" |
| 416 | ] |
| 417 | }, |
| 418 | { |
| 419 | "md": "**Roll every box in both regions before you start an offline move.** `seal` waits until every box in the instance's current region has stopped it and said so, and a box on an earlier release never says so.", |
| 420 | "branches": [ |
| 421 | "moves-offline" |
| 422 | ] |
| 423 | }, |
| 424 | { |
| 425 | "md": "**A box whose guard is armed on v0.28.4 needs one update by hand.** Its updater reads a candidate's progress messages as part of the answer, so `carlos system update` refuses every candidate on that box. Stop `carlos-system-update.path`, put the v0.28.5 binary in a root-only file after checking it against `SHA256SUMS.txt`, run it as root as `system apply` with the box's `host.env`, check the box, then start `carlos-system-update.path` again. Do one box at a time. From then on the box updates as usual.", |
| 426 | "branches": [ |
| 427 | "armed-box-updates" |
| 428 | ], |
| 429 | "docs": [ |
| 430 | "/docs/cli#carlos-system" |
| 431 | ] |
| 432 | }, |
| 433 | { |
| 434 | "md": "**The guarded updater reads only what a candidate writes to standard output.** Progress and warnings no longer break its checks, so this is the last update a guard-armed box needs by hand.", |
| 435 | "branches": [ |
| 436 | "armed-box-updates" |
| 437 | ] |
| 438 | }, |
| 439 | { |
| 440 | "md": "**`carlos system guard-arm` makes its directories readable whatever your umask is.** Before, a root shell with a strict umask left them unreadable to the box's updater.", |
| 441 | "branches": [ |
| 442 | "claim-guard-umask" |
| 443 | ], |
| 444 | "docs": [ |
| 445 | "/docs/cli#carlos-system" |
| 446 | ] |
| 447 | }, |
| 448 | { |
| 449 | "md": "**Routes with their own unit now restart on boxes whose agent doesn't run as root.** The agent now hands those restarts to root. Before, the restart was refused, the agent read that as a broken build and rolled back.", |
| 450 | "branches": [ |
| 451 | "adopt-unit-root-pass-315" |
| 452 | ] |
| 453 | }, |
| 454 | { |
| 455 | "md": "**`carlos system status` warns when a new box would boot an older build.** It compares `bootstrap/carlos` with stable's build and says which file to copy over it.", |
| 456 | "branches": [ |
| 457 | "bootstrap-carlos-follows-316" |
| 458 | ], |
| 459 | "docs": [ |
| 460 | "/docs/cli#carlos-system" |
| 461 | ] |
| 462 | }, |
| 463 | { |
| 464 | "md": "**Every dormant switch stays off.** Leave `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`. Keep `CARLOS_SWAP` as it is: a box armed for zero-downtime deploys stays armed.", |
| 465 | "docs": [ |
| 466 | "/docs/cli#carlos-channels-digests" |
| 467 | ] |
| 468 | } |
| 469 | ] |
| 470 | } |
| 471 | ] |
| 472 | }, |
| 473 | "changes": [ |
| 474 | { |
| 475 | "sha": "54ae7fb93820f37f123bbdcbcb57f4f2efb25dc9", |
| 476 | "date": "2026-10-20", |
| 477 | "subject": "armed-box-updates: guard-armed boxes can take a release by the ruled re-arm. Cherry-picks 8376a468 (rootaws: an inherited disabled sentinel is not an override) and 8a313548 (hostfloor: a guarded run returns stdout only) from claim-empty-cohort-done, Astra-reviewed there; census-ruling-claim-rootaws-sentinel, confirmed for main by platform-1c. For v0.28.5.", |
| 478 | "branch": "armed-box-updates", |
| 479 | "branch_url": "https://amadan.net/carlos/platform/-/branch/armed-box-updates", |
| 480 | "commits": 3, |
| 481 | "credit": [ |
| 482 | { |
| 483 | "person": "Paul Campbell", |
| 484 | "agents": [ |
| 485 | "claude" |
| 486 | ] |
| 487 | } |
| 488 | ] |
| 489 | }, |
| 490 | { |
| 491 | "sha": "7af881553052fb0b1a26308f49e446df5bcf71be", |
| 492 | "date": "2026-10-20", |
| 493 | "subject": "moves-offline: operator-run offline region move (claims-off, planned downtime): holds and fences every source box, seals the source with a create-only tombstone after a final checkpoint, lands every dependency on the target proven against an immutable seal.json, opens, then retires the source by rename. Reviewed task by task and by Fable and Astra; census-ruling-moves-offline; copy approved by Paul 2026-10-20. Dormant until an operator runs carlos move offline.", |
| 494 | "branch": "moves-offline", |
| 495 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-offline", |
| 496 | "commits": 40, |
| 497 | "docs": [ |
| 498 | "/docs/cli#carlos-move" |
| 499 | ], |
| 500 | "credit": [ |
| 501 | { |
| 502 | "person": "Paul Campbell", |
| 503 | "agents": [ |
| 504 | "claude" |
| 505 | ] |
| 506 | } |
| 507 | ] |
| 508 | }, |
| 509 | { |
| 510 | "sha": "57569bfffa089b9e0ac9c61b9d6f1a03ccf4fc97", |
| 511 | "date": "2026-10-20", |
| 512 | "subject": "changelog-v0.28.4: release step 10 for v0.28.1 to v0.28.4", |
| 513 | "branch": "changelog-v0.28.4", |
| 514 | "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-v0.28.4", |
| 515 | "commits": 1, |
| 516 | "credit": [ |
| 517 | { |
| 518 | "person": "Paul Campbell", |
| 519 | "agents": [ |
| 520 | "claude" |
| 521 | ] |
| 522 | } |
| 523 | ] |
| 524 | }, |
| 525 | { |
| 526 | "sha": "cd2dd6e1a3f208b31932d28721bfa0eedb7e7a76", |
| 527 | "date": "2026-10-20", |
| 528 | "subject": "system status: say when bootstrap/carlos is not stable's build (#316)", |
| 529 | "branch": "bootstrap-carlos-follows-316", |
| 530 | "branch_url": "https://amadan.net/carlos/platform/-/branch/bootstrap-carlos-follows-316", |
| 531 | "commits": 2, |
| 532 | "discussions": [ |
| 533 | { |
| 534 | "id": 280, |
| 535 | "title": "Root trusts service-writable hostguard and health records under /data (claim root paths)", |
| 536 | "state": "open" |
| 537 | }, |
| 538 | { |
| 539 | "id": 316, |
| 540 | "title": "Keep bootstrap/carlos in step with the fleet: system update mirrors releases but new boxes still boot a stale binary", |
| 541 | "state": "open" |
| 542 | } |
| 543 | ], |
| 544 | "credit": [ |
| 545 | { |
| 546 | "person": "Paul Campbell", |
| 547 | "agents": [ |
| 548 | "claude" |
| 549 | ] |
| 550 | } |
| 551 | ] |
| 552 | }, |
| 553 | { |
| 554 | "sha": "d7a5b8eb640535f54dd7e0380eda59e9bcc6c2c6", |
| 555 | "date": "2026-10-20", |
| 556 | "subject": "adopt: an agent that is not root hands named-unit routes to root's pass (#315)", |
| 557 | "branch": "adopt-unit-root-pass-315", |
| 558 | "branch_url": "https://amadan.net/carlos/platform/-/branch/adopt-unit-root-pass-315", |
| 559 | "commits": 3, |
| 560 | "discussions": [ |
| 561 | { |
| 562 | "id": 280, |
| 563 | "title": "Root trusts service-writable hostguard and health records under /data (claim root paths)", |
| 564 | "state": "open" |
| 565 | }, |
| 566 | { |
| 567 | "id": 315, |
| 568 | "title": "Agent's in-process adopt rolls back a console update when it can't restart console.service itself (\"Interactive authentication required\")", |
| 569 | "state": "closed" |
| 570 | } |
| 571 | ], |
| 572 | "credit": [ |
| 573 | { |
| 574 | "person": "Paul Campbell", |
| 575 | "agents": [ |
| 576 | "claude" |
| 577 | ] |
| 578 | } |
| 579 | ] |
| 580 | }, |
| 581 | { |
| 582 | "sha": "96db0efe4a0dc94f26cc8e01d5ed8c5c07e3296a", |
| 583 | "date": "2026-10-19", |
| 584 | "subject": "claim-guard-umask: guard-arm makes its guard, system and lock directories 0755 whatever the caller's umask (#317)", |
| 585 | "branch": "claim-guard-umask", |
| 586 | "branch_url": "https://amadan.net/carlos/platform/-/branch/claim-guard-umask", |
| 587 | "commits": 2, |
| 588 | "discussions": [ |
| 589 | { |
| 590 | "id": 317, |
| 591 | "title": "guard-arm's directories inherit the caller's umask: umask 077 broke the guarded console (exit 203)", |
| 592 | "state": "open" |
| 593 | } |
| 594 | ], |
| 595 | "credit": [ |
| 596 | { |
| 597 | "person": "Paul Campbell", |
| 598 | "agents": [ |
| 599 | "claude" |
| 600 | ] |
| 601 | } |
| 602 | ] |
| 603 | } |
| 604 | ] |
| 605 | }, |
| 606 | { |
| 607 | "tag": "v0.28.4", |
| 608 | "date": "2026-10-18", |
| 609 | "sha": "f3bf1214ab92a47ecb626400e7bd1b35cd7a112c", |
| 610 | "published": true, |
| 611 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.4", |
| 612 | "notes": { |
| 613 | "form": "bullets", |
| 614 | "sections": [ |
| 615 | { |
| 616 | "title": "", |
| 617 | "bullets": [ |
| 618 | { |
| 619 | "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.", |
| 620 | "branches": [ |
| 621 | "design-console-invite-delivery" |
| 622 | ] |
| 623 | }, |
| 624 | { |
| 625 | "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.", |
| 626 | "branches": [ |
| 627 | "design-console-invite-delivery" |
| 628 | ] |
| 629 | }, |
| 630 | { |
| 631 | "md": "**Nothing changes in the CLI.**" |
| 632 | } |
| 633 | ] |
| 634 | }, |
| 635 | { |
| 636 | "title": "For operators", |
| 637 | "bullets": [ |
| 638 | { |
| 639 | "md": "**Roll the boxes first, then the console.**" |
| 640 | }, |
| 641 | { |
| 642 | "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." |
| 643 | }, |
| 644 | { |
| 645 | "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.", |
| 646 | "branches": [ |
| 647 | "design-console-invite-delivery" |
| 648 | ] |
| 649 | }, |
| 650 | { |
| 651 | "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.", |
| 652 | "branches": [ |
| 653 | "design-console-invite-delivery" |
| 654 | ] |
| 655 | }, |
| 656 | { |
| 657 | "md": "**With `CARLOS_HOST_CLAIM` on, the console sends no email.** Invites then go by Keymail, or the owner passes the link on.", |
| 658 | "branches": [ |
| 659 | "design-console-invite-delivery" |
| 660 | ] |
| 661 | }, |
| 662 | { |
| 663 | "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.", |
| 664 | "branches": [ |
| 665 | "claim-untagged-pointer" |
| 666 | ], |
| 667 | "docs": [ |
| 668 | "/docs/cli#carlos-system" |
| 669 | ] |
| 670 | }, |
| 671 | { |
| 672 | "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`.", |
| 673 | "docs": [ |
| 674 | "/docs/cli#carlos-channels-digests" |
| 675 | ] |
| 676 | } |
| 677 | ] |
| 678 | } |
| 679 | ] |
| 680 | }, |
| 681 | "changes": [ |
| 682 | { |
| 683 | "sha": "f3bf1214ab92a47ecb626400e7bd1b35cd7a112c", |
| 684 | "date": "2026-10-18", |
| 685 | "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", |
| 686 | "branch": "claim-untagged-pointer", |
| 687 | "branch_url": "https://amadan.net/carlos/platform/-/branch/claim-untagged-pointer", |
| 688 | "commits": 6, |
| 689 | "docs": [ |
| 690 | "/docs/cli#boxes-a-region-s-group-launches" |
| 691 | ], |
| 692 | "credit": [ |
| 693 | { |
| 694 | "person": "Paul Campbell", |
| 695 | "agents": [ |
| 696 | "claude" |
| 697 | ] |
| 698 | } |
| 699 | ] |
| 700 | }, |
| 701 | { |
| 702 | "sha": "91a651b3c5a0837445c1a5bc738aafe340928510", |
| 703 | "date": "2026-10-18", |
| 704 | "subject": "spec: console invite delivery by Keymail federation, then email", |
| 705 | "branch": "design-console-invite-delivery", |
| 706 | "branch_url": "https://amadan.net/carlos/platform/-/branch/design-console-invite-delivery", |
| 707 | "commits": 20, |
| 708 | "discussions": [ |
| 709 | { |
| 710 | "id": 216, |
| 711 | "title": "Mail: a member can adopt another party's verified SES domain; sending-domain claims never expire", |
| 712 | "state": "open" |
| 713 | }, |
| 714 | { |
| 715 | "id": 250, |
| 716 | "title": "Host floor guard: fix these before anyone runs guard-arm (Opus review of Plans 8/8b)", |
| 717 | "state": "open" |
| 718 | } |
| 719 | ], |
| 720 | "credit": [ |
| 721 | { |
| 722 | "person": "Paul Campbell", |
| 723 | "agents": [ |
| 724 | "claude" |
| 725 | ] |
| 726 | } |
| 727 | ] |
| 728 | } |
| 729 | ] |
| 730 | }, |
| 731 | { |
| 732 | "tag": "v0.28.3", |
| 733 | "date": "2026-10-18", |
| 734 | "sha": "50f5b26845fb0a23109078654ec5d59b3723d9c4", |
| 735 | "published": true, |
| 736 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.3", |
| 737 | "notes": { |
| 738 | "form": "bullets", |
| 739 | "sections": [ |
| 740 | { |
| 741 | "title": "", |
| 742 | "bullets": [ |
| 743 | { |
| 744 | "md": "**Nothing changes for people using the CLI.**" |
| 745 | } |
| 746 | ] |
| 747 | }, |
| 748 | { |
| 749 | "title": "For operators", |
| 750 | "bullets": [ |
| 751 | { |
| 752 | "md": "**Roll the boxes first, then the console.**" |
| 753 | }, |
| 754 | { |
| 755 | "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." |
| 756 | }, |
| 757 | { |
| 758 | "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.", |
| 759 | "branches": [ |
| 760 | "claim-prev-rehearsal" |
| 761 | ], |
| 762 | "docs": [ |
| 763 | "/docs/cli#carlos-system" |
| 764 | ] |
| 765 | }, |
| 766 | { |
| 767 | "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`.", |
| 768 | "docs": [ |
| 769 | "/docs/cli#carlos-channels-digests" |
| 770 | ] |
| 771 | } |
| 772 | ] |
| 773 | } |
| 774 | ] |
| 775 | }, |
| 776 | "changes": [ |
| 777 | { |
| 778 | "sha": "50f5b26845fb0a23109078654ec5d59b3723d9c4", |
| 779 | "date": "2026-10-18", |
| 780 | "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", |
| 781 | "branch": "claim-prev-rehearsal", |
| 782 | "branch_url": "https://amadan.net/carlos/platform/-/branch/claim-prev-rehearsal", |
| 783 | "commits": 7, |
| 784 | "docs": [ |
| 785 | "/docs/cli#boxes-a-region-s-group-launches" |
| 786 | ], |
| 787 | "credit": [ |
| 788 | { |
| 789 | "person": "Paul Campbell", |
| 790 | "agents": [ |
| 791 | "claude" |
| 792 | ] |
| 793 | } |
| 794 | ] |
| 795 | } |
| 796 | ] |
| 797 | }, |
| 798 | { |
| 799 | "tag": "v0.28.2", |
| 800 | "date": "2026-10-18", |
| 801 | "sha": "7c1beb2da18da1a659e57a4514aee8abe2146d2d", |
| 802 | "published": true, |
| 803 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.2", |
| 804 | "notes": { |
| 805 | "form": "bullets", |
| 806 | "sections": [ |
| 807 | { |
| 808 | "title": "", |
| 809 | "bullets": [ |
| 810 | { |
| 811 | "md": "**Nothing changes for people using the CLI.**" |
| 812 | } |
| 813 | ] |
| 814 | }, |
| 815 | { |
| 816 | "title": "For operators", |
| 817 | "bullets": [ |
| 818 | { |
| 819 | "md": "**Roll the boxes first, then the console.**" |
| 820 | }, |
| 821 | { |
| 822 | "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." |
| 823 | }, |
| 824 | { |
| 825 | "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.", |
| 826 | "branches": [ |
| 827 | "claim-step6-artifacts" |
| 828 | ], |
| 829 | "docs": [ |
| 830 | "/docs/cli#carlos-system-claims", |
| 831 | "/docs/cli#carlos-system" |
| 832 | ] |
| 833 | }, |
| 834 | { |
| 835 | "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`.", |
| 836 | "docs": [ |
| 837 | "/docs/cli#carlos-channels-digests" |
| 838 | ] |
| 839 | } |
| 840 | ] |
| 841 | } |
| 842 | ] |
| 843 | }, |
| 844 | "changes": [ |
| 845 | { |
| 846 | "sha": "7c1beb2da18da1a659e57a4514aee8abe2146d2d", |
| 847 | "date": "2026-10-18", |
| 848 | "subject": "claim-step6-artifacts: claims run sign-policy and publish-identity, --out byte-exact files, claims install-console (dev cohort-1 trial step 6)", |
| 849 | "branch": "claim-step6-artifacts", |
| 850 | "branch_url": "https://amadan.net/carlos/platform/-/branch/claim-step6-artifacts", |
| 851 | "commits": 9, |
| 852 | "docs": [ |
| 853 | "/docs/cli#carlos-system-claims" |
| 854 | ], |
| 855 | "credit": [ |
| 856 | { |
| 857 | "person": "Paul Campbell", |
| 858 | "agents": [ |
| 859 | "claude" |
| 860 | ] |
| 861 | } |
| 862 | ] |
| 863 | } |
| 864 | ] |
| 865 | }, |
| 866 | { |
| 867 | "tag": "v0.28.1", |
| 868 | "date": "2026-10-18", |
| 869 | "sha": "3b69c2bd60edaecb04771d4cd85792e326010cc0", |
| 870 | "published": true, |
| 871 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.1", |
| 872 | "notes": { |
| 873 | "form": "bullets", |
| 874 | "sections": [ |
| 875 | { |
| 876 | "title": "", |
| 877 | "bullets": [ |
| 878 | { |
| 879 | "md": "**Nothing changes for people using the CLI.**" |
| 880 | } |
| 881 | ] |
| 882 | }, |
| 883 | { |
| 884 | "title": "For operators", |
| 885 | "bullets": [ |
| 886 | { |
| 887 | "md": "**Roll the boxes first, then the console.**" |
| 888 | }, |
| 889 | { |
| 890 | "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." |
| 891 | }, |
| 892 | { |
| 893 | "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.", |
| 894 | "branches": [ |
| 895 | "box-publish-record" |
| 896 | ] |
| 897 | }, |
| 898 | { |
| 899 | "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.", |
| 900 | "branches": [ |
| 901 | "region-ha-2b-build" |
| 902 | ], |
| 903 | "docs": [ |
| 904 | "/docs/cli#carlos-status" |
| 905 | ] |
| 906 | }, |
| 907 | { |
| 908 | "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.", |
| 909 | "branches": [ |
| 910 | "region-ha-2b-build" |
| 911 | ] |
| 912 | }, |
| 913 | { |
| 914 | "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`.", |
| 915 | "docs": [ |
| 916 | "/docs/cli#carlos-channels-digests" |
| 917 | ] |
| 918 | } |
| 919 | ] |
| 920 | } |
| 921 | ] |
| 922 | }, |
| 923 | "changes": [ |
| 924 | { |
| 925 | "sha": "3b69c2bd60edaecb04771d4cd85792e326010cc0", |
| 926 | "date": "2026-10-18", |
| 927 | "subject": "box-publish-record", |
| 928 | "branch": "box-publish-record", |
| 929 | "branch_url": "https://amadan.net/carlos/platform/-/branch/box-publish-record", |
| 930 | "commits": 1, |
| 931 | "docs": [ |
| 932 | "/docs/cli#a-box-s-identity-record" |
| 933 | ], |
| 934 | "credit": [ |
| 935 | { |
| 936 | "person": "Paul Campbell", |
| 937 | "agents": [ |
| 938 | "claude" |
| 939 | ] |
| 940 | } |
| 941 | ] |
| 942 | }, |
| 943 | { |
| 944 | "sha": "b11189254fcf542ba99a428e63742c0aa81f069e", |
| 945 | "date": "2026-10-18", |
| 946 | "subject": "region HA 2b: the joining and enrolment plan and its copy record", |
| 947 | "branch": "region-ha-2b-build", |
| 948 | "branch_url": "https://amadan.net/carlos/platform/-/branch/region-ha-2b-build", |
| 949 | "commits": 32, |
| 950 | "discussions": [ |
| 951 | { |
| 952 | "id": 275, |
| 953 | "title": "carlos binary doubled to 74.5 MB: the EC2 SDK client via internal/awsinv", |
| 954 | "state": "closed" |
| 955 | } |
| 956 | ], |
| 957 | "docs": [ |
| 958 | "/docs/cli#boxes-a-region-s-group-launches" |
| 959 | ], |
| 960 | "credit": [ |
| 961 | { |
| 962 | "person": "Paul Campbell", |
| 963 | "agents": [ |
| 964 | "claude" |
| 965 | ] |
| 966 | } |
| 967 | ] |
| 968 | }, |
| 969 | { |
| 970 | "sha": "04819f9b42ed6767d816bdfecd53490407ee20bb", |
| 971 | "date": "2026-10-17", |
| 972 | "subject": "changelog-v0.28.0: release step 10 for v0.28.0, plus the darwin/windows vet fix for claimunit_inputs_test.go", |
| 973 | "branch": "changelog-v0.28.0", |
| 974 | "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-v0.28.0", |
| 975 | "commits": 2, |
| 976 | "credit": [ |
| 977 | { |
| 978 | "person": "Paul Campbell", |
| 979 | "agents": [ |
| 980 | "claude" |
| 981 | ] |
| 982 | } |
| 983 | ] |
| 984 | } |
| 985 | ] |
| 986 | }, |
| 987 | { |
| 988 | "tag": "v0.28.0", |
| 989 | "date": "2026-10-17", |
| 990 | "sha": "260653783857088d6ba940101191c599974f8caa", |
| 991 | "published": true, |
| 992 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.28.0", |
| 993 | "notes": { |
| 994 | "form": "bullets", |
| 995 | "sections": [ |
| 996 | { |
| 997 | "title": "", |
| 998 | "bullets": [ |
| 999 | { |
| 1000 | "md": "**`carlos run` runs one of your app's commands against one instance.** `carlos run --app shop --instance www.example.com -- <command>` runs it as that instance, with its environment and database, and prints the output as it arrives. `--file` uploads files with the run, up to 64 MB in total. `--timeout` sets how long it may take, 30 minutes by default and up to 6 hours. `--follow <id>` reattaches to a run already started. It needs an instance on the nested layout.", |
| 1001 | "branches": [ |
| 1002 | "carlos-run" |
| 1003 | ], |
| 1004 | "docs": [ |
| 1005 | "/docs/cli#carlos-run" |
| 1006 | ] |
| 1007 | }, |
| 1008 | { |
| 1009 | "md": "**New instances can start from a copy of another instance's database.** `carlos instances create --from <host>` copies the source's replica, so the source keeps serving. `carlos instances import` brings an instance the platform never ran onto it, from a snapshot of its database. Both refuse until your operator turns them on.", |
| 1010 | "branches": [ |
| 1011 | "seeded-instances" |
| 1012 | ], |
| 1013 | "docs": [ |
| 1014 | "/docs/cli#carlos-instances" |
| 1015 | ] |
| 1016 | }, |
| 1017 | { |
| 1018 | "md": "**The download is smaller again.** The linux/arm64 binary is about 46 MB, down from about 78 MB.", |
| 1019 | "branches": [ |
| 1020 | "fix-binary-size-275" |
| 1021 | ] |
| 1022 | }, |
| 1023 | { |
| 1024 | "md": "**Nothing else changes for people using the CLI.**" |
| 1025 | } |
| 1026 | ] |
| 1027 | }, |
| 1028 | { |
| 1029 | "title": "For operators", |
| 1030 | "bullets": [ |
| 1031 | { |
| 1032 | "md": "**Roll the boxes first, then every console.** A run is refused until the console that records it is on this release.", |
| 1033 | "branches": [ |
| 1034 | "carlos-run" |
| 1035 | ] |
| 1036 | }, |
| 1037 | { |
| 1038 | "md": "**Coming from v0.26.x, read the [v0.27.0](https://github.com/carlosframework/releases/releases/tag/v0.27.0) to [v0.27.3](https://github.com/carlosframework/releases/releases/tag/v0.27.3) operator notes first.** They all still apply." |
| 1039 | }, |
| 1040 | { |
| 1041 | "md": "**Instance control restarts with this update.** `carlos system update` does that on its own. A box updated any other way needs `systemctl restart carlos-instance-control` afterwards.", |
| 1042 | "docs": [ |
| 1043 | "/docs/cli#carlos-system" |
| 1044 | ] |
| 1045 | }, |
| 1046 | { |
| 1047 | "md": "**Give the console room for run uploads.** The console holds a run's uploaded files, up to 64 MB per run, in its temporary directory until the box takes them.", |
| 1048 | "branches": [ |
| 1049 | "carlos-run" |
| 1050 | ] |
| 1051 | }, |
| 1052 | { |
| 1053 | "md": "**Seeded instances stay off until you publish the seeds floor.** `carlos instances create --from` and `carlos instances import` refuse until `carlos system seeds-floor publish` names a release every box runs. Publishing it is one way: from then on no box recovers to an older build. Leave it unpublished until you have decided to turn seeding on.", |
| 1054 | "branches": [ |
| 1055 | "seeded-instances" |
| 1056 | ], |
| 1057 | "docs": [ |
| 1058 | "/docs/cli#carlos-instances", |
| 1059 | "/docs/cli#carlos-system" |
| 1060 | ] |
| 1061 | }, |
| 1062 | { |
| 1063 | "md": "**The host claim is still off.** This release carries the claim's protected host state and the `carlos system claims` activation commands, but nothing uses them while `CARLOS_HOST_CLAIM` is unset. Errors from a route that has no app are now filed so the claim's checks can read the bucket.", |
| 1064 | "branches": [ |
| 1065 | "feat/claim-root-trusted-state-p3", |
| 1066 | "feat/claim-files-backfill" |
| 1067 | ], |
| 1068 | "docs": [ |
| 1069 | "/docs/cli#carlos-system-claims" |
| 1070 | ] |
| 1071 | }, |
| 1072 | { |
| 1073 | "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, and don't run `carlos channels digests on`.", |
| 1074 | "docs": [ |
| 1075 | "/docs/cli#carlos-channels-digests" |
| 1076 | ] |
| 1077 | } |
| 1078 | ] |
| 1079 | } |
| 1080 | ] |
| 1081 | }, |
| 1082 | "changes": [ |
| 1083 | { |
| 1084 | "sha": "260653783857088d6ba940101191c599974f8caa", |
| 1085 | "date": "2026-10-17", |
| 1086 | "subject": "WIP claim Plan 14 foundations (not for merge): descriptor-backed root state, root-owned D3 health history, release lock, floor reconstruction and migration preflight helpers, constructor census, root-read census with the legacy freeze", |
| 1087 | "branch": "feat/claim-root-trusted-state-p3", |
| 1088 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fclaim-root-trusted-state-p3", |
| 1089 | "commits": 102, |
| 1090 | "docs": [ |
| 1091 | "/docs/cli#carlos-proof-history", |
| 1092 | "/docs/cli#carlos-system-claims" |
| 1093 | ], |
| 1094 | "credit": [ |
| 1095 | { |
| 1096 | "person": "Paul Campbell", |
| 1097 | "agents": [ |
| 1098 | "claude", |
| 1099 | "codex" |
| 1100 | ] |
| 1101 | } |
| 1102 | ] |
| 1103 | }, |
| 1104 | { |
| 1105 | "sha": "6834659c9f0d5453051902c72ca24539562cd010", |
| 1106 | "date": "2026-10-16", |
| 1107 | "subject": "region HA spec 2 (two-box regions), rev 1 draft, and its Astra brief", |
| 1108 | "branch": "region-ha-2a-build", |
| 1109 | "branch_url": "https://amadan.net/carlos/platform/-/branch/region-ha-2a-build", |
| 1110 | "commits": 63, |
| 1111 | "discussions": [ |
| 1112 | { |
| 1113 | "id": 299, |
| 1114 | "title": "Provider-neutral box identity, so multi-box regions work without AWS", |
| 1115 | "state": "open" |
| 1116 | } |
| 1117 | ], |
| 1118 | "docs": [ |
| 1119 | "/docs/cli#box-and-group-roles" |
| 1120 | ], |
| 1121 | "credit": [ |
| 1122 | { |
| 1123 | "person": "Paul Campbell", |
| 1124 | "agents": [ |
| 1125 | "claude" |
| 1126 | ] |
| 1127 | } |
| 1128 | ] |
| 1129 | }, |
| 1130 | { |
| 1131 | "sha": "e8e961dd423f03399ec7922f3cd7100defb0af62", |
| 1132 | "date": "2026-10-16", |
| 1133 | "subject": "fix-empty-app-key", |
| 1134 | "branch": "fix-empty-app-key", |
| 1135 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-empty-app-key", |
| 1136 | "commits": 1, |
| 1137 | "credit": [ |
| 1138 | { |
| 1139 | "person": "Paul Campbell", |
| 1140 | "agents": [ |
| 1141 | "claude" |
| 1142 | ] |
| 1143 | } |
| 1144 | ] |
| 1145 | }, |
| 1146 | { |
| 1147 | "sha": "e963691d5571fcca926a454d7c485657681c4fcc", |
| 1148 | "date": "2026-10-16", |
| 1149 | "subject": "runbook-home2-sha", |
| 1150 | "branch": "runbook-home2-sha", |
| 1151 | "branch_url": "https://amadan.net/carlos/platform/-/branch/runbook-home2-sha", |
| 1152 | "commits": 1, |
| 1153 | "credit": [ |
| 1154 | { |
| 1155 | "person": "Paul Campbell", |
| 1156 | "agents": [ |
| 1157 | "claude" |
| 1158 | ] |
| 1159 | } |
| 1160 | ] |
| 1161 | }, |
| 1162 | { |
| 1163 | "sha": "a89e35caaf969492d10d93c556a2ef303f2bc679", |
| 1164 | "date": "2026-10-16", |
| 1165 | "subject": "moves-home-part2-plan", |
| 1166 | "branch": "moves-home-part2-plan", |
| 1167 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-home-part2-plan", |
| 1168 | "commits": 1, |
| 1169 | "credit": [ |
| 1170 | { |
| 1171 | "person": "Paul Campbell", |
| 1172 | "agents": [ |
| 1173 | "claude" |
| 1174 | ] |
| 1175 | } |
| 1176 | ] |
| 1177 | }, |
| 1178 | { |
| 1179 | "sha": "ee35dee27b68a2280d69d4954154e67e75f699bd", |
| 1180 | "date": "2026-10-16", |
| 1181 | "subject": "Prompts:", |
| 1182 | "branch": "feat/claim-files-backfill", |
| 1183 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fclaim-files-backfill", |
| 1184 | "commits": 32, |
| 1185 | "discussions": [ |
| 1186 | { |
| 1187 | "id": 250, |
| 1188 | "title": "Host floor guard: fix these before anyone runs guard-arm (Opus review of Plans 8/8b)", |
| 1189 | "state": "open" |
| 1190 | } |
| 1191 | ], |
| 1192 | "credit": [ |
| 1193 | { |
| 1194 | "person": "Paul Campbell", |
| 1195 | "agents": [ |
| 1196 | "claude" |
| 1197 | ] |
| 1198 | } |
| 1199 | ] |
| 1200 | }, |
| 1201 | { |
| 1202 | "sha": "70e57449fc8d8106e8e5ef729cc5df85f84ad7be", |
| 1203 | "date": "2026-10-15", |
| 1204 | "subject": "moves-overcap-cut", |
| 1205 | "branch": "moves-overcap-cut", |
| 1206 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-overcap-cut", |
| 1207 | "commits": 1, |
| 1208 | "credit": [ |
| 1209 | { |
| 1210 | "person": "Paul Campbell", |
| 1211 | "agents": [ |
| 1212 | "claude" |
| 1213 | ] |
| 1214 | } |
| 1215 | ] |
| 1216 | }, |
| 1217 | { |
| 1218 | "sha": "a5003aba7b1786e96073d6d23438a40c042c3c03", |
| 1219 | "date": "2026-10-15", |
| 1220 | "subject": "docs-rehearsal-dev-uk-secrets-key", |
| 1221 | "branch": "docs-rehearsal-dev-uk-secrets-key", |
| 1222 | "branch_url": "https://amadan.net/carlos/platform/-/branch/docs-rehearsal-dev-uk-secrets-key", |
| 1223 | "commits": 1, |
| 1224 | "credit": [ |
| 1225 | { |
| 1226 | "person": "Paul Campbell", |
| 1227 | "agents": [ |
| 1228 | "claude" |
| 1229 | ] |
| 1230 | } |
| 1231 | ] |
| 1232 | }, |
| 1233 | { |
| 1234 | "sha": "9f17062aec02421b8c0eb540650754cac778a637", |
| 1235 | "date": "2026-10-15", |
| 1236 | "subject": "docs-rehearsal-dev-uk-bootstrap", |
| 1237 | "branch": "docs-rehearsal-dev-uk-bootstrap", |
| 1238 | "branch_url": "https://amadan.net/carlos/platform/-/branch/docs-rehearsal-dev-uk-bootstrap", |
| 1239 | "commits": 1, |
| 1240 | "credit": [ |
| 1241 | { |
| 1242 | "person": "Paul Campbell", |
| 1243 | "agents": [ |
| 1244 | "claude" |
| 1245 | ] |
| 1246 | } |
| 1247 | ] |
| 1248 | }, |
| 1249 | { |
| 1250 | "sha": "5f4ace8b841036f273b10ce0eb26430e85a83db0", |
| 1251 | "date": "2026-10-15", |
| 1252 | "subject": "hostfiles: the path cap applies to live entries only (LiveEntriesWithinCap), so a manifest written before the cap that holds a tombstone or skipped entry past it stays readable, and a moves recovery that selects it is not stranded (#236, moves' review of a8cebad)", |
| 1253 | "branch": "hostfiles-cap-live-entries", |
| 1254 | "branch_url": "https://amadan.net/carlos/platform/-/branch/hostfiles-cap-live-entries", |
| 1255 | "commits": 16, |
| 1256 | "discussions": [ |
| 1257 | { |
| 1258 | "id": 236, |
| 1259 | "title": "Host claim Plan 8: three decisions for Paul (floor release, declare-lost attestation, actor roster)", |
| 1260 | "state": "open" |
| 1261 | }, |
| 1262 | { |
| 1263 | "id": 250, |
| 1264 | "title": "Host floor guard: fix these before anyone runs guard-arm (Opus review of Plans 8/8b)", |
| 1265 | "state": "open" |
| 1266 | } |
| 1267 | ], |
| 1268 | "credit": [ |
| 1269 | { |
| 1270 | "person": "Paul Campbell", |
| 1271 | "agents": [ |
| 1272 | "claude" |
| 1273 | ] |
| 1274 | } |
| 1275 | ] |
| 1276 | }, |
| 1277 | { |
| 1278 | "sha": "f97898f1224f08f7da5ee4e12d9f39ce04b083a6", |
| 1279 | "date": "2026-10-15", |
| 1280 | "subject": "copy gate: the seeded-instances deck, pinned (Plan 1 Task 1)", |
| 1281 | "branch": "seeded-instances", |
| 1282 | "branch_url": "https://amadan.net/carlos/platform/-/branch/seeded-instances", |
| 1283 | "commits": 96, |
| 1284 | "discussions": [ |
| 1285 | { |
| 1286 | "id": 292, |
| 1287 | "title": "Edge restart: the stopping agent recycles an instance and strands its lease for 15 minutes", |
| 1288 | "state": "closed" |
| 1289 | } |
| 1290 | ], |
| 1291 | "docs": [ |
| 1292 | "/docs/cli#carlos-instances", |
| 1293 | "/docs/cli#the-seeds-floor", |
| 1294 | "/docs/cli#legacy-route-assignments" |
| 1295 | ], |
| 1296 | "credit": [ |
| 1297 | { |
| 1298 | "person": "Paul Campbell", |
| 1299 | "agents": [ |
| 1300 | "claude" |
| 1301 | ] |
| 1302 | } |
| 1303 | ] |
| 1304 | }, |
| 1305 | { |
| 1306 | "sha": "37ab10c5fe5937d6b9699cc158669bdb3dc3a1a9", |
| 1307 | "date": "2026-10-15", |
| 1308 | "subject": "specs: carlos run (#259) and instances seeded from a database (#260, #261)", |
| 1309 | "branch": "carlos-run", |
| 1310 | "branch_url": "https://amadan.net/carlos/platform/-/branch/carlos-run", |
| 1311 | "commits": 73, |
| 1312 | "discussions": [ |
| 1313 | { |
| 1314 | "id": 259, |
| 1315 | "title": "carlos run: a member runs an app command against one instance, without root on the box", |
| 1316 | "state": "open" |
| 1317 | }, |
| 1318 | { |
| 1319 | "id": 260, |
| 1320 | "title": "carlos instances create --from <host>: a new instance seeded from another's replica copy (same app, same account)", |
| 1321 | "state": "open" |
| 1322 | }, |
| 1323 | { |
| 1324 | "id": 261, |
| 1325 | "title": "Schedule the adoption door (instance-moves §9, G9) after the nested-layout rollout: every controld titogo instance converts to platform-run", |
| 1326 | "state": "open" |
| 1327 | }, |
| 1328 | { |
| 1329 | "id": 280, |
| 1330 | "title": "Root trusts service-writable hostguard and health records under /data (claim root paths)", |
| 1331 | "state": "open" |
| 1332 | }, |
| 1333 | { |
| 1334 | "id": 294, |
| 1335 | "title": "carlos run: the cmd role is outside #292's start/stop fence in instance control", |
| 1336 | "state": "open" |
| 1337 | } |
| 1338 | ], |
| 1339 | "docs": [ |
| 1340 | "/docs/cli#carlos-run", |
| 1341 | "/docs/cli#what-an-instance-is-started-with", |
| 1342 | "/docs/cli#carlos-instance-exec", |
| 1343 | "/docs/cli#carlos-instance-exit" |
| 1344 | ], |
| 1345 | "credit": [ |
| 1346 | { |
| 1347 | "person": "Paul Campbell", |
| 1348 | "agents": [ |
| 1349 | "claude" |
| 1350 | ] |
| 1351 | } |
| 1352 | ] |
| 1353 | }, |
| 1354 | { |
| 1355 | "sha": "1c5718f695c72e47bd4a3b13b0abfde49ae765f3", |
| 1356 | "date": "2026-10-15", |
| 1357 | "subject": "activator: write a cold wake's build-state record at its exec (#272)", |
| 1358 | "branch": "zdd-owed-items", |
| 1359 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-owed-items", |
| 1360 | "commits": 6, |
| 1361 | "discussions": [ |
| 1362 | { |
| 1363 | "id": 250, |
| 1364 | "title": "Host floor guard: fix these before anyone runs guard-arm (Opus review of Plans 8/8b)", |
| 1365 | "state": "open" |
| 1366 | }, |
| 1367 | { |
| 1368 | "id": 272, |
| 1369 | "title": "Zero-downtime deploys: owed before CARLOS_SWAP can go on", |
| 1370 | "state": "open" |
| 1371 | }, |
| 1372 | { |
| 1373 | "id": 292, |
| 1374 | "title": "Edge restart: the stopping agent recycles an instance and strands its lease for 15 minutes", |
| 1375 | "state": "closed" |
| 1376 | } |
| 1377 | ], |
| 1378 | "credit": [ |
| 1379 | { |
| 1380 | "person": "Paul Campbell", |
| 1381 | "agents": [ |
| 1382 | "claude" |
| 1383 | ] |
| 1384 | } |
| 1385 | ] |
| 1386 | }, |
| 1387 | { |
| 1388 | "sha": "132cf996ee438fd9760a5920307608559acb9720", |
| 1389 | "date": "2026-10-14", |
| 1390 | "subject": "binary-size-275: store SDK method values, not clients, in interfaces; add a size ceiling", |
| 1391 | "branch": "fix-binary-size-275", |
| 1392 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-binary-size-275", |
| 1393 | "commits": 3, |
| 1394 | "credit": [ |
| 1395 | { |
| 1396 | "person": "Paul Campbell", |
| 1397 | "agents": [ |
| 1398 | "claude" |
| 1399 | ] |
| 1400 | } |
| 1401 | ] |
| 1402 | }, |
| 1403 | { |
| 1404 | "sha": "2683f16acaf7a47124c1140ed53c54fa432e72ea", |
| 1405 | "date": "2026-10-14", |
| 1406 | "subject": "Prompts:", |
| 1407 | "branch": "changelog-v0.27.3", |
| 1408 | "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-v0.27.3", |
| 1409 | "commits": 1, |
| 1410 | "credit": [ |
| 1411 | { |
| 1412 | "person": "Paul Campbell", |
| 1413 | "agents": [ |
| 1414 | "claude" |
| 1415 | ] |
| 1416 | } |
| 1417 | ] |
| 1418 | } |
| 1419 | ] |
| 1420 | }, |
| 1421 | { |
| 1422 | "tag": "v0.27.3", |
| 1423 | "date": "2026-10-14", |
| 1424 | "sha": "e15ad6be618aeea85b19b5b8cab42df6d75a8af8", |
| 1425 | "published": true, |
| 1426 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.27.3", |
| 1427 | "notes": { |
| 1428 | "form": "bullets", |
| 1429 | "sections": [ |
| 1430 | { |
| 1431 | "title": "", |
| 1432 | "bullets": [ |
| 1433 | { |
| 1434 | "md": "**Restarting the edge no longer leaves an instance unreachable for 15 minutes.** If the edge stopped while an instance was waking, the instance could stay locked until its lease expired, and every request to it was refused for up to 15 minutes. The stopping edge now cancels the wake, makes sure it has stopped, and lets the lease go. If it cannot confirm the stop, it keeps the lease, as before.", |
| 1435 | "branches": [ |
| 1436 | "fix-shutdown-lease-292" |
| 1437 | ] |
| 1438 | }, |
| 1439 | { |
| 1440 | "md": "**New accounts never get a reserved address.** An account's address is part of every app's hostname. Account creation now skips any address that spells a name the platform uses itself, such as dev, edge or www. Existing accounts keep theirs.", |
| 1441 | "branches": [ |
| 1442 | "reserved-sqids-285" |
| 1443 | ] |
| 1444 | }, |
| 1445 | { |
| 1446 | "md": "**Nothing else changes for people using the CLI.**" |
| 1447 | } |
| 1448 | ] |
| 1449 | }, |
| 1450 | { |
| 1451 | "title": "For operators", |
| 1452 | "bullets": [ |
| 1453 | { |
| 1454 | "md": "**Roll the boxes first, then the console.**" |
| 1455 | }, |
| 1456 | { |
| 1457 | "md": "**Coming from v0.26.x, read the [v0.27.0](https://github.com/carlosframework/releases/releases/tag/v0.27.0), [v0.27.1](https://github.com/carlosframework/releases/releases/tag/v0.27.1) and [v0.27.2](https://github.com/carlosframework/releases/releases/tag/v0.27.2) operator notes first.** They all still apply." |
| 1458 | }, |
| 1459 | { |
| 1460 | "md": "**Instance control restarts with this update.** This release changes `carlos-instance-control`, so it has to restart on each box. `carlos system update` does that on its own. A box updated any other way needs `systemctl restart carlos-instance-control` afterwards.", |
| 1461 | "branches": [ |
| 1462 | "fix-shutdown-lease-292" |
| 1463 | ], |
| 1464 | "docs": [ |
| 1465 | "/docs/cli#carlos-system" |
| 1466 | ] |
| 1467 | }, |
| 1468 | { |
| 1469 | "md": "**Roll the console as well as the boxes.** Only a console on this release skips reserved account addresses when it creates an account.", |
| 1470 | "branches": [ |
| 1471 | "reserved-sqids-285" |
| 1472 | ] |
| 1473 | }, |
| 1474 | { |
| 1475 | "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, and don't run `carlos channels digests on`. With `CARLOS_HOST_CLAIM` set, instance control now refuses to start until a later release.", |
| 1476 | "docs": [ |
| 1477 | "/docs/cli#carlos-channels-digests" |
| 1478 | ] |
| 1479 | } |
| 1480 | ] |
| 1481 | } |
| 1482 | ] |
| 1483 | }, |
| 1484 | "changes": [ |
| 1485 | { |
| 1486 | "sha": "e15ad6be618aeea85b19b5b8cab42df6d75a8af8", |
| 1487 | "date": "2026-10-14", |
| 1488 | "subject": "activator: Shutdown aborts a waking entry and gives its lease back with swaps off (#292)", |
| 1489 | "branch": "fix-shutdown-lease-292", |
| 1490 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-shutdown-lease-292", |
| 1491 | "commits": 7, |
| 1492 | "discussions": [ |
| 1493 | { |
| 1494 | "id": 272, |
| 1495 | "title": "Zero-downtime deploys: owed before CARLOS_SWAP can go on", |
| 1496 | "state": "open" |
| 1497 | }, |
| 1498 | { |
| 1499 | "id": 292, |
| 1500 | "title": "Edge restart: the stopping agent recycles an instance and strands its lease for 15 minutes", |
| 1501 | "state": "closed" |
| 1502 | } |
| 1503 | ], |
| 1504 | "credit": [ |
| 1505 | { |
| 1506 | "person": "Paul Campbell", |
| 1507 | "agents": [ |
| 1508 | "claude" |
| 1509 | ] |
| 1510 | } |
| 1511 | ] |
| 1512 | }, |
| 1513 | { |
| 1514 | "sha": "fc70bc754dec1c2fe2f04d14d77f716b4180a7df", |
| 1515 | "date": "2026-10-14", |
| 1516 | "subject": "reserved-sqids-285", |
| 1517 | "branch": "reserved-sqids-285", |
| 1518 | "branch_url": "https://amadan.net/carlos/platform/-/branch/reserved-sqids-285", |
| 1519 | "commits": 1, |
| 1520 | "credit": [ |
| 1521 | { |
| 1522 | "person": "Paul Campbell", |
| 1523 | "agents": [ |
| 1524 | "claude" |
| 1525 | ] |
| 1526 | } |
| 1527 | ] |
| 1528 | }, |
| 1529 | { |
| 1530 | "sha": "8b5c75610c0c169d2213f7bb71a68b01b7dda96a", |
| 1531 | "date": "2026-10-14", |
| 1532 | "subject": "changelog-v0.27.x: v0.27.0, v0.27.1 and v0.27.2 (README release step 10)", |
| 1533 | "branch": "changelog-v0.27", |
| 1534 | "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-v0.27", |
| 1535 | "commits": 1, |
| 1536 | "credit": [ |
| 1537 | { |
| 1538 | "person": "Paul Campbell", |
| 1539 | "agents": [ |
| 1540 | "claude" |
| 1541 | ] |
| 1542 | } |
| 1543 | ] |
| 1544 | }, |
| 1545 | { |
| 1546 | "sha": "a3bfa662250917557faed570efcc67c8c788254a", |
| 1547 | "date": "2026-10-14", |
| 1548 | "subject": "rehearsal-p0-two-box", |
| 1549 | "branch": "rehearsal-p0-two-box", |
| 1550 | "branch_url": "https://amadan.net/carlos/platform/-/branch/rehearsal-p0-two-box", |
| 1551 | "commits": 1, |
| 1552 | "credit": [ |
| 1553 | { |
| 1554 | "person": "Paul Campbell", |
| 1555 | "agents": [ |
| 1556 | "claude" |
| 1557 | ] |
| 1558 | } |
| 1559 | ] |
| 1560 | }, |
| 1561 | { |
| 1562 | "sha": "4e577fdef0c840e7868013d936c7471a1fc42d7b", |
| 1563 | "date": "2026-10-14", |
| 1564 | "subject": "readme-roll-order", |
| 1565 | "branch": "readme-roll-order", |
| 1566 | "branch_url": "https://amadan.net/carlos/platform/-/branch/readme-roll-order", |
| 1567 | "commits": 1, |
| 1568 | "credit": [ |
| 1569 | { |
| 1570 | "person": "Paul Campbell", |
| 1571 | "agents": [ |
| 1572 | "claude" |
| 1573 | ] |
| 1574 | } |
| 1575 | ] |
| 1576 | } |
| 1577 | ] |
| 1578 | }, |
| 1579 | { |
| 1580 | "tag": "v0.27.2", |
| 1581 | "date": "2026-10-14", |
| 1582 | "sha": "ebddcfc6f4c55a6239d07faa6b46d3773186327b", |
| 1583 | "published": true, |
| 1584 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.27.2", |
| 1585 | "notes": { |
| 1586 | "form": "bullets", |
| 1587 | "sections": [ |
| 1588 | { |
| 1589 | "title": "", |
| 1590 | "bullets": [ |
| 1591 | { |
| 1592 | "md": "**Two builds at once keeps each build's socket name.** Where a deployment turns on two builds at once, each build's socket now has the same file name it has with the switch off, in a directory of its own. An app that works out its own address from its socket's name now starts the same way either way. Before, such an app saw a different name for the new build and refused to start. Nothing changes where the switch is off, which is every deployment by default.", |
| 1593 | "branches": [ |
| 1594 | "zdd-gen-socket-names" |
| 1595 | ] |
| 1596 | }, |
| 1597 | { |
| 1598 | "md": "**Nothing changes for people using the CLI.**" |
| 1599 | } |
| 1600 | ] |
| 1601 | }, |
| 1602 | { |
| 1603 | "title": "For operators", |
| 1604 | "bullets": [ |
| 1605 | { |
| 1606 | "md": "**Roll the boxes first, then the console.**" |
| 1607 | }, |
| 1608 | { |
| 1609 | "md": "**Coming from v0.26.x, read the [v0.27.0](https://github.com/carlosframework/releases/releases/tag/v0.27.0) and [v0.27.1](https://github.com/carlosframework/releases/releases/tag/v0.27.1) operator notes first.** They all still apply." |
| 1610 | }, |
| 1611 | { |
| 1612 | "md": "**A long host name keeps stop-then-start updates.** With two builds at once on, a host on a flat box whose name is longer than 59 bytes is updated the old way: stopped, then started on the new build. Its socket path would otherwise be too long.", |
| 1613 | "branches": [ |
| 1614 | "zdd-gen-socket-names" |
| 1615 | ] |
| 1616 | }, |
| 1617 | { |
| 1618 | "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, and don't run `carlos channels digests on`. With `CARLOS_HOST_CLAIM` set, instance control now refuses to start until a later release.", |
| 1619 | "docs": [ |
| 1620 | "/docs/cli#carlos-channels-digests" |
| 1621 | ] |
| 1622 | } |
| 1623 | ] |
| 1624 | } |
| 1625 | ] |
| 1626 | }, |
| 1627 | "changes": [ |
| 1628 | { |
| 1629 | "sha": "ebddcfc6f4c55a6239d07faa6b46d3773186327b", |
| 1630 | "date": "2026-10-14", |
| 1631 | "subject": "zdd rev 19 amendment: generation sockets keep the flag-off file name", |
| 1632 | "branch": "zdd-gen-socket-names", |
| 1633 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-gen-socket-names", |
| 1634 | "commits": 5, |
| 1635 | "discussions": [ |
| 1636 | { |
| 1637 | "id": 272, |
| 1638 | "title": "Zero-downtime deploys: owed before CARLOS_SWAP can go on", |
| 1639 | "state": "open" |
| 1640 | } |
| 1641 | ], |
| 1642 | "credit": [ |
| 1643 | { |
| 1644 | "person": "Paul Campbell", |
| 1645 | "agents": [ |
| 1646 | "claude" |
| 1647 | ] |
| 1648 | } |
| 1649 | ] |
| 1650 | }, |
| 1651 | { |
| 1652 | "sha": "d2f58fd330726e461b1022edfc9e4c4688696dd1", |
| 1653 | "date": "2026-10-13", |
| 1654 | "subject": "startup-largebox-test-281", |
| 1655 | "branch": "startup-largebox-test-281", |
| 1656 | "branch_url": "https://amadan.net/carlos/platform/-/branch/startup-largebox-test-281", |
| 1657 | "commits": 1, |
| 1658 | "credit": [ |
| 1659 | { |
| 1660 | "person": "Paul Campbell", |
| 1661 | "agents": [ |
| 1662 | "claude" |
| 1663 | ] |
| 1664 | } |
| 1665 | ] |
| 1666 | }, |
| 1667 | { |
| 1668 | "sha": "21d91fd6087aa1ef7a21f35fc9188b263e3d0529", |
| 1669 | "date": "2026-10-13", |
| 1670 | "subject": "host: rootinventory_test.go is linux-only", |
| 1671 | "branch": "fix-cross-test-compile", |
| 1672 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-cross-test-compile", |
| 1673 | "commits": 1, |
| 1674 | "credit": [ |
| 1675 | { |
| 1676 | "person": "Paul Campbell", |
| 1677 | "agents": [ |
| 1678 | "claude" |
| 1679 | ] |
| 1680 | } |
| 1681 | ] |
| 1682 | } |
| 1683 | ] |
| 1684 | }, |
| 1685 | { |
| 1686 | "tag": "v0.27.1", |
| 1687 | "date": "2026-10-13", |
| 1688 | "sha": "6dfbff103985e1e81899f2e611b1afff0ddb3769", |
| 1689 | "published": true, |
| 1690 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.27.1", |
| 1691 | "notes": { |
| 1692 | "form": "bullets", |
| 1693 | "sections": [ |
| 1694 | { |
| 1695 | "title": "", |
| 1696 | "bullets": [ |
| 1697 | { |
| 1698 | "md": "**A box with many instances no longer fails its update while it starts.** On a box with over a hundred instances, v0.27.0's update could take longer than the 20 seconds it allows, because the edge waited for the agent to check every instance first. The box then rolled back after about 45 seconds of failed requests. The edge now starts serving straight away. Requests for an instance wait up to 30 seconds for that check to finish, then get the usual answer that the instance is waking.", |
| 1699 | "branches": [ |
| 1700 | "hotfix-startup-sweep-281" |
| 1701 | ] |
| 1702 | }, |
| 1703 | { |
| 1704 | "md": "**Nothing changes for people using the CLI.**" |
| 1705 | } |
| 1706 | ] |
| 1707 | }, |
| 1708 | { |
| 1709 | "title": "For operators", |
| 1710 | "bullets": [ |
| 1711 | { |
| 1712 | "md": "**Roll the boxes first, then the console.**" |
| 1713 | }, |
| 1714 | { |
| 1715 | "md": "**Coming from v0.26.x, read the [v0.27.0 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.27.0) first.** They all still apply." |
| 1716 | }, |
| 1717 | { |
| 1718 | "md": "**After each box updates, check that it finished starting.** The update's 20-second check now passes once the edge serves, before the agent has checked every instance. So also check the box's journal for `agent: hibernation activator armed`, and that one request to a sleeping instance succeeds." |
| 1719 | }, |
| 1720 | { |
| 1721 | "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, and don't run `carlos channels digests on`. With `CARLOS_HOST_CLAIM` set, instance control now refuses to start until a later release.", |
| 1722 | "docs": [ |
| 1723 | "/docs/cli#carlos-channels-digests" |
| 1724 | ] |
| 1725 | } |
| 1726 | ] |
| 1727 | } |
| 1728 | ] |
| 1729 | }, |
| 1730 | "changes": [ |
| 1731 | { |
| 1732 | "sha": "6dfbff103985e1e81899f2e611b1afff0ddb3769", |
| 1733 | "date": "2026-10-13", |
| 1734 | "subject": "hotfix #281: the edge no longer waits on the startup sweep and recovery", |
| 1735 | "branch": "hotfix-startup-sweep-281", |
| 1736 | "branch_url": "https://amadan.net/carlos/platform/-/branch/hotfix-startup-sweep-281", |
| 1737 | "commits": 1, |
| 1738 | "discussions": [ |
| 1739 | { |
| 1740 | "id": 281, |
| 1741 | "title": "Agent startup is not bounded under the 20s update gate: sweep and recovery still run before the edge listens", |
| 1742 | "state": "open" |
| 1743 | } |
| 1744 | ], |
| 1745 | "credit": [ |
| 1746 | { |
| 1747 | "person": "Paul Campbell" |
| 1748 | } |
| 1749 | ] |
| 1750 | } |
| 1751 | ] |
| 1752 | }, |
| 1753 | { |
| 1754 | "tag": "v0.27.0", |
| 1755 | "date": "2026-10-13", |
| 1756 | "sha": "f4cf27dd0c48eac32d7b4beaec77686752ca6cff", |
| 1757 | "published": true, |
| 1758 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.27.0", |
| 1759 | "notes": { |
| 1760 | "form": "bullets", |
| 1761 | "sections": [ |
| 1762 | { |
| 1763 | "title": "", |
| 1764 | "bullets": [ |
| 1765 | { |
| 1766 | "md": "**Root keeps its own record of each box's releases.** A box's root process now keeps the builds it has seen run healthy, and the build each service ran before its current one, in directories only root can write. Before, it read them from places the platform's own service could write. Restarts, rollbacks and recovering from a bad build work exactly as they did.", |
| 1767 | "branches": [ |
| 1768 | "feat/claim-root-trusted-state" |
| 1769 | ] |
| 1770 | }, |
| 1771 | { |
| 1772 | "md": "**Nothing changes for people using the CLI.**" |
| 1773 | } |
| 1774 | ] |
| 1775 | }, |
| 1776 | { |
| 1777 | "title": "For operators", |
| 1778 | "bullets": [ |
| 1779 | { |
| 1780 | "md": "**Roll the boxes first, then the console.**" |
| 1781 | }, |
| 1782 | { |
| 1783 | "md": "**Coming from v0.25.x, read the [v0.26.0 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.26.0) and the [v0.26.1 notes](https://github.com/carlosframework/releases/releases/tag/v0.26.1) first.** They all still apply." |
| 1784 | }, |
| 1785 | { |
| 1786 | "md": "**Before rolling, check two things on each box.** `/`, `/var` and `/var/lib` must be owned by root and not writable by group or others, and `/var/lib/carlos-claims` must not exist. If either check fails, root can't update a service that has its own unit, such as the console, on that box, and logs `repoint failed: permission denied` on every pass." |
| 1787 | }, |
| 1788 | { |
| 1789 | "md": "**Health history starts empty.** Root no longer reads the health history the service kept before this release. Don't add a `require` or `prove` entry for a service to `/etc/carlos/proof-policy.json` until both its current build and the one before it have been seen healthy since the roll. Otherwise rolling back to the earlier build waits for a proof." |
| 1790 | }, |
| 1791 | { |
| 1792 | "md": "**One earlier build per service is kept.** `/opt/carlos/previous/<host>` points at the build each service ran before its current one, and the box keeps that build when it prunes old versions. Disk use can grow by up to one build per service." |
| 1793 | }, |
| 1794 | { |
| 1795 | "md": "**`carlos __cgexec` can appear in `ps`.** Each new instance process now starts through a short-lived helper that places it in its cgroup before it runs. For a few milliseconds `ps` can show `carlos __cgexec` as a child of the agent. Monitoring, or a `pkill` that matches \"carlos\" in a command line, can catch it.", |
| 1796 | "branches": [ |
| 1797 | "zdd-flag-readiness-3" |
| 1798 | ] |
| 1799 | }, |
| 1800 | { |
| 1801 | "md": "**After the roll, check placement on each box.** `journalctl -u carlos-edge --since '<roll time>' | grep 'placement before exec failed'` should print nothing. A line there means a process was moved into its cgroup after it started instead. That affects resource accounting, not serving.", |
| 1802 | "branches": [ |
| 1803 | "zdd-flag-readiness-3" |
| 1804 | ] |
| 1805 | }, |
| 1806 | { |
| 1807 | "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, and don't run `carlos channels digests on`. With `CARLOS_HOST_CLAIM` set, instance control now refuses to start until a later release.", |
| 1808 | "docs": [ |
| 1809 | "/docs/cli#carlos-channels-digests" |
| 1810 | ] |
| 1811 | } |
| 1812 | ] |
| 1813 | } |
| 1814 | ] |
| 1815 | }, |
| 1816 | "changes": [ |
| 1817 | { |
| 1818 | "sha": "f4cf27dd0c48eac32d7b4beaec77686752ca6cff", |
| 1819 | "date": "2026-10-13", |
| 1820 | "subject": "changelog: v0.26.1 (release step 10)", |
| 1821 | "branch": "changelog-v0.26.1", |
| 1822 | "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-v0.26.1", |
| 1823 | "commits": 1, |
| 1824 | "credit": [ |
| 1825 | { |
| 1826 | "person": "Paul Campbell", |
| 1827 | "agents": [ |
| 1828 | "claude" |
| 1829 | ] |
| 1830 | } |
| 1831 | ] |
| 1832 | }, |
| 1833 | { |
| 1834 | "sha": "2e00b17e18f49cd391b2c6890f8abd68bbdeba23", |
| 1835 | "date": "2026-10-13", |
| 1836 | "subject": "plan: zdd flag readiness round 3 (draft)", |
| 1837 | "branch": "zdd-flag-readiness-3", |
| 1838 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-flag-readiness-3", |
| 1839 | "commits": 23, |
| 1840 | "discussions": [ |
| 1841 | { |
| 1842 | "id": 272, |
| 1843 | "title": "Zero-downtime deploys: owed before CARLOS_SWAP can go on", |
| 1844 | "state": "open" |
| 1845 | } |
| 1846 | ], |
| 1847 | "credit": [ |
| 1848 | { |
| 1849 | "person": "Paul Campbell", |
| 1850 | "agents": [ |
| 1851 | "claude" |
| 1852 | ] |
| 1853 | } |
| 1854 | ] |
| 1855 | }, |
| 1856 | { |
| 1857 | "sha": "645a7d0541cc77bbf52523f88a901f720ceaf64a", |
| 1858 | "date": "2026-10-13", |
| 1859 | "subject": "claim Plan 14 Part 1 (#280): root-trusted state foundations, families B, C and D", |
| 1860 | "branch": "feat/claim-root-trusted-state", |
| 1861 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fclaim-root-trusted-state", |
| 1862 | "commits": 1, |
| 1863 | "discussions": [ |
| 1864 | { |
| 1865 | "id": 280, |
| 1866 | "title": "Root trusts service-writable hostguard and health records under /data (claim root paths)", |
| 1867 | "state": "open" |
| 1868 | } |
| 1869 | ], |
| 1870 | "credit": [ |
| 1871 | { |
| 1872 | "person": "Paul Campbell", |
| 1873 | "agents": [ |
| 1874 | "codex" |
| 1875 | ] |
| 1876 | } |
| 1877 | ] |
| 1878 | }, |
| 1879 | { |
| 1880 | "sha": "34a4328f7d29cfed7b5404cec39cef616e115a26", |
| 1881 | "date": "2026-10-13", |
| 1882 | "subject": "hotfix-instance-key-gate", |
| 1883 | "branch": "hotfix-instance-key-gate", |
| 1884 | "branch_url": "https://amadan.net/carlos/platform/-/branch/hotfix-instance-key-gate", |
| 1885 | "commits": 1, |
| 1886 | "credit": [ |
| 1887 | { |
| 1888 | "person": "Paul Campbell", |
| 1889 | "agents": [ |
| 1890 | "claude" |
| 1891 | ] |
| 1892 | } |
| 1893 | ] |
| 1894 | }, |
| 1895 | { |
| 1896 | "sha": "ba52d5efe55a4a8a78acaa0af9d500e803aeb4c0", |
| 1897 | "date": "2026-10-13", |
| 1898 | "subject": "plan: zero-downtime flag readiness, round 2 (draft for Astra's review)", |
| 1899 | "branch": "zdd-flag-readiness-2", |
| 1900 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-flag-readiness-2", |
| 1901 | "commits": 48, |
| 1902 | "credit": [ |
| 1903 | { |
| 1904 | "person": "Paul Campbell", |
| 1905 | "agents": [ |
| 1906 | "claude" |
| 1907 | ] |
| 1908 | } |
| 1909 | ] |
| 1910 | }, |
| 1911 | { |
| 1912 | "sha": "67698c9c016e1f34fbb4a337ebc833380d023937", |
| 1913 | "date": "2026-10-13", |
| 1914 | "subject": "changelog-nested-bullets", |
| 1915 | "branch": "changelog-nested-bullets", |
| 1916 | "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-nested-bullets", |
| 1917 | "commits": 1, |
| 1918 | "credit": [ |
| 1919 | { |
| 1920 | "person": "Paul Campbell", |
| 1921 | "agents": [ |
| 1922 | "claude" |
| 1923 | ] |
| 1924 | } |
| 1925 | ] |
| 1926 | }, |
| 1927 | { |
| 1928 | "sha": "729e85080ff0891fc8c622367dc52a5d27823c8a", |
| 1929 | "date": "2026-10-13", |
| 1930 | "subject": "changelog-v0.26.0", |
| 1931 | "branch": "changelog-v0.26.0", |
| 1932 | "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-v0.26.0", |
| 1933 | "commits": 1, |
| 1934 | "credit": [ |
| 1935 | { |
| 1936 | "person": "Paul Campbell", |
| 1937 | "agents": [ |
| 1938 | "claude" |
| 1939 | ] |
| 1940 | } |
| 1941 | ] |
| 1942 | } |
| 1943 | ] |
| 1944 | }, |
| 1945 | { |
| 1946 | "tag": "v0.26.1", |
| 1947 | "date": "2026-10-13", |
| 1948 | "sha": "9aaeace220780db1a844595f2d8f690bf2cba375", |
| 1949 | "published": true, |
| 1950 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.26.1", |
| 1951 | "notes": { |
| 1952 | "form": "bullets", |
| 1953 | "sections": [ |
| 1954 | { |
| 1955 | "title": "", |
| 1956 | "bullets": [ |
| 1957 | { |
| 1958 | "md": "**A box with many instances no longer fails the update.** v0.26.0 gave every instance on a box its key before the edge started, with one bucket read per instance. On a box with over a hundred instances that took longer than the 20 seconds the update allows, so the box rolled back after about half a minute of failed requests. The keys are now written in the background once the edge is serving, and the update no longer waits for them." |
| 1959 | }, |
| 1960 | { |
| 1961 | "md": "**Nothing changes for people using the CLI.**" |
| 1962 | } |
| 1963 | ] |
| 1964 | }, |
| 1965 | { |
| 1966 | "title": "For operators", |
| 1967 | "bullets": [ |
| 1968 | { |
| 1969 | "md": "**Roll the boxes first, then the console.**" |
| 1970 | }, |
| 1971 | { |
| 1972 | "md": "**Coming from v0.25.x, read the [v0.26.0 operator notes](https://github.com/carlosframework/releases/releases/tag/v0.26.0) first.** They all still apply, and that includes any box that rolled back from v0.26.0. Restart `carlos-instance-control.service` on each box after it updates, run the instance key checks before any box rolls, and check what root's AWS settings rely on (#267)." |
| 1973 | }, |
| 1974 | { |
| 1975 | "md": "**Wait for the instance key line.** `agent: instance keys:` now comes after `hibernation activator armed`, up to about a minute after the agent starts. Wait for it before you check for `0 failed`. It also counts rows skipped because a move or a layout change held the host. Those get their key at their next start." |
| 1976 | }, |
| 1977 | { |
| 1978 | "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, and don't run `carlos channels digests on`. The v0.26.0 notes say where each one is set.", |
| 1979 | "docs": [ |
| 1980 | "/docs/cli#carlos-channels-digests" |
| 1981 | ] |
| 1982 | } |
| 1983 | ] |
| 1984 | } |
| 1985 | ] |
| 1986 | }, |
| 1987 | "changes": [ |
| 1988 | { |
| 1989 | "sha": "9aaeace220780db1a844595f2d8f690bf2cba375", |
| 1990 | "date": "2026-10-13", |
| 1991 | "subject": "console test: the layout guard's at-floor update asks for a version the vendor feed can never publish", |
| 1992 | "commits": 1, |
| 1993 | "credit": [ |
| 1994 | { |
| 1995 | "person": "Paul Campbell", |
| 1996 | "agents": [ |
| 1997 | "claude" |
| 1998 | ] |
| 1999 | } |
| 2000 | ] |
| 2001 | }, |
| 2002 | { |
| 2003 | "sha": "b8ddad180a6a9da7553b8e7210c9bc1e8db5e7df", |
| 2004 | "date": "2026-10-13", |
| 2005 | "subject": "agent: run the instance-key backfill after Start, off the edge's path (v0.26.1)", |
| 2006 | "commits": 1, |
| 2007 | "credit": [ |
| 2008 | { |
| 2009 | "person": "Paul Campbell", |
| 2010 | "agents": [ |
| 2011 | "claude" |
| 2012 | ] |
| 2013 | } |
| 2014 | ] |
| 2015 | } |
| 2016 | ] |
| 2017 | }, |
| 2018 | { |
| 2019 | "tag": "v0.26.0", |
| 2020 | "date": "2026-10-13", |
| 2021 | "sha": "09c5a4a5f30690d99a3d5c6ef4af2d8bea99a741", |
| 2022 | "published": true, |
| 2023 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.26.0", |
| 2024 | "notes": { |
| 2025 | "form": "bullets", |
| 2026 | "sections": [ |
| 2027 | { |
| 2028 | "title": "", |
| 2029 | "bullets": [ |
| 2030 | { |
| 2031 | "md": "**Two builds at once, off until your deployment turns it on.** Where it is on, a new build starts beside the old one and takes over once it passes its health check, so no request waits. For a few seconds both builds share the instance's database and its scheduled work, and the new build's migrations run while the old one still serves. So add a column, table or index in one release and drop the old one in a later release. Keep the names of scheduled work (`carlos schedule`) the same across the two builds. A release that can't follow these rules ships with `--swap hold` on `carlos deploy` or `carlos ship`, which stops each instance before its new build starts. `carlos apps set <app> --swap hold` makes that the app's rule, and `--swap-concurrency` sets how many instances swap at once on one box. Every deployment ships with this off.", |
| 2032 | "branches": [ |
| 2033 | "zdd-1-generations", |
| 2034 | "zdd-2-containment", |
| 2035 | "zdd-3-swap", |
| 2036 | "zdd-4-release-side", |
| 2037 | "zdd-5-scheduler", |
| 2038 | "zdd-6-surfaces", |
| 2039 | "zdd-flag-readiness" |
| 2040 | ], |
| 2041 | "docs": [ |
| 2042 | "/docs/cli#carlos-schedule", |
| 2043 | "/docs/cli#carlos-deploy", |
| 2044 | "/docs/cli#carlos-ship", |
| 2045 | "/docs/cli#carlos-apps" |
| 2046 | ] |
| 2047 | }, |
| 2048 | { |
| 2049 | "md": "**`carlos deploy` follows the rollout box by box.** Where a box reports its rollout, deploy counts an awake instance once the new build has passed its health check and taken over, and an asleep one once its box has installed the build. If the build fails on a box, that box stops rolling it out, and deploy names the failure and exits with an error. Boxes report only where two builds at once is on. Everywhere else deploy watches the app's URL, as before. If the console can't list the app's instances, deploy keeps asking until its deadline and then says the list could not be read.", |
| 2050 | "branches": [ |
| 2051 | "zdd-6-surfaces", |
| 2052 | "zdd-flag-readiness" |
| 2053 | ], |
| 2054 | "docs": [ |
| 2055 | "/docs/cli#carlos-deploy" |
| 2056 | ] |
| 2057 | }, |
| 2058 | { |
| 2059 | "md": "**`carlos instances list` shows two builds.** INSTALLED is the build on the instance's box, and SERVING is the one answering its requests. They differ while a build rolls out, while an asleep instance waits for its next request, and after a build has failed on that box. REASON says which. A dash under SERVING means the box doesn't report it, which is every box until two builds at once is on. `carlos instances retry <host>` clears the failure hold on one instance, so the build that failed there is tried again as a canary.", |
| 2060 | "branches": [ |
| 2061 | "zdd-4-release-side", |
| 2062 | "zdd-6-surfaces" |
| 2063 | ], |
| 2064 | "docs": [ |
| 2065 | "/docs/cli#carlos-instances" |
| 2066 | ] |
| 2067 | }, |
| 2068 | { |
| 2069 | "md": "**Choose how each instance takes new builds.** `carlos instances set <host> --updates manual` stops an instance taking new builds on its own. `--channel`, `--major` (stable only) and `--pin <build>` set the rest, and an empty value goes back to the app's default. `carlos instances update <host>` asks the box to install the newest build it considers ready, even with manual updates. `--fast-track` skips the safety delay, and only account owners can use it. On the app, `carlos apps set --instance-control updates,pin` names the settings an instance may change for itself once instances can act for themselves. `--default-updates`, `--default-major` and `--default-channel` set the app's defaults. The console accepts manual updates, a major hold or a pin only once every box can keep the builds they name, and says how many boxes it is waiting for.", |
| 2070 | "branches": [ |
| 2071 | "settings-3-console-settings", |
| 2072 | "settings-4-root-applies", |
| 2073 | "settings-5-surfaces" |
| 2074 | ], |
| 2075 | "docs": [ |
| 2076 | "/docs/cli#carlos-instances-set", |
| 2077 | "/docs/cli#carlos-instances-update", |
| 2078 | "/docs/cli#carlos-apps" |
| 2079 | ] |
| 2080 | }, |
| 2081 | { |
| 2082 | "md": "**Read a database as it was.** `carlos db pull --at <time>` and `carlos db query --at <time>` read an instance's database as it was at an earlier time, given in RFC 3339 form such as `2026-10-07T14:00:00Z`. The copy is never newer than that time, and the command says which transaction it stopped at. Ask for a time before the oldest history and it names the oldest time you can use. Instances that sleep now keep seven days of history, as awake ones do. That week fills in over the seven days after your deployment rolls this release.", |
| 2083 | "branches": [ |
| 2084 | "db-pull-at", |
| 2085 | "hibernate-retention" |
| 2086 | ], |
| 2087 | "docs": [ |
| 2088 | "/docs/cli#carlos-db" |
| 2089 | ] |
| 2090 | }, |
| 2091 | { |
| 2092 | "md": "**Channel digests.** `carlos channels digests` shows whether channel pointers carry the sha256 of each build's manifest, and lists the channels that don't yet. Once a deployment turns digests on, boxes refuse pointers without them. So update the CLI on every machine and CI job that promotes, rolls back or fast-tracks before then. `carlos channels resign <channel>` re-signs a channel nobody has promoted to since digests went on. It shows every digest and signs only when you type yes.", |
| 2093 | "branches": [ |
| 2094 | "settings-1-pointer-digests" |
| 2095 | ], |
| 2096 | "docs": [ |
| 2097 | "/docs/cli#carlos-channels-digests", |
| 2098 | "/docs/cli#carlos-channels-resign" |
| 2099 | ] |
| 2100 | }, |
| 2101 | { |
| 2102 | "md": "**`carlos releases authorize <app> <version>`, for operators.** It shows a build's manifest and file digests and, when you type yes, signs a promotion record for exactly those bytes. Every promotion now writes one. This is for a build promoted before records existed, so an instance can be pinned to it or recovered onto it.", |
| 2103 | "branches": [ |
| 2104 | "settings-2-promotion-records" |
| 2105 | ], |
| 2106 | "docs": [ |
| 2107 | "/docs/cli#carlos-releases" |
| 2108 | ] |
| 2109 | }, |
| 2110 | { |
| 2111 | "md": "**What an instance is started with.** Every instance and seed now gets `CARLOS_HOST`, its hostname exactly as `carlos instances list` shows it. Read it, never the socket's file name. On an isolated box, an instance starts in its own data directory, the one its database is in, so a relative path such as `./data/blobs` lands beside its database. Files and directories named after the host, such as `<host>/` or `<host>-blobs`, now move with an instance when its box isolates it, and come back on a revert.", |
| 2112 | "branches": [ |
| 2113 | "fix-roll-incident-256" |
| 2114 | ], |
| 2115 | "docs": [ |
| 2116 | "/docs/cli#carlos-instances" |
| 2117 | ] |
| 2118 | }, |
| 2119 | { |
| 2120 | "md": "**`carlos move`, off until your deployment turns moves on.** It moves one instance to another region. The instance keeps serving while its data is copied, then goes offline for the cut. If the new region can't start it, the move takes it back on its own. Against a console without moves, `carlos move` sends nothing.", |
| 2121 | "branches": [ |
| 2122 | "moves-phase1", |
| 2123 | "moves-phase1-2", |
| 2124 | "moves-phase1-3", |
| 2125 | "moves-phase1-3b", |
| 2126 | "moves-phase1-3c", |
| 2127 | "moves-phase1-4", |
| 2128 | "moves-phase1-5", |
| 2129 | "moves-phase1-5b", |
| 2130 | "moves-phase1-5c", |
| 2131 | "moves-phase1-5d", |
| 2132 | "moves-phase1-5e", |
| 2133 | "moves-phase1-5f", |
| 2134 | "moves-phase1-6", |
| 2135 | "moves-phase1-7", |
| 2136 | "moves-cut-guard" |
| 2137 | ], |
| 2138 | "docs": [ |
| 2139 | "/docs/cli#carlos-move" |
| 2140 | ] |
| 2141 | }, |
| 2142 | { |
| 2143 | "md": "**Smaller fixes.** A build of about 100 MB no longer runs the box's staging out of memory, so its promote no longer waits for the hourly pass. `carlos sidecars ls` shows the build each sidecar's box last started, and \"unknown\" for one that hasn't started anywhere. `carlos instances set-channel` finds a host typed with capitals, and for a box route with no instance record it says how to move the route on its box.", |
| 2144 | "branches": [ |
| 2145 | "stage-stream-artifact", |
| 2146 | "zdd-6-surfaces", |
| 2147 | "setenv-box-route-error" |
| 2148 | ], |
| 2149 | "docs": [ |
| 2150 | "/docs/cli#carlos-sidecars", |
| 2151 | "/docs/cli#carlos-instances" |
| 2152 | ] |
| 2153 | } |
| 2154 | ] |
| 2155 | }, |
| 2156 | { |
| 2157 | "title": "For operators", |
| 2158 | "bullets": [ |
| 2159 | { |
| 2160 | "md": "**If your boxes haven't run v0.25.1, read its operator notes and v0.25.0's first.** They all apply to this release." |
| 2161 | }, |
| 2162 | { |
| 2163 | "md": "**Roll the boxes first, then the console.** Roll the boxes with `carlos system update`.", |
| 2164 | "docs": [ |
| 2165 | "/docs/cli#carlos-system" |
| 2166 | ] |
| 2167 | }, |
| 2168 | { |
| 2169 | "md": "**After each box updates, restart `carlos-instance-control.service` on it.** The update runs the code the box already has, which installs this release without restarting that service. This release's agent refuses to wake isolated instances while the service runs an older build, and the reason in `carlos logs` ends with `restart carlos-instance-control.service`. `carlos system status` still reads `current`, so it won't tell you. From this release on, `carlos system update` restarts the service itself.", |
| 2170 | "branches": [ |
| 2171 | "fix-roll-incident-256" |
| 2172 | ], |
| 2173 | "docs": [ |
| 2174 | "/docs/cli#carlos-logs", |
| 2175 | "/docs/cli#carlos-system" |
| 2176 | ] |
| 2177 | }, |
| 2178 | { |
| 2179 | "md": "**Before any box rolls, run the instance key checks.** This release writes a `CARLOS_INSTANCE_KEY` into each instance's `<host>.env` the first time it starts, and starts a replica only with its home's key.", |
| 2180 | "items": [ |
| 2181 | "On every box, `find <data> -maxdepth 1 -name '*.env' -type l` must print nothing. A `<host>.env` that is a symlink now fails that instance's start. Stop the instance, replace the link with the real file, and treat the token in it as leaked.", |
| 2182 | "On every box with a replica (`sqlite3 <data>/registry.db \"select host from routes where replica=1\"`), compare each replica's key with its home's. A key is the last `CARLOS_INSTANCE_KEY` line of `<host>.env`, or of `<host>.config.env` when `<host>.env` has none, in the data directory for a flat instance or the instance's own directory for an isolated one. Where the two match, add `<replica-host>=<sha256 of the key>` to `/etc/carlos/replica-home-keys` on the replica's box before it rolls. Write the whole list to a temporary file in `/etc/carlos`, make it root:carlos 0640, and rename it into place. Where they differ, the replica is refused after the roll. Tell its owner first.", |
| 2183 | "A replica with no key keeps starting where it has a control socket, but its legacy sidecar and any worker row of its own stop at the roll. List them on each box with a replica, and tell their owners.", |
| 2184 | "Check the agent can read the list: `sudo -u <agent user> test -r /etc/carlos/replica-home-keys && echo ok` must print `ok`.", |
| 2185 | "After the roll, `journalctl -u carlos-edge --since '<roll time>' | grep 'agent: instance keys:'` must show `0 failed`." |
| 2186 | ], |
| 2187 | "branches": [ |
| 2188 | "instance-key-provision", |
| 2189 | "instance-key-build" |
| 2190 | ] |
| 2191 | }, |
| 2192 | { |
| 2193 | "md": "**Root ignores AWS profile, endpoint and trust-store settings.** A box's root processes now ignore `AWS_PROFILE`, `AWS_DEFAULT_PROFILE`, `AWS_CA_BUNDLE`, the `AWS_ENDPOINT_URL` variables, `SSL_CERT_FILE`, `SSL_CERT_DIR` and shared AWS config files, and log an alert when one is set. Before rolling, check that no box's host.env depends on them. On a box outside AWS, `/etc/carlos/credentials` must hold only static keys under `[default]`. The agent rewrites it as root:carlos 0640 on every start.", |
| 2194 | "branches": [ |
| 2195 | "fix/267-credentials", |
| 2196 | "fix/267-adopt-writes", |
| 2197 | "docs/267-remote-host" |
| 2198 | ] |
| 2199 | }, |
| 2200 | { |
| 2201 | "md": "**Every dormant switch stays off.** Leave each of these unset, and run none of the commands named, until its own rollout is approved.", |
| 2202 | "items": [ |
| 2203 | "`CARLOS_SWAP` on every box. Two builds at once still has open items, and only the exact word `overlap` arms it.", |
| 2204 | "`CARLOS_MOVES_PHASE1` on the console and every box. Don't publish a moves protocol floor (`control/moves-protocol.json`) either.", |
| 2205 | "`CARLOS_HOST_CLAIM`, `CARLOS_HOST_CLAIM_ORIGINS` and `CARLOS_HOST_CLAIM_RETIRED_LOCATIONS` on the console and every box, and `CARLOS_CONSOLE_ID` on the console. Don't run `carlos system guard-arm` or `carlos system journal-migrate`.", |
| 2206 | "`CARLOS_REGION_HA` on every box.", |
| 2207 | "`CONSOLE_APP_REGIONS` and `CARLOS_TEMPORARY_APPS` on the console.", |
| 2208 | "`CARLOS_REQUIRE_POINTER_DIGEST` on every box. Don't run `carlos channels digests on` yet." |
| 2209 | ], |
| 2210 | "docs": [ |
| 2211 | "/docs/cli#carlos-system", |
| 2212 | "/docs/cli#carlos-system-journal-migrate", |
| 2213 | "/docs/cli#carlos-channels-digests" |
| 2214 | ] |
| 2215 | }, |
| 2216 | { |
| 2217 | "md": "**Host claims: every roster reader first.** Binaries older than this release reject a signed roster that names a home region. So before anyone publishes the home designation, every reader of `control/host-actors.json` must run this release: every console, every box's agent and root services, the update and rollback tools, and any offline or recovery binary. The designation is write-once, and this roll doesn't publish it.", |
| 2218 | "branches": [ |
| 2219 | "feat/hostclaim-home-region", |
| 2220 | "fix/home-region-followups" |
| 2221 | ] |
| 2222 | }, |
| 2223 | { |
| 2224 | "md": "**Digests: writers before readers.** Once a box has verified a channel pointer with digests, it refuses pointers for that channel without them. So first upgrade every writer: every console, and every CLI or deploy script that promotes, rolls back or fast-tracks. Then run `carlos channels digests on`, and watch `carlos channels digests` until it lists nothing. Only then set `CARLOS_REQUIRE_POINTER_DIGEST=on` in every box's host.env. `carlos channels digests off` stops writers adding digests while one is fixed, but doesn't clear boxes that have already seen them.", |
| 2225 | "branches": [ |
| 2226 | "settings-1-pointer-digests" |
| 2227 | ], |
| 2228 | "docs": [ |
| 2229 | "/docs/cli#carlos-channels-digests" |
| 2230 | ] |
| 2231 | }, |
| 2232 | { |
| 2233 | "md": "**Instance update settings wait for every box.** The console refuses manual updates, a major hold or a pin until every box reports it can keep the builds they name. Before rolling any box back below this release, run `carlos releases retention --off` for each app that has a retention policy, because an older box prunes builds a pin or a held instance still needs. After such a rollback the console shows *settings not enforced* for instances on the older boxes.", |
| 2234 | "branches": [ |
| 2235 | "settings-4-root-applies", |
| 2236 | "settings-5-surfaces" |
| 2237 | ], |
| 2238 | "docs": [ |
| 2239 | "/docs/cli#carlos-releases" |
| 2240 | ] |
| 2241 | }, |
| 2242 | { |
| 2243 | "md": "**Remove the staging memory drop-ins after the roll.** Staging now streams a build to disk instead of reading it into memory. A deployment that raised the memory of `carlos-stage.service` or `carlos-adopt.service` with a drop-in can remove it from every box, and from its box bootstrap, once every box runs this release.", |
| 2244 | "branches": [ |
| 2245 | "stage-stream-artifact" |
| 2246 | ] |
| 2247 | }, |
| 2248 | { |
| 2249 | "md": "**The `deployment-buckets` module now guards fence writes.** Its new statement refuses every write under `control/box-fences/` from a role not listed in `box_fence_writer_role_arns`. Nothing writes there while host claims are off, so applying it now is safe.", |
| 2250 | "branches": [ |
| 2251 | "feat/hostclaim-activation" |
| 2252 | ] |
| 2253 | }, |
| 2254 | { |
| 2255 | "md": "**Files left behind by earlier moves.** An instance its box isolated before this release may have left files named after its host in the shared data directory. `carlos status --layout` and the agent log now name them on every pass. Move them into the instance's directory by hand.", |
| 2256 | "branches": [ |
| 2257 | "fix-roll-incident-256" |
| 2258 | ], |
| 2259 | "docs": [ |
| 2260 | "/docs/cli#carlos-status" |
| 2261 | ] |
| 2262 | } |
| 2263 | ] |
| 2264 | } |
| 2265 | ] |
| 2266 | }, |
| 2267 | "changes": [ |
| 2268 | { |
| 2269 | "sha": "09c5a4a5f30690d99a3d5c6ef4af2d8bea99a741", |
| 2270 | "date": "2026-10-13", |
| 2271 | "subject": "moves-copy-approve-p5f", |
| 2272 | "branch": "moves-copy-approve-p5f", |
| 2273 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-copy-approve-p5f", |
| 2274 | "commits": 1, |
| 2275 | "credit": [ |
| 2276 | { |
| 2277 | "person": "Paul Campbell", |
| 2278 | "agents": [ |
| 2279 | "claude" |
| 2280 | ] |
| 2281 | } |
| 2282 | ] |
| 2283 | }, |
| 2284 | { |
| 2285 | "sha": "a8cebadeae463ff4f0189c9652e3d6e7d745c01c", |
| 2286 | "date": "2026-10-13", |
| 2287 | "subject": "plan: region HA 1b-next, relocation released by stop evidence or a termination fence, reconcile row cases, create's once-only executor choice, and fences consumed in claim CASes", |
| 2288 | "branch": "region-ha-1b-next-build", |
| 2289 | "branch_url": "https://amadan.net/carlos/platform/-/branch/region-ha-1b-next-build", |
| 2290 | "commits": 210, |
| 2291 | "discussions": [ |
| 2292 | { |
| 2293 | "id": 66, |
| 2294 | "title": "restore-verify cannot check currency for DynamicUser tenants: the drill runs as carlos, the replicator as root", |
| 2295 | "state": "open" |
| 2296 | }, |
| 2297 | { |
| 2298 | "id": 236, |
| 2299 | "title": "Host claim Plan 8: three decisions for Paul (floor release, declare-lost attestation, actor roster)", |
| 2300 | "state": "open" |
| 2301 | }, |
| 2302 | { |
| 2303 | "id": 278, |
| 2304 | "title": "CI resumed; record-write census requires review of eight changed or unlisted sites", |
| 2305 | "state": "open" |
| 2306 | }, |
| 2307 | { |
| 2308 | "id": 279, |
| 2309 | "title": "hostfiles: resource bounds on tenant-writable trees (gate before region HA activation)", |
| 2310 | "state": "open" |
| 2311 | } |
| 2312 | ], |
| 2313 | "credit": [ |
| 2314 | { |
| 2315 | "person": "Paul Campbell", |
| 2316 | "agents": [ |
| 2317 | "claude" |
| 2318 | ] |
| 2319 | } |
| 2320 | ] |
| 2321 | }, |
| 2322 | { |
| 2323 | "sha": "68b6ab5e8b707bb772843f5b270e6198df78b519", |
| 2324 | "date": "2026-10-13", |
| 2325 | "subject": "moves-plan15-proof", |
| 2326 | "branch": "moves-plan15-proof", |
| 2327 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-plan15-proof", |
| 2328 | "commits": 1, |
| 2329 | "credit": [ |
| 2330 | { |
| 2331 | "person": "Paul Campbell", |
| 2332 | "agents": [ |
| 2333 | "claude" |
| 2334 | ] |
| 2335 | } |
| 2336 | ] |
| 2337 | }, |
| 2338 | { |
| 2339 | "sha": "93ceb6cdc2397f20659401707e0b4e3162335981", |
| 2340 | "date": "2026-10-13", |
| 2341 | "subject": "Region HA two-box model: plan rev 11 and its Astra reviews (from region-ha-hostlife-two-box 8f95c4e0)", |
| 2342 | "branch": "region-ha-two-box-build", |
| 2343 | "branch_url": "https://amadan.net/carlos/platform/-/branch/region-ha-two-box-build", |
| 2344 | "commits": 54, |
| 2345 | "credit": [ |
| 2346 | { |
| 2347 | "person": "Paul Campbell", |
| 2348 | "agents": [ |
| 2349 | "claude" |
| 2350 | ] |
| 2351 | } |
| 2352 | ] |
| 2353 | }, |
| 2354 | { |
| 2355 | "sha": "d850865bf0399bce6be73cde59d4415f857ed9f2", |
| 2356 | "date": "2026-10-12", |
| 2357 | "subject": "settings-5 task 1: draft plan 5's update settings copy for review", |
| 2358 | "branch": "settings-5-surfaces", |
| 2359 | "branch_url": "https://amadan.net/carlos/platform/-/branch/settings-5-surfaces", |
| 2360 | "commits": 16, |
| 2361 | "docs": [ |
| 2362 | "/docs/cli#carlos-apps", |
| 2363 | "/docs/cli#carlos-instances-set", |
| 2364 | "/docs/cli#carlos-instances-update" |
| 2365 | ], |
| 2366 | "credit": [ |
| 2367 | { |
| 2368 | "person": "Paul Campbell", |
| 2369 | "agents": [ |
| 2370 | "claude" |
| 2371 | ] |
| 2372 | } |
| 2373 | ] |
| 2374 | }, |
| 2375 | { |
| 2376 | "sha": "01edf9015b55218ef970eafa54cff92c35c2dfdb", |
| 2377 | "date": "2026-10-12", |
| 2378 | "subject": "feat/claim-admitted-provenance", |
| 2379 | "branch": "feat/claim-admitted-provenance", |
| 2380 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fclaim-admitted-provenance", |
| 2381 | "commits": 1, |
| 2382 | "credit": [ |
| 2383 | { |
| 2384 | "person": "Paul Campbell", |
| 2385 | "agents": [ |
| 2386 | "codex" |
| 2387 | ] |
| 2388 | } |
| 2389 | ] |
| 2390 | }, |
| 2391 | { |
| 2392 | "sha": "d6122533b8dc9163005bf6f21109387cb9251656", |
| 2393 | "date": "2026-10-12", |
| 2394 | "subject": "moves-phase1-5f", |
| 2395 | "branch": "moves-phase1-5f", |
| 2396 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-5f", |
| 2397 | "commits": 1, |
| 2398 | "credit": [ |
| 2399 | { |
| 2400 | "person": "Paul Campbell", |
| 2401 | "agents": [ |
| 2402 | "claude" |
| 2403 | ] |
| 2404 | } |
| 2405 | ] |
| 2406 | }, |
| 2407 | { |
| 2408 | "sha": "650e6152be0af5851b879980f67970382750becd", |
| 2409 | "date": "2026-10-12", |
| 2410 | "subject": "moves: restoring keeps the source region authoritative until a clean return or the commit (J2/F4, L18 finding 1)", |
| 2411 | "branch": "moves-restoring-source-protection", |
| 2412 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-restoring-source-protection", |
| 2413 | "commits": 1, |
| 2414 | "credit": [ |
| 2415 | { |
| 2416 | "person": "Paul Campbell", |
| 2417 | "agents": [ |
| 2418 | "claude" |
| 2419 | ] |
| 2420 | } |
| 2421 | ] |
| 2422 | }, |
| 2423 | { |
| 2424 | "sha": "8916558d34f68698f488ee7a0aa7f4a55808c380", |
| 2425 | "date": "2026-10-12", |
| 2426 | "subject": "settings-4 task 1: the build state, its registry copy, and root's consumed file", |
| 2427 | "branch": "settings-4-root-applies", |
| 2428 | "branch_url": "https://amadan.net/carlos/platform/-/branch/settings-4-root-applies", |
| 2429 | "commits": 40, |
| 2430 | "credit": [ |
| 2431 | { |
| 2432 | "person": "Paul Campbell", |
| 2433 | "agents": [ |
| 2434 | "claude" |
| 2435 | ] |
| 2436 | } |
| 2437 | ] |
| 2438 | }, |
| 2439 | { |
| 2440 | "sha": "39986908150d2e3c90477de4320c0d2941ffaac6", |
| 2441 | "date": "2026-10-12", |
| 2442 | "subject": "feat/claim-loss-pages", |
| 2443 | "branch": "feat/claim-loss-pages", |
| 2444 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fclaim-loss-pages", |
| 2445 | "commits": 1, |
| 2446 | "credit": [ |
| 2447 | { |
| 2448 | "person": "Paul Campbell", |
| 2449 | "agents": [ |
| 2450 | "claude", |
| 2451 | "codex" |
| 2452 | ] |
| 2453 | } |
| 2454 | ] |
| 2455 | }, |
| 2456 | { |
| 2457 | "sha": "8ebd9d8ce7c7cb82b404bb94b6f3607569c8981b", |
| 2458 | "date": "2026-10-12", |
| 2459 | "subject": "zdd-readiness: implementation plan for the flag-readiness round (#272)", |
| 2460 | "branch": "zdd-flag-readiness", |
| 2461 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-flag-readiness", |
| 2462 | "commits": 52, |
| 2463 | "discussions": [ |
| 2464 | { |
| 2465 | "id": 1, |
| 2466 | "title": "Flagship went fully dark on memory pressure (2026-08-28): one tenant can take the box, and nothing notices", |
| 2467 | "state": "open" |
| 2468 | }, |
| 2469 | { |
| 2470 | "id": 2, |
| 2471 | "title": "Managed email identities: many senders per app", |
| 2472 | "state": "open" |
| 2473 | }, |
| 2474 | { |
| 2475 | "id": 5, |
| 2476 | "title": "A first instance defaults to stable, so the first deploy needs a passkey", |
| 2477 | "state": "closed" |
| 2478 | }, |
| 2479 | { |
| 2480 | "id": 6, |
| 2481 | "title": "Timing at the platform boundary: activator wake and edge round-trip are invisible to an app", |
| 2482 | "state": "open" |
| 2483 | }, |
| 2484 | { |
| 2485 | "id": 9, |
| 2486 | "title": "/fleet/architecture: the box layer is off-screen at every width, box names truncate to a single string, and the diagram draws a path that does not exist", |
| 2487 | "state": "open" |
| 2488 | }, |
| 2489 | { |
| 2490 | "id": 10, |
| 2491 | "title": "The replication ladder is unreachable: stream/batched/daily exist and are honoured, but nothing can set the column", |
| 2492 | "state": "open" |
| 2493 | }, |
| 2494 | { |
| 2495 | "id": 272, |
| 2496 | "title": "Zero-downtime deploys: owed before CARLOS_SWAP can go on", |
| 2497 | "state": "open" |
| 2498 | } |
| 2499 | ], |
| 2500 | "credit": [ |
| 2501 | { |
| 2502 | "person": "Paul Campbell", |
| 2503 | "agents": [ |
| 2504 | "claude" |
| 2505 | ] |
| 2506 | } |
| 2507 | ] |
| 2508 | }, |
| 2509 | { |
| 2510 | "sha": "2ad5412cd50cf552d61dfa41b16b41b6a30fed5c", |
| 2511 | "date": "2026-10-12", |
| 2512 | "subject": "fix/home-region-followups", |
| 2513 | "branch": "fix/home-region-followups", |
| 2514 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fhome-region-followups", |
| 2515 | "commits": 1, |
| 2516 | "credit": [ |
| 2517 | { |
| 2518 | "person": "Paul Campbell", |
| 2519 | "agents": [ |
| 2520 | "claude", |
| 2521 | "codex" |
| 2522 | ] |
| 2523 | } |
| 2524 | ] |
| 2525 | }, |
| 2526 | { |
| 2527 | "sha": "a0806e4c24a2e4d6298edf6cfb527d1ecff00b70", |
| 2528 | "date": "2026-10-12", |
| 2529 | "subject": "feat/hostclaim-home-region", |
| 2530 | "branch": "feat/hostclaim-home-region", |
| 2531 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-home-region", |
| 2532 | "commits": 1, |
| 2533 | "credit": [ |
| 2534 | { |
| 2535 | "person": "Paul Campbell", |
| 2536 | "agents": [ |
| 2537 | "codex" |
| 2538 | ] |
| 2539 | } |
| 2540 | ] |
| 2541 | }, |
| 2542 | { |
| 2543 | "sha": "dde859f38182f5915706b0e3e8b17c2deea22019", |
| 2544 | "date": "2026-10-12", |
| 2545 | "subject": "moves-held-lock", |
| 2546 | "branch": "moves-held-lock", |
| 2547 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-held-lock", |
| 2548 | "commits": 1, |
| 2549 | "credit": [ |
| 2550 | { |
| 2551 | "person": "Paul Campbell", |
| 2552 | "agents": [ |
| 2553 | "claude" |
| 2554 | ] |
| 2555 | } |
| 2556 | ] |
| 2557 | }, |
| 2558 | { |
| 2559 | "sha": "359e8ac270f8deae26df97846910639a6b16915c", |
| 2560 | "date": "2026-10-12", |
| 2561 | "subject": "moves-home-parks", |
| 2562 | "branch": "moves-home-parks", |
| 2563 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-home-parks", |
| 2564 | "commits": 1, |
| 2565 | "credit": [ |
| 2566 | { |
| 2567 | "person": "Paul Campbell", |
| 2568 | "agents": [ |
| 2569 | "claude" |
| 2570 | ] |
| 2571 | } |
| 2572 | ] |
| 2573 | }, |
| 2574 | { |
| 2575 | "sha": "0715faca664041152e2a437a70debd06c7177669", |
| 2576 | "date": "2026-10-12", |
| 2577 | "subject": "moves-phase1-7", |
| 2578 | "branch": "moves-phase1-7", |
| 2579 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-7", |
| 2580 | "commits": 1, |
| 2581 | "credit": [ |
| 2582 | { |
| 2583 | "person": "Paul Campbell", |
| 2584 | "agents": [ |
| 2585 | "claude" |
| 2586 | ] |
| 2587 | } |
| 2588 | ] |
| 2589 | }, |
| 2590 | { |
| 2591 | "sha": "1b5802fb75864e7659bd44ca1f90ad20a1979cc9", |
| 2592 | "date": "2026-10-12", |
| 2593 | "subject": "feat/hostclaim-moves-integration", |
| 2594 | "branch": "feat/hostclaim-moves-integration", |
| 2595 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-moves-integration", |
| 2596 | "commits": 1, |
| 2597 | "credit": [ |
| 2598 | { |
| 2599 | "person": "Paul Campbell", |
| 2600 | "agents": [ |
| 2601 | "codex" |
| 2602 | ] |
| 2603 | } |
| 2604 | ] |
| 2605 | }, |
| 2606 | { |
| 2607 | "sha": "b04ff852c1be6aa4bc09d5c3fa721e765141d107", |
| 2608 | "date": "2026-10-12", |
| 2609 | "subject": "moves-cut-guard", |
| 2610 | "branch": "moves-cut-guard", |
| 2611 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-cut-guard", |
| 2612 | "commits": 1, |
| 2613 | "credit": [ |
| 2614 | { |
| 2615 | "person": "Paul Campbell", |
| 2616 | "agents": [ |
| 2617 | "claude" |
| 2618 | ] |
| 2619 | } |
| 2620 | ] |
| 2621 | }, |
| 2622 | { |
| 2623 | "sha": "bd9d6321c706b923221a2cbc9bca2c8dc0a6318b", |
| 2624 | "date": "2026-10-12", |
| 2625 | "subject": "moves-copy-approve-58", |
| 2626 | "branch": "moves-copy-approve-58", |
| 2627 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-copy-approve-58", |
| 2628 | "commits": 1, |
| 2629 | "credit": [ |
| 2630 | { |
| 2631 | "person": "Paul Campbell", |
| 2632 | "agents": [ |
| 2633 | "claude" |
| 2634 | ] |
| 2635 | } |
| 2636 | ] |
| 2637 | }, |
| 2638 | { |
| 2639 | "sha": "bc25674a7a7acf29c4e9ea402f2c2ba4f0cda108", |
| 2640 | "date": "2026-10-11", |
| 2641 | "subject": "moves-phase1-6", |
| 2642 | "branch": "moves-phase1-6", |
| 2643 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-6", |
| 2644 | "commits": 1, |
| 2645 | "docs": [ |
| 2646 | "/docs/cli#carlos-move" |
| 2647 | ], |
| 2648 | "credit": [ |
| 2649 | { |
| 2650 | "person": "Paul Campbell", |
| 2651 | "agents": [ |
| 2652 | "claude" |
| 2653 | ] |
| 2654 | } |
| 2655 | ] |
| 2656 | }, |
| 2657 | { |
| 2658 | "sha": "43da77c2f4f1ad73147eeea9e4b093f047d90fd5", |
| 2659 | "date": "2026-10-11", |
| 2660 | "subject": "Instance key provision (region HA L21): the platform mints CARLOS_INSTANCE_KEY create-only and durably into <host>.env on every launch path once configuration is delivered, gates every replica launch on its home's verified key, adds the writer-bound adoption verb (unmounted until O6/O7) and a legacy-box startup backfill, and carries the key byte for byte through re-render and moves. Rastrillo's carlos.InstanceKey consumes it. Effectively dormant until apps adopt the helper; rollout has pre-roll checks.", |
| 2661 | "branch": "instance-key-build", |
| 2662 | "branch_url": "https://amadan.net/carlos/platform/-/branch/instance-key-build", |
| 2663 | "commits": 56, |
| 2664 | "discussions": [ |
| 2665 | { |
| 2666 | "id": 66, |
| 2667 | "title": "restore-verify cannot check currency for DynamicUser tenants: the drill runs as carlos, the replicator as root", |
| 2668 | "state": "open" |
| 2669 | }, |
| 2670 | { |
| 2671 | "id": 162, |
| 2672 | "title": "A route can carry replica placements, served locally instead of hairpinned (edge checkout)", |
| 2673 | "state": "closed" |
| 2674 | }, |
| 2675 | { |
| 2676 | "id": 273, |
| 2677 | "title": "activator: EnsureAdminToken's mint path follows a symlink at a flat row's <host>.env", |
| 2678 | "state": "open" |
| 2679 | } |
| 2680 | ], |
| 2681 | "credit": [ |
| 2682 | { |
| 2683 | "person": "Paul Campbell", |
| 2684 | "agents": [ |
| 2685 | "claude" |
| 2686 | ] |
| 2687 | } |
| 2688 | ] |
| 2689 | }, |
| 2690 | { |
| 2691 | "sha": "5da1cc9b4ea2427dcd16a5d5d6f35e2a7ecd1fb9", |
| 2692 | "date": "2026-10-11", |
| 2693 | "subject": "zdd-6 task 2: rolloutwords, the one home for rollout phrases", |
| 2694 | "branch": "zdd-6-surfaces", |
| 2695 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-6-surfaces", |
| 2696 | "commits": 39, |
| 2697 | "discussions": [ |
| 2698 | { |
| 2699 | "id": 1, |
| 2700 | "title": "Flagship went fully dark on memory pressure (2026-08-28): one tenant can take the box, and nothing notices", |
| 2701 | "state": "open" |
| 2702 | }, |
| 2703 | { |
| 2704 | "id": 2, |
| 2705 | "title": "Managed email identities: many senders per app", |
| 2706 | "state": "open" |
| 2707 | }, |
| 2708 | { |
| 2709 | "id": 3, |
| 2710 | "title": "CARLOS apps do not have to be written in Go", |
| 2711 | "state": "open" |
| 2712 | }, |
| 2713 | { |
| 2714 | "id": 4, |
| 2715 | "title": "No machine credential for programmatic instance provisioning", |
| 2716 | "state": "closed" |
| 2717 | }, |
| 2718 | { |
| 2719 | "id": 5, |
| 2720 | "title": "A first instance defaults to stable, so the first deploy needs a passkey", |
| 2721 | "state": "closed" |
| 2722 | }, |
| 2723 | { |
| 2724 | "id": 6, |
| 2725 | "title": "Timing at the platform boundary: activator wake and edge round-trip are invisible to an app", |
| 2726 | "state": "open" |
| 2727 | }, |
| 2728 | { |
| 2729 | "id": 7, |
| 2730 | "title": "Multi-region is a copy-paste exercise: the platform ships a host module but no shape around it", |
| 2731 | "state": "open" |
| 2732 | }, |
| 2733 | { |
| 2734 | "id": 8, |
| 2735 | "title": "carlos adopt runs as root and carlos agent as carlos, on one SQLite registry — a fresh box can end up unstartable", |
| 2736 | "state": "open" |
| 2737 | }, |
| 2738 | { |
| 2739 | "id": 9, |
| 2740 | "title": "/fleet/architecture: the box layer is off-screen at every width, box names truncate to a single string, and the diagram draws a path that does not exist", |
| 2741 | "state": "open" |
| 2742 | } |
| 2743 | ], |
| 2744 | "docs": [ |
| 2745 | "/docs/cli#carlos-apps", |
| 2746 | "/docs/cli#carlos-deploy", |
| 2747 | "/docs/cli#two-builds-at-once", |
| 2748 | "/docs/cli#carlos-instances", |
| 2749 | "/docs/cli#carlos-sidecars" |
| 2750 | ], |
| 2751 | "credit": [ |
| 2752 | { |
| 2753 | "person": "Paul Campbell", |
| 2754 | "agents": [ |
| 2755 | "claude" |
| 2756 | ] |
| 2757 | } |
| 2758 | ] |
| 2759 | }, |
| 2760 | { |
| 2761 | "sha": "30866251ab3cac055505ebdcd6b5a827c3a8ec9b", |
| 2762 | "date": "2026-10-11", |
| 2763 | "subject": "settings-3 task 1: release.UpdateSettings", |
| 2764 | "branch": "settings-3-console-settings", |
| 2765 | "branch_url": "https://amadan.net/carlos/platform/-/branch/settings-3-console-settings", |
| 2766 | "commits": 17, |
| 2767 | "credit": [ |
| 2768 | { |
| 2769 | "person": "Paul Campbell", |
| 2770 | "agents": [ |
| 2771 | "claude" |
| 2772 | ] |
| 2773 | } |
| 2774 | ] |
| 2775 | }, |
| 2776 | { |
| 2777 | "sha": "5157c1e702da0d5f318f52c825de4e1de3f28288", |
| 2778 | "date": "2026-10-11", |
| 2779 | "subject": "moves-phase1-5e", |
| 2780 | "branch": "moves-phase1-5e", |
| 2781 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-5e", |
| 2782 | "commits": 1, |
| 2783 | "credit": [ |
| 2784 | { |
| 2785 | "person": "Paul Campbell", |
| 2786 | "agents": [ |
| 2787 | "claude" |
| 2788 | ] |
| 2789 | } |
| 2790 | ] |
| 2791 | }, |
| 2792 | { |
| 2793 | "sha": "e79d71b59aff4815f04973fd92b3f4a95cb18b52", |
| 2794 | "date": "2026-10-11", |
| 2795 | "subject": "moves-phase1-5c", |
| 2796 | "branch": "moves-phase1-5c", |
| 2797 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-5c", |
| 2798 | "commits": 1, |
| 2799 | "credit": [ |
| 2800 | { |
| 2801 | "person": "Paul Campbell", |
| 2802 | "agents": [ |
| 2803 | "claude" |
| 2804 | ] |
| 2805 | } |
| 2806 | ] |
| 2807 | }, |
| 2808 | { |
| 2809 | "sha": "d562d7f24ddfeb211242c925ac4c897382492e6d", |
| 2810 | "date": "2026-10-11", |
| 2811 | "subject": "moves-phase1-5d", |
| 2812 | "branch": "moves-phase1-5d", |
| 2813 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-5d", |
| 2814 | "commits": 1, |
| 2815 | "credit": [ |
| 2816 | { |
| 2817 | "person": "Paul Campbell", |
| 2818 | "agents": [ |
| 2819 | "claude" |
| 2820 | ] |
| 2821 | } |
| 2822 | ] |
| 2823 | }, |
| 2824 | { |
| 2825 | "sha": "0901e835da06009bf37440fd5e77f14a208487bc", |
| 2826 | "date": "2026-10-10", |
| 2827 | "subject": "Instance key provision (region HA L21) implementation plan", |
| 2828 | "branch": "instance-key-provision", |
| 2829 | "branch_url": "https://amadan.net/carlos/platform/-/branch/instance-key-provision", |
| 2830 | "commits": 2, |
| 2831 | "credit": [ |
| 2832 | { |
| 2833 | "person": "Paul Campbell", |
| 2834 | "agents": [ |
| 2835 | "claude" |
| 2836 | ] |
| 2837 | } |
| 2838 | ] |
| 2839 | }, |
| 2840 | { |
| 2841 | "sha": "0d338c143a006eb39c27a3b4373a58ab52ed5564", |
| 2842 | "date": "2026-10-10", |
| 2843 | "subject": "hostbox: ColdRestore removes the temp database's -wal and -shm", |
| 2844 | "branch": "fix-restore-wal-leftovers", |
| 2845 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-restore-wal-leftovers", |
| 2846 | "commits": 1, |
| 2847 | "credit": [ |
| 2848 | { |
| 2849 | "person": "Paul Campbell", |
| 2850 | "agents": [ |
| 2851 | "claude" |
| 2852 | ] |
| 2853 | } |
| 2854 | ] |
| 2855 | }, |
| 2856 | { |
| 2857 | "sha": "70f8119f07bdef756b7e881bab0207a12e248451", |
| 2858 | "date": "2026-10-10", |
| 2859 | "subject": "settings-2 task 1: internal/updatewords, the draft strings for the settings plans", |
| 2860 | "branch": "settings-2-promotion-records", |
| 2861 | "branch_url": "https://amadan.net/carlos/platform/-/branch/settings-2-promotion-records", |
| 2862 | "commits": 20, |
| 2863 | "docs": [ |
| 2864 | "/docs/cli#carlos-releases" |
| 2865 | ], |
| 2866 | "credit": [ |
| 2867 | { |
| 2868 | "person": "Paul Campbell", |
| 2869 | "agents": [ |
| 2870 | "claude" |
| 2871 | ] |
| 2872 | } |
| 2873 | ] |
| 2874 | }, |
| 2875 | { |
| 2876 | "sha": "44c1b6d77ed16f92e46e892b8254835edbd567d8", |
| 2877 | "date": "2026-10-10", |
| 2878 | "subject": "feat/hostclaim-moves-recovery", |
| 2879 | "branch": "feat/hostclaim-moves-recovery", |
| 2880 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-moves-recovery", |
| 2881 | "commits": 1, |
| 2882 | "credit": [ |
| 2883 | { |
| 2884 | "person": "Paul Campbell", |
| 2885 | "agents": [ |
| 2886 | "codex" |
| 2887 | ] |
| 2888 | } |
| 2889 | ] |
| 2890 | }, |
| 2891 | { |
| 2892 | "sha": "843b7180e5eeb11b1d8ba75286b36bf44d95ae2b", |
| 2893 | "date": "2026-10-10", |
| 2894 | "subject": "docs, lease: remote-host runbook for root:carlos 0640 credentials and the fresh-inode repair; the off-cloud session-token error (#267, copy approved by Paul 2026-10-10)", |
| 2895 | "branch": "docs/267-remote-host", |
| 2896 | "branch_url": "https://amadan.net/carlos/platform/-/branch/docs%2F267-remote-host", |
| 2897 | "commits": 1, |
| 2898 | "discussions": [ |
| 2899 | { |
| 2900 | "id": 267, |
| 2901 | "title": "Security: root operates on the service user's /data registry files (local escalation, on main today)", |
| 2902 | "state": "open" |
| 2903 | } |
| 2904 | ], |
| 2905 | "credit": [ |
| 2906 | { |
| 2907 | "person": "Paul Campbell", |
| 2908 | "agents": [ |
| 2909 | "claude" |
| 2910 | ] |
| 2911 | } |
| 2912 | ] |
| 2913 | }, |
| 2914 | { |
| 2915 | "sha": "d905a67622cfaa1387bd265dd8e907f8a79067a3", |
| 2916 | "date": "2026-10-10", |
| 2917 | "subject": "zdd-5 task 1: pin the plan 1-4 surface; CARLOS_SWAP flag", |
| 2918 | "branch": "zdd-5-scheduler", |
| 2919 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-5-scheduler", |
| 2920 | "commits": 54, |
| 2921 | "credit": [ |
| 2922 | { |
| 2923 | "person": "Paul Campbell", |
| 2924 | "agents": [ |
| 2925 | "claude" |
| 2926 | ] |
| 2927 | } |
| 2928 | ] |
| 2929 | }, |
| 2930 | { |
| 2931 | "sha": "d6f66ef3c475e300b1ccd569880bee1461c723b1", |
| 2932 | "date": "2026-10-10", |
| 2933 | "subject": "lease: TestBlockedRenewalDeadlinePrecedesTakeover runs at a 3s TTL so its termination margin outlasts CI scheduling (#268)", |
| 2934 | "branch": "fix/268-lease-margin", |
| 2935 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2F268-lease-margin", |
| 2936 | "commits": 1, |
| 2937 | "discussions": [ |
| 2938 | { |
| 2939 | "id": 268, |
| 2940 | "title": "Flaky: TestBlockedRenewalDeadlinePrecedesTakeover (90ms timing margin) failed main CI", |
| 2941 | "state": "closed" |
| 2942 | } |
| 2943 | ], |
| 2944 | "credit": [ |
| 2945 | { |
| 2946 | "person": "Paul Campbell", |
| 2947 | "agents": [ |
| 2948 | "claude" |
| 2949 | ] |
| 2950 | } |
| 2951 | ] |
| 2952 | }, |
| 2953 | { |
| 2954 | "sha": "00fdf5411455b7bb5ebd66284d213e2172b9d53c", |
| 2955 | "date": "2026-10-10", |
| 2956 | "subject": "moves floor gate: compare the floor file in Go, not with cmp", |
| 2957 | "branch": "fix-moves-floor-gate", |
| 2958 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-moves-floor-gate", |
| 2959 | "commits": 2, |
| 2960 | "discussions": [ |
| 2961 | { |
| 2962 | "id": 267, |
| 2963 | "title": "Security: root operates on the service user's /data registry files (local escalation, on main today)", |
| 2964 | "state": "open" |
| 2965 | } |
| 2966 | ], |
| 2967 | "credit": [ |
| 2968 | { |
| 2969 | "person": "Paul Campbell", |
| 2970 | "agents": [ |
| 2971 | "claude" |
| 2972 | ] |
| 2973 | } |
| 2974 | ] |
| 2975 | }, |
| 2976 | { |
| 2977 | "sha": "93ef4b50dd220122f0375cdc6c2cf692d3b5aed2", |
| 2978 | "date": "2026-10-10", |
| 2979 | "subject": "feat/hostclaim-region-ha", |
| 2980 | "branch": "feat/hostclaim-region-ha", |
| 2981 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-region-ha", |
| 2982 | "commits": 1, |
| 2983 | "credit": [ |
| 2984 | { |
| 2985 | "person": "Paul Campbell", |
| 2986 | "agents": [ |
| 2987 | "claude", |
| 2988 | "codex" |
| 2989 | ] |
| 2990 | } |
| 2991 | ] |
| 2992 | }, |
| 2993 | { |
| 2994 | "sha": "ca591df7f9239679ce39e95589ff40379220c5f7", |
| 2995 | "date": "2026-10-10", |
| 2996 | "subject": "moves-phase1-5b", |
| 2997 | "branch": "moves-phase1-5b", |
| 2998 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-5b", |
| 2999 | "commits": 1, |
| 3000 | "credit": [ |
| 3001 | { |
| 3002 | "person": "Paul Campbell", |
| 3003 | "agents": [ |
| 3004 | "claude" |
| 3005 | ] |
| 3006 | } |
| 3007 | ] |
| 3008 | }, |
| 3009 | { |
| 3010 | "sha": "756184804d8c76654b4ef9230a6fd8e3fd93b3f9", |
| 3011 | "date": "2026-10-09", |
| 3012 | "subject": "fix/267-credentials", |
| 3013 | "branch": "fix/267-credentials", |
| 3014 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2F267-credentials", |
| 3015 | "commits": 1, |
| 3016 | "credit": [ |
| 3017 | { |
| 3018 | "person": "Paul Campbell", |
| 3019 | "agents": [ |
| 3020 | "codex" |
| 3021 | ] |
| 3022 | } |
| 3023 | ] |
| 3024 | }, |
| 3025 | { |
| 3026 | "sha": "a34623bd85f28eaffd702ef78aed899be5f50039", |
| 3027 | "date": "2026-10-09", |
| 3028 | "subject": "moves-phase1-3c", |
| 3029 | "branch": "moves-phase1-3c", |
| 3030 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-3c", |
| 3031 | "commits": 1, |
| 3032 | "credit": [ |
| 3033 | { |
| 3034 | "person": "Paul Campbell", |
| 3035 | "agents": [ |
| 3036 | "claude" |
| 3037 | ] |
| 3038 | } |
| 3039 | ] |
| 3040 | }, |
| 3041 | { |
| 3042 | "sha": "2d3ff96378d669a30c864d4e0b46357f620cf927", |
| 3043 | "date": "2026-10-09", |
| 3044 | "subject": "fix/267-adopt-writes", |
| 3045 | "branch": "fix/267-adopt-writes", |
| 3046 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2F267-adopt-writes", |
| 3047 | "commits": 1, |
| 3048 | "credit": [ |
| 3049 | { |
| 3050 | "person": "Paul Campbell", |
| 3051 | "agents": [ |
| 3052 | "claude", |
| 3053 | "codex" |
| 3054 | ] |
| 3055 | } |
| 3056 | ] |
| 3057 | }, |
| 3058 | { |
| 3059 | "sha": "29dab2d8c45e3cbeb0b86295dc6d1d7d3e5ef1a3", |
| 3060 | "date": "2026-10-09", |
| 3061 | "subject": "fix/registry-chown-nofollow", |
| 3062 | "branch": "fix/registry-chown-nofollow", |
| 3063 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fregistry-chown-nofollow", |
| 3064 | "commits": 1, |
| 3065 | "credit": [ |
| 3066 | { |
| 3067 | "person": "Paul Campbell", |
| 3068 | "agents": [ |
| 3069 | "claude", |
| 3070 | "codex" |
| 3071 | ] |
| 3072 | } |
| 3073 | ] |
| 3074 | }, |
| 3075 | { |
| 3076 | "sha": "cd987f6ca876572ee718566d48e3431f796fd8a4", |
| 3077 | "date": "2026-10-09", |
| 3078 | "subject": "release: stream the artifact to disk while staging (#269)", |
| 3079 | "branch": "stage-stream-artifact", |
| 3080 | "branch_url": "https://amadan.net/carlos/platform/-/branch/stage-stream-artifact", |
| 3081 | "commits": 2, |
| 3082 | "discussions": [ |
| 3083 | { |
| 3084 | "id": 269, |
| 3085 | "title": "Staging a release reads the whole build into memory; a ~99 MB build kills the 256 MB stage pass", |
| 3086 | "state": "closed" |
| 3087 | } |
| 3088 | ], |
| 3089 | "credit": [ |
| 3090 | { |
| 3091 | "person": "Paul Campbell", |
| 3092 | "agents": [ |
| 3093 | "claude" |
| 3094 | ] |
| 3095 | } |
| 3096 | ] |
| 3097 | }, |
| 3098 | { |
| 3099 | "sha": "a3bf7d6c0038094495a58d3d18623fd1568b90d4", |
| 3100 | "date": "2026-10-09", |
| 3101 | "subject": "zdd plan 3 task 1: swap types, the SwapBackend seam, flat staged spawn without health, each artifact's tier, canonical link at the switch", |
| 3102 | "branch": "zdd-3-swap", |
| 3103 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-3-swap", |
| 3104 | "commits": 39, |
| 3105 | "discussions": [ |
| 3106 | { |
| 3107 | "id": 4, |
| 3108 | "title": "No machine credential for programmatic instance provisioning", |
| 3109 | "state": "closed" |
| 3110 | } |
| 3111 | ], |
| 3112 | "credit": [ |
| 3113 | { |
| 3114 | "person": "Paul Campbell", |
| 3115 | "agents": [ |
| 3116 | "claude" |
| 3117 | ] |
| 3118 | } |
| 3119 | ] |
| 3120 | }, |
| 3121 | { |
| 3122 | "sha": "da76647be42e2b330f3ba425333f7a38a6ddcc52", |
| 3123 | "date": "2026-10-09", |
| 3124 | "subject": "moves-phase1-5", |
| 3125 | "branch": "moves-phase1-5", |
| 3126 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-5", |
| 3127 | "commits": 1, |
| 3128 | "credit": [ |
| 3129 | { |
| 3130 | "person": "Paul Campbell", |
| 3131 | "agents": [ |
| 3132 | "claude" |
| 3133 | ] |
| 3134 | } |
| 3135 | ] |
| 3136 | }, |
| 3137 | { |
| 3138 | "sha": "abcc732dbe9d21dd2fe8e7edcd3d28ab0ebac020", |
| 3139 | "date": "2026-10-09", |
| 3140 | "subject": "claim Plan 9: activation readiness (amadan #250), Paul's six rulings, ResolveMoveStart, moves C1 integration", |
| 3141 | "branch": "feat/hostclaim-activation", |
| 3142 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-activation", |
| 3143 | "commits": 6, |
| 3144 | "discussions": [ |
| 3145 | { |
| 3146 | "id": 250, |
| 3147 | "title": "Host floor guard: fix these before anyone runs guard-arm (Opus review of Plans 8/8b)", |
| 3148 | "state": "open" |
| 3149 | } |
| 3150 | ], |
| 3151 | "docs": [ |
| 3152 | "/docs/cli#cancel-an-unpublished-activation", |
| 3153 | "/docs/cli#carlos-system-journal-migrate" |
| 3154 | ], |
| 3155 | "credit": [ |
| 3156 | { |
| 3157 | "person": "Paul Campbell", |
| 3158 | "agents": [ |
| 3159 | "claude", |
| 3160 | "codex" |
| 3161 | ] |
| 3162 | } |
| 3163 | ] |
| 3164 | }, |
| 3165 | { |
| 3166 | "sha": "17d5960b093cdf06746c6ee72034f19c2146772e", |
| 3167 | "date": "2026-10-09", |
| 3168 | "subject": "moves copy: Paul approved the 16 rows from Plans 3 and 4 (2026-10-09), no edits", |
| 3169 | "branch": "moves-copy-approve-2", |
| 3170 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-copy-approve-2", |
| 3171 | "commits": 1, |
| 3172 | "credit": [ |
| 3173 | { |
| 3174 | "person": "Paul Campbell", |
| 3175 | "agents": [ |
| 3176 | "claude" |
| 3177 | ] |
| 3178 | } |
| 3179 | ] |
| 3180 | }, |
| 3181 | { |
| 3182 | "sha": "9426318718587a2b4db3a6219805866292ff8c09", |
| 3183 | "date": "2026-10-09", |
| 3184 | "subject": "moves copy: bring 24 approved rows to their code, 21 stay pending", |
| 3185 | "branch": "moves-copy-drift", |
| 3186 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-copy-drift", |
| 3187 | "commits": 2, |
| 3188 | "credit": [ |
| 3189 | { |
| 3190 | "person": "Paul Campbell", |
| 3191 | "agents": [ |
| 3192 | "claude" |
| 3193 | ] |
| 3194 | } |
| 3195 | ] |
| 3196 | }, |
| 3197 | { |
| 3198 | "sha": "316a07682dd896dc6ec8711c7c3ec96d1d6df3f7", |
| 3199 | "date": "2026-10-09", |
| 3200 | "subject": "stopevidence test: wait until fd 3 holds the database by identity before scanning (flaky on arm64 CI)", |
| 3201 | "branch": "fix-fdholders-alias-test", |
| 3202 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-fdholders-alias-test", |
| 3203 | "commits": 1, |
| 3204 | "credit": [ |
| 3205 | { |
| 3206 | "person": "Paul Campbell", |
| 3207 | "agents": [ |
| 3208 | "claude" |
| 3209 | ] |
| 3210 | } |
| 3211 | ] |
| 3212 | }, |
| 3213 | { |
| 3214 | "sha": "3342526589d59d33dec46ccc77d814badbe6dfed", |
| 3215 | "date": "2026-10-09", |
| 3216 | "subject": "moves copy: Paul approved the 205 reviewed rows (2026-10-09); 160 applied rows marked approved", |
| 3217 | "branch": "moves-copy-approve-1", |
| 3218 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-copy-approve-1", |
| 3219 | "commits": 2, |
| 3220 | "credit": [ |
| 3221 | { |
| 3222 | "person": "Paul Campbell", |
| 3223 | "agents": [ |
| 3224 | "claude" |
| 3225 | ] |
| 3226 | } |
| 3227 | ] |
| 3228 | }, |
| 3229 | { |
| 3230 | "sha": "412ca787cbfc8551eb33a59c4e9606dbfa159b90", |
| 3231 | "date": "2026-10-09", |
| 3232 | "subject": "moves-phase1-4", |
| 3233 | "branch": "moves-phase1-4", |
| 3234 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-4", |
| 3235 | "commits": 1, |
| 3236 | "credit": [ |
| 3237 | { |
| 3238 | "person": "Paul Campbell", |
| 3239 | "agents": [ |
| 3240 | "claude" |
| 3241 | ] |
| 3242 | } |
| 3243 | ] |
| 3244 | }, |
| 3245 | { |
| 3246 | "sha": "8d33cef1679542b29161ca59766eef3c917f44ee", |
| 3247 | "date": "2026-10-08", |
| 3248 | "subject": "settings-1 task 2: manifest digests and GetManifestRaw", |
| 3249 | "branch": "settings-1-pointer-digests", |
| 3250 | "branch_url": "https://amadan.net/carlos/platform/-/branch/settings-1-pointer-digests", |
| 3251 | "commits": 26, |
| 3252 | "discussions": [ |
| 3253 | { |
| 3254 | "id": 1, |
| 3255 | "title": "Flagship went fully dark on memory pressure (2026-08-28): one tenant can take the box, and nothing notices", |
| 3256 | "state": "open" |
| 3257 | }, |
| 3258 | { |
| 3259 | "id": 2, |
| 3260 | "title": "Managed email identities: many senders per app", |
| 3261 | "state": "open" |
| 3262 | }, |
| 3263 | { |
| 3264 | "id": 3, |
| 3265 | "title": "CARLOS apps do not have to be written in Go", |
| 3266 | "state": "open" |
| 3267 | }, |
| 3268 | { |
| 3269 | "id": 4, |
| 3270 | "title": "No machine credential for programmatic instance provisioning", |
| 3271 | "state": "closed" |
| 3272 | }, |
| 3273 | { |
| 3274 | "id": 5, |
| 3275 | "title": "A first instance defaults to stable, so the first deploy needs a passkey", |
| 3276 | "state": "closed" |
| 3277 | }, |
| 3278 | { |
| 3279 | "id": 6, |
| 3280 | "title": "Timing at the platform boundary: activator wake and edge round-trip are invisible to an app", |
| 3281 | "state": "open" |
| 3282 | }, |
| 3283 | { |
| 3284 | "id": 7, |
| 3285 | "title": "Multi-region is a copy-paste exercise: the platform ships a host module but no shape around it", |
| 3286 | "state": "open" |
| 3287 | }, |
| 3288 | { |
| 3289 | "id": 8, |
| 3290 | "title": "carlos adopt runs as root and carlos agent as carlos, on one SQLite registry — a fresh box can end up unstartable", |
| 3291 | "state": "open" |
| 3292 | } |
| 3293 | ], |
| 3294 | "docs": [ |
| 3295 | "/docs/cli#carlos-channels-resign", |
| 3296 | "/docs/cli#carlos-channels-digests" |
| 3297 | ], |
| 3298 | "credit": [ |
| 3299 | { |
| 3300 | "person": "Paul Campbell", |
| 3301 | "agents": [ |
| 3302 | "claude" |
| 3303 | ] |
| 3304 | } |
| 3305 | ] |
| 3306 | }, |
| 3307 | { |
| 3308 | "sha": "f36718c5467cc8f3a452ae2eb5efa68250d484ef", |
| 3309 | "date": "2026-10-08", |
| 3310 | "subject": "hibernate-retention: sleeping instances keep 7 days of snapshots, like awake ones (#263)", |
| 3311 | "branch": "hibernate-retention", |
| 3312 | "branch_url": "https://amadan.net/carlos/platform/-/branch/hibernate-retention", |
| 3313 | "commits": 3, |
| 3314 | "discussions": [ |
| 3315 | { |
| 3316 | "id": 263, |
| 3317 | "title": "Hibernating instances: keep 7 days of snapshot history like awake ones", |
| 3318 | "state": "closed" |
| 3319 | } |
| 3320 | ], |
| 3321 | "credit": [ |
| 3322 | { |
| 3323 | "person": "Paul Campbell", |
| 3324 | "agents": [ |
| 3325 | "claude" |
| 3326 | ] |
| 3327 | } |
| 3328 | ] |
| 3329 | }, |
| 3330 | { |
| 3331 | "sha": "218b74547a42b5baa7eeae811276258ba1271774", |
| 3332 | "date": "2026-10-08", |
| 3333 | "subject": "zdd-2-containment", |
| 3334 | "branch": "zdd-2-containment", |
| 3335 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-2-containment", |
| 3336 | "commits": 1, |
| 3337 | "credit": [ |
| 3338 | { |
| 3339 | "person": "Paul Campbell", |
| 3340 | "agents": [ |
| 3341 | "claude" |
| 3342 | ] |
| 3343 | } |
| 3344 | ] |
| 3345 | }, |
| 3346 | { |
| 3347 | "sha": "db8c3f061cd1890467fc6c4d5a2e6d9418fd59e1", |
| 3348 | "date": "2026-10-08", |
| 3349 | "subject": "zdd-4 task 1: Manifest.Swap, the release's own demand (additive)", |
| 3350 | "branch": "zdd-4-release-side", |
| 3351 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-4-release-side", |
| 3352 | "commits": 26, |
| 3353 | "credit": [ |
| 3354 | { |
| 3355 | "person": "Paul Campbell", |
| 3356 | "agents": [ |
| 3357 | "claude" |
| 3358 | ] |
| 3359 | } |
| 3360 | ] |
| 3361 | }, |
| 3362 | { |
| 3363 | "sha": "8e066e29ff08d987ab63b3e3b71436d16787f630", |
| 3364 | "date": "2026-10-08", |
| 3365 | "subject": "zdd-1-generations", |
| 3366 | "branch": "zdd-1-generations", |
| 3367 | "branch_url": "https://amadan.net/carlos/platform/-/branch/zdd-1-generations", |
| 3368 | "commits": 1, |
| 3369 | "credit": [ |
| 3370 | { |
| 3371 | "person": "Paul Campbell", |
| 3372 | "agents": [ |
| 3373 | "claude" |
| 3374 | ] |
| 3375 | } |
| 3376 | ] |
| 3377 | }, |
| 3378 | { |
| 3379 | "sha": "1621d271a7a8db8f34f65b8a25ce44eeaefdcc83", |
| 3380 | "date": "2026-10-08", |
| 3381 | "subject": "db-pull-at: carlos db pull/query --at reads a database as of a past time (#262)", |
| 3382 | "branch": "db-pull-at", |
| 3383 | "branch_url": "https://amadan.net/carlos/platform/-/branch/db-pull-at", |
| 3384 | "commits": 4, |
| 3385 | "discussions": [ |
| 3386 | { |
| 3387 | "id": 262, |
| 3388 | "title": "carlos db pull/query --at: read a database as of a past time", |
| 3389 | "state": "closed" |
| 3390 | } |
| 3391 | ], |
| 3392 | "docs": [ |
| 3393 | "/docs/cli#carlos-db" |
| 3394 | ], |
| 3395 | "credit": [ |
| 3396 | { |
| 3397 | "person": "Paul Campbell", |
| 3398 | "agents": [ |
| 3399 | "claude" |
| 3400 | ] |
| 3401 | } |
| 3402 | ] |
| 3403 | }, |
| 3404 | { |
| 3405 | "sha": "04aaa23b2e3773521393e9444eec88af211427ae", |
| 3406 | "date": "2026-10-08", |
| 3407 | "subject": "instances set-environment/set-channel: say what a 404 really was (#264)", |
| 3408 | "branch": "setenv-box-route-error", |
| 3409 | "branch_url": "https://amadan.net/carlos/platform/-/branch/setenv-box-route-error", |
| 3410 | "commits": 1, |
| 3411 | "discussions": [ |
| 3412 | { |
| 3413 | "id": 264, |
| 3414 | "title": "instances set-environment says 'not found: check --account' for a box route with no instance record, so binding an environment needs root on the box", |
| 3415 | "state": "closed" |
| 3416 | } |
| 3417 | ], |
| 3418 | "credit": [ |
| 3419 | { |
| 3420 | "person": "Paul Campbell", |
| 3421 | "agents": [ |
| 3422 | "claude" |
| 3423 | ] |
| 3424 | } |
| 3425 | ] |
| 3426 | }, |
| 3427 | { |
| 3428 | "sha": "4a51a6daac3582709ac2af89bd9071eb0e7375c3", |
| 3429 | "date": "2026-10-08", |
| 3430 | "subject": "moves-phase1-3b", |
| 3431 | "branch": "moves-phase1-3b", |
| 3432 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-3b", |
| 3433 | "commits": 1, |
| 3434 | "credit": [ |
| 3435 | { |
| 3436 | "person": "Paul Campbell", |
| 3437 | "agents": [ |
| 3438 | "claude" |
| 3439 | ] |
| 3440 | } |
| 3441 | ] |
| 3442 | }, |
| 3443 | { |
| 3444 | "sha": "81d0cc609fbe24d0c9d8b5c2f986a93e925c8c4c", |
| 3445 | "date": "2026-10-08", |
| 3446 | "subject": "moves-phase1-3", |
| 3447 | "branch": "moves-phase1-3", |
| 3448 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-3", |
| 3449 | "commits": 1, |
| 3450 | "credit": [ |
| 3451 | { |
| 3452 | "person": "Paul Campbell", |
| 3453 | "agents": [ |
| 3454 | "claude" |
| 3455 | ] |
| 3456 | } |
| 3457 | ] |
| 3458 | }, |
| 3459 | { |
| 3460 | "sha": "56ebee16ff94107ba42eac33e4a72487611362c1", |
| 3461 | "date": "2026-10-08", |
| 3462 | "subject": "Roll incident #256: system apply restarts instance-control; app entries move with the host; CARLOS_HOST; WorkingDirectory for instances", |
| 3463 | "branch": "fix-roll-incident-256", |
| 3464 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-roll-incident-256", |
| 3465 | "commits": 5, |
| 3466 | "discussions": [ |
| 3467 | { |
| 3468 | "id": 256, |
| 3469 | "title": "v0.25.1 flagship roll incident: nested instances failed to start; one app lost its key directory", |
| 3470 | "state": "open" |
| 3471 | } |
| 3472 | ], |
| 3473 | "docs": [ |
| 3474 | "/docs/cli#what-an-instance-is-started-with", |
| 3475 | "/docs/cli#the-platform-s-own-binary", |
| 3476 | "/docs/cli#instance-layout", |
| 3477 | "/docs/cli#carlos-instance-control" |
| 3478 | ], |
| 3479 | "credit": [ |
| 3480 | { |
| 3481 | "person": "Paul Campbell", |
| 3482 | "agents": [ |
| 3483 | "claude" |
| 3484 | ] |
| 3485 | } |
| 3486 | ] |
| 3487 | }, |
| 3488 | { |
| 3489 | "sha": "4f26f15cb41ecfdd9214b49393c228399f34490b", |
| 3490 | "date": "2026-10-08", |
| 3491 | "subject": "moves-phase1-2", |
| 3492 | "branch": "moves-phase1-2", |
| 3493 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1-2", |
| 3494 | "commits": 1, |
| 3495 | "credit": [ |
| 3496 | { |
| 3497 | "person": "Paul Campbell", |
| 3498 | "agents": [ |
| 3499 | "claude" |
| 3500 | ] |
| 3501 | } |
| 3502 | ] |
| 3503 | }, |
| 3504 | { |
| 3505 | "sha": "76f728a910ff9c78856620801e712650b962f2cd", |
| 3506 | "date": "2026-10-08", |
| 3507 | "subject": "feat/hostclaim-console", |
| 3508 | "branch": "feat/hostclaim-console", |
| 3509 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-console", |
| 3510 | "commits": 1, |
| 3511 | "credit": [ |
| 3512 | { |
| 3513 | "person": "Paul Campbell", |
| 3514 | "agents": [ |
| 3515 | "claude", |
| 3516 | "codex" |
| 3517 | ] |
| 3518 | } |
| 3519 | ] |
| 3520 | }, |
| 3521 | { |
| 3522 | "sha": "a4cd300376ea2892f356df6b77761b391a43c88c", |
| 3523 | "date": "2026-10-07", |
| 3524 | "subject": "host, hostbox, registry, activator, provision, instancectl, cgroup, schedule, hostguard, console: claim Plan 6b, production assembly of the box wiring", |
| 3525 | "branch": "feat/hostclaim-box-assembly", |
| 3526 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-box-assembly", |
| 3527 | "commits": 2, |
| 3528 | "credit": [ |
| 3529 | { |
| 3530 | "person": "Paul Campbell", |
| 3531 | "agents": [ |
| 3532 | "claude", |
| 3533 | "codex" |
| 3534 | ] |
| 3535 | } |
| 3536 | ] |
| 3537 | }, |
| 3538 | { |
| 3539 | "sha": "9cf9f18f53aac403f49ad755089c41c490b7e735", |
| 3540 | "date": "2026-10-07", |
| 3541 | "subject": "stopevidence: an fd entry that exists but cannot be followed is unreadable, not closed", |
| 3542 | "branch": "fix/fdholders-lstat", |
| 3543 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Ffdholders-lstat", |
| 3544 | "commits": 1, |
| 3545 | "credit": [ |
| 3546 | { |
| 3547 | "person": "Paul Campbell", |
| 3548 | "agents": [ |
| 3549 | "claude" |
| 3550 | ] |
| 3551 | } |
| 3552 | ] |
| 3553 | }, |
| 3554 | { |
| 3555 | "sha": "8e9ac1b8471dc10ba63921357e4e179307fb3f4d", |
| 3556 | "date": "2026-10-07", |
| 3557 | "subject": "stopevidence: FDHolders matches the open file's device and inode, not only its path", |
| 3558 | "branch": "fix/fdholders-inode", |
| 3559 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Ffdholders-inode", |
| 3560 | "commits": 1, |
| 3561 | "credit": [ |
| 3562 | { |
| 3563 | "person": "Paul Campbell", |
| 3564 | "agents": [ |
| 3565 | "claude" |
| 3566 | ] |
| 3567 | } |
| 3568 | ] |
| 3569 | }, |
| 3570 | { |
| 3571 | "sha": "e5adf3291b59686fb5e85506e519d247539537e8", |
| 3572 | "date": "2026-10-07", |
| 3573 | "subject": "moves copy gate: inventory only moves code, and skip the diff checks where git cannot name the merge base", |
| 3574 | "branch": "fix/moves-copy-gate-scope", |
| 3575 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fmoves-copy-gate-scope", |
| 3576 | "commits": 1, |
| 3577 | "credit": [ |
| 3578 | { |
| 3579 | "person": "Paul Campbell", |
| 3580 | "agents": [ |
| 3581 | "claude" |
| 3582 | ] |
| 3583 | } |
| 3584 | ] |
| 3585 | }, |
| 3586 | { |
| 3587 | "sha": "cfdb4e12fdbd759b1abdf0674039601c2952b070", |
| 3588 | "date": "2026-10-07", |
| 3589 | "subject": "hostclaim: the pre-flip conversion reads the move's own intent (C7 contract with moves)", |
| 3590 | "branch": "fix/c7-moves-intent", |
| 3591 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fc7-moves-intent", |
| 3592 | "commits": 1, |
| 3593 | "credit": [ |
| 3594 | { |
| 3595 | "person": "Paul Campbell", |
| 3596 | "agents": [ |
| 3597 | "claude" |
| 3598 | ] |
| 3599 | } |
| 3600 | ] |
| 3601 | }, |
| 3602 | { |
| 3603 | "sha": "17362eaf97bb5a83bc2aeaad0df40e805d331707", |
| 3604 | "date": "2026-10-07", |
| 3605 | "subject": "moves-phase1", |
| 3606 | "branch": "moves-phase1", |
| 3607 | "branch_url": "https://amadan.net/carlos/platform/-/branch/moves-phase1", |
| 3608 | "commits": 1, |
| 3609 | "credit": [ |
| 3610 | { |
| 3611 | "person": "Paul Campbell", |
| 3612 | "agents": [ |
| 3613 | "claude" |
| 3614 | ] |
| 3615 | } |
| 3616 | ] |
| 3617 | }, |
| 3618 | { |
| 3619 | "sha": "76b1400f9e175e6fa573f70e27e7323e2830eeaa", |
| 3620 | "date": "2026-10-07", |
| 3621 | "subject": "changelog: v0.25.0 (release step 10)", |
| 3622 | "branch": "changelog-v0.25.0", |
| 3623 | "branch_url": "https://amadan.net/carlos/platform/-/branch/changelog-v0.25.0", |
| 3624 | "commits": 1, |
| 3625 | "credit": [ |
| 3626 | { |
| 3627 | "person": "Paul Campbell", |
| 3628 | "agents": [ |
| 3629 | "claude" |
| 3630 | ] |
| 3631 | } |
| 3632 | ] |
| 3633 | } |
| 3634 | ] |
| 3635 | }, |
| 3636 | { |
| 3637 | "tag": "v0.25.1", |
| 3638 | "date": "2026-10-07", |
| 3639 | "sha": "289043db93be42a87efa5f376bb73bd62be748f4", |
| 3640 | "published": true, |
| 3641 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.25.1", |
| 3642 | "notes": { |
| 3643 | "form": "bullets", |
| 3644 | "sections": [ |
| 3645 | { |
| 3646 | "title": "", |
| 3647 | "bullets": [ |
| 3648 | { |
| 3649 | "md": "**Isolated instances now happen.** v0.25.0 moved instances into their own box only on a box whose isolation probe passed, and no box could pass. Part of the probe checked the box's addresses using a kind of socket the probe's own unit is not allowed to open. The control service now makes that check itself, reading the addresses from `/proc`. Boxes whose other checks pass are now ready, and their instances move as v0.25.0 described." |
| 3650 | }, |
| 3651 | { |
| 3652 | "md": "**Isolated instances stop cleanly.** Inside its own box, an app ran as the first process, where the kernel ignores any signal the app has no handler for. A Go app with no SIGTERM handler could not be stopped: each stop waited 20 seconds, killed it, and left the unit failed. A small init now runs first. It passes stop signals on to the app, cleans up exited processes, and exits with the app's status. An app that dies by a signal now shows as `exit 128+n` in its instance event line, so a crash on SIGSEGV reads `instance exited: exit 139`. It used to read `signal`." |
| 3653 | }, |
| 3654 | { |
| 3655 | "md": "**Temporary static sites, off until a deployment turns them on.** `carlos deploy --temporary ./dist` creates an app named `tmp-` plus six letters and digits, or `tmp-<name>` with `--app <name>`. It lives 7 days, or what `--ttl` says (1h to 30d). When its time is up it moves to the Trash, and it is purged 3 days later instead of 30. `carlos apps ttl` moves the expiry and `carlos apps keep` makes it permanent. A temporary app is served only at its own platform address, so `--host` and `--kind binary` are refused, and an account holds at most 20.", |
| 3656 | "docs": [ |
| 3657 | "/docs/cli#carlos-deploy", |
| 3658 | "/docs/cli#carlos-apps" |
| 3659 | ] |
| 3660 | }, |
| 3661 | { |
| 3662 | "md": "**Names starting with `tmp-` are reserved** for temporary sites. `carlos apps create`, `carlos add --app`, renames and `console grant` refuse them, whether or not temporary sites are on.", |
| 3663 | "docs": [ |
| 3664 | "/docs/cli#carlos-apps", |
| 3665 | "/docs/cli#carlos-add" |
| 3666 | ] |
| 3667 | }, |
| 3668 | { |
| 3669 | "md": "**`carlos apps list`** shows every app in the account, the Trash included, and when each expires or is purged.", |
| 3670 | "docs": [ |
| 3671 | "/docs/cli#carlos-apps" |
| 3672 | ] |
| 3673 | }, |
| 3674 | { |
| 3675 | "md": "**`carlos ship` checks the program.** For a Go binary, ship records its main package in the manifest. It refuses a release whose main package differs from the app's latest release. When the change is meant, ship with `--program-change`. `carlos deploy` has no such flag, so use `carlos ship --program-change` and then promote. Boxes check the bytes too, so a release shipped by an older client is refused at adoption and is not pointed live. A build the route has run before is always accepted, so going back across an intended change works.", |
| 3676 | "docs": [ |
| 3677 | "/docs/cli#carlos-ship", |
| 3678 | "/docs/cli#carlos-deploy" |
| 3679 | ] |
| 3680 | }, |
| 3681 | { |
| 3682 | "md": "**A console that will not start is rolled back.** After a box adopts a new build for a route with a named unit, such as the console, it waits for the unit to stay up and accept connections. If it doesn't, the box rolls back, refuses that promotion and alerts. A plain re-promote stays refused. `carlos promote --retry <version> <channel>` tries again. `carlos status --live` shows refused hosts.", |
| 3683 | "docs": [ |
| 3684 | "/docs/cli#carlos-promote", |
| 3685 | "/docs/cli#carlos-status" |
| 3686 | ] |
| 3687 | }, |
| 3688 | { |
| 3689 | "md": "**GeoIP for apps.** On a deployment that has published a GeoIP database, every request to an app carries the visitor's rough location in `X-Carlos-Geo-Country`, `X-Carlos-Geo-Subdivision`, `X-Carlos-Geo-Lat`, `X-Carlos-Geo-Lon` and `X-Carlos-Geo-Source`. Any of them can be missing; treat that as unknown. The edge removes any of these a visitor sends. Analytics count page views by country and credit the database. `carlos geo <address> --app <a>` gives the same answer for any address, and apps can call `GET /api/cli/apps/<account>/<app>/geo?ip=<address>`, at most 60 a minute. An app that shows visitors anything worked out from these headers must credit the database `X-Carlos-Geo-Source` names.", |
| 3690 | "docs": [ |
| 3691 | "/docs/cli#carlos-geo" |
| 3692 | ] |
| 3693 | } |
| 3694 | ] |
| 3695 | }, |
| 3696 | { |
| 3697 | "title": "For operators", |
| 3698 | "bullets": [ |
| 3699 | { |
| 3700 | "md": "**If your boxes have not run v0.25.0, read its operator notes first.** All of them apply to this release." |
| 3701 | }, |
| 3702 | { |
| 3703 | "md": "**Instances move to the nested layout on their own, and this time they will.** v0.25.0's note applies again. With no layout intent recorded, every box whose isolation probe passes starts moving its instances on the first change it sees after this release lands. Awake instances get an hour, then are stopped and moved. This includes boxes that already run v0.25.0 and recorded nothing. **To keep control,** record `carlos system layout revert` before you roll, then `carlos system layout migrate --box <label>` one box at a time, or put `CARLOS_LAYOUT_DEFAULT=flat` in a box's host.env to leave that box alone.", |
| 3704 | "docs": [ |
| 3705 | "/docs/cli#carlos-system" |
| 3706 | ] |
| 3707 | }, |
| 3708 | { |
| 3709 | "md": "**Before rolling, check one box:** `systemctl start carlos-instance-probe.service` then read `/run/carlos-control/probe.out`. It must say `ready: true`. The control service no longer opens a resolver that is one of the box's own addresses. It reports that as a failing `resolver-local` line, and if it cannot read the box's addresses it opens no resolver at all. Landlock must be in the booted kernel's `lsm=` list, and `/etc/resolv.conf` (or resolved's upstream list) must name a resolver that isn't on loopback." |
| 3710 | }, |
| 3711 | { |
| 3712 | "md": "**Roll the boxes before the console.** The rollback, wrong-program and `tmp-` checks run on the box, and so does removing forged GeoIP headers." |
| 3713 | }, |
| 3714 | { |
| 3715 | "md": "**Fix each console box's binding before you rely on the rollback.** The rollback check runs only when the console unit's `ExecStart` names the live link of the route stamped with that unit. Where it doesn't, `adopt` logs `binding: … restart not checked` and restarts the unit as before, unchecked. On each console box, read `systemctl show -p ExecStart console.service`, stamp that host with `carlos route --host <host> --unit console.service`, and clear the stamp from any other host with `--unit \"\"`. Until the binding is right, keep the final `systemctl restart` in your console roll.", |
| 3716 | "docs": [ |
| 3717 | "/docs/cli#carlos-route" |
| 3718 | ] |
| 3719 | }, |
| 3720 | { |
| 3721 | "md": "**The rollback check is on everywhere.** After adopting a build for a route with a named unit, the box waits up to 30 seconds (`CARLOS_UNIT_SETTLE`, at least 5s) for the unit to stay up on the new build and accept connections. If it does not, the box rolls back, writes a refusal and alerts through SNS or `CARLOS_ALERT_WEBHOOK`. If your console takes longer than that to start listening, raise `CARLOS_UNIT_SETTLE` on its box before you fix the binding. With `CONSOLE_GEOIP_DB` set, the console now checks that file in a separate process before it listens." |
| 3722 | }, |
| 3723 | { |
| 3724 | "md": "**The wrong-program check is on everywhere.** A box refuses a staged binary whose Go main package differs from the live build's and from every program that route has run before, unless its manifest records `--program-change`. The refused build is not pointed live and nothing restarts. Each route starts its history from its live binary on its first pass. The console's ship door makes the same check once the console runs this release. The `carlos` binary is never a console artifact; build the console from `./cmd/console`." |
| 3725 | }, |
| 3726 | { |
| 3727 | "md": "**Dev proofs are off.** They are off unless a box has `/etc/carlos/proof-policy.json` (root, mode 0644). On a proving console box, run `carlos proof keygen` as root, then write a policy file with a `prove` block: the apps, the prover's name, how long a build must run (`after`, such as 15m) and `key_file`. That box then mints a proof for each build that runs healthily for that long. On a requiring box, a `require` entry names the app, the prover and its public key. A new build of that app is then adopted only with a proof for those exact bytes, or if the box has already run that build healthily. Carry a proof with `carlos proof get` against the proving deployment and `carlos proof put` against the requiring one. `carlos status --live` shows a host that is waiting. A policy file that does not parse holds every named-unit route on its current build and says so in the journal. To switch the requirement off, delete the `require` entry (or the file) as root and run `carlos adopt --stage-only`. The box then logs once an hour that it is off. Write policy files on the box over SSM, not through tofu `user_data`.", |
| 3728 | "docs": [ |
| 3729 | "/docs/cli#carlos-proof", |
| 3730 | "/docs/cli#carlos-status", |
| 3731 | "/docs/cli#carlos-adopt" |
| 3732 | ] |
| 3733 | }, |
| 3734 | { |
| 3735 | "md": "**Temporary sites are off until you set `CARLOS_TEMPORARY_APPS=1` on the console.** The console adds four columns to its `apps` table when it starts. The change is additive. Its expiry pass runs every 5 minutes either way, and with no temporary apps it does nothing. Before you turn them on, roll every box, then check that no box's registry and neither the console's `apps` nor its `owners` table has a `tmp-` name. An expiry drops a temporary app's routes, so rename or remove any `tmp-` name you find first." |
| 3736 | }, |
| 3737 | { |
| 3738 | "md": "**Platform GeoIP sends nothing until you publish a database.** From this release every edge removes forged `X-Carlos-Geo-` headers and watches the bucket for a database. `carlos system geoip publish <file.mmdb>` sends one, and every edge picks it up within 12 minutes. Publish only after `carlos system geoip status` says `ready`, because a box on an older release passes a visitor's forged headers straight through. A retired box that still has `control/edges/<label>.json` keeps it from saying `ready`; delete that record. `carlos system geoip off` removes the database. On the console box, check that the console can read `/data/carlos/geoip/current`: with `CONSOLE_GEOIP_DB` unset, the console's region guess now uses that copy.", |
| 3739 | "docs": [ |
| 3740 | "/docs/cli#carlos-system" |
| 3741 | ] |
| 3742 | }, |
| 3743 | { |
| 3744 | "md": "**The GeoIP feed is off until you set `CONSOLE_GEOIP_FEED`.** `dbip-city-lite` is free, needs nothing else, and requires the credit the platform already shows. For MaxMind, also set `CONSOLE_GEOIP_MAXMIND_ACCOUNT` and `CONSOLE_GEOIP_MAXMIND_KEY`. The console checks once a day. A GeoLite2 database is dropped 30 days after it was built. Before you publish GeoLite2, apply the `deployment-buckets` module version that expires old copies under `control/geoip/` after a day. It is the module's first lifecycle configuration, and a bucket holds one, so check whether yours already has one before you apply." |
| 3745 | }, |
| 3746 | { |
| 3747 | "md": "**A new `geoip` box alert** sits beside `disk`, `mem`, `cpu` and `lag`. It fires after 30 minutes when the loaded database is over 45 days old, a GeoLite2 database is 21 days old, the database has expired, a box has not loaded the published database for over an hour, or the feed has failed 7 checks in a row. With no database and no feed it never fires." |
| 3748 | }, |
| 3749 | { |
| 3750 | "md": "**Host claims stay dormant. Leave `CARLOS_HOST_CLAIM` unset**, on the console and on every box. On a box, any value that is not blank stops the agent from starting. On the console, it starts claim recovery and backfill that have nothing to work from yet. **Leave `CARLOS_CONSOLE_ID` unset** on the console too. **Do not run `carlos system guard-arm`.** It replaces how the update, edge and console units start, and once armed it is enforced whatever `CARLOS_HOST_CLAIM` says. With all three left alone, nothing in this release writes or reads host claims.", |
| 3751 | "docs": [ |
| 3752 | "/docs/cli#carlos-system" |
| 3753 | ] |
| 3754 | } |
| 3755 | ] |
| 3756 | } |
| 3757 | ] |
| 3758 | }, |
| 3759 | "changes": [ |
| 3760 | { |
| 3761 | "sha": "289043db93be42a87efa5f376bb73bd62be748f4", |
| 3762 | "date": "2026-10-07", |
| 3763 | "subject": "changelog: carlosframework.com/platform/changelog, generated from git, release notes and Amadan", |
| 3764 | "branch": "platform-changelog", |
| 3765 | "branch_url": "https://amadan.net/carlos/platform/-/branch/platform-changelog", |
| 3766 | "commits": 8, |
| 3767 | "credit": [ |
| 3768 | { |
| 3769 | "person": "Paul Campbell", |
| 3770 | "agents": [ |
| 3771 | "claude" |
| 3772 | ] |
| 3773 | } |
| 3774 | ] |
| 3775 | }, |
| 3776 | { |
| 3777 | "sha": "3407d114f8c8a413214b88295457263bea50dcb7", |
| 3778 | "date": "2026-10-07", |
| 3779 | "subject": "feat/hostclaim-console", |
| 3780 | "branch": "feat/hostclaim-console", |
| 3781 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-console", |
| 3782 | "commits": 1, |
| 3783 | "credit": [ |
| 3784 | { |
| 3785 | "person": "Paul Campbell", |
| 3786 | "agents": [ |
| 3787 | "claude", |
| 3788 | "codex" |
| 3789 | ] |
| 3790 | } |
| 3791 | ] |
| 3792 | }, |
| 3793 | { |
| 3794 | "sha": "cbc0922e76bd5898f1de8a6802ae5c047f16f193", |
| 3795 | "date": "2026-10-07", |
| 3796 | "subject": "feat/hostclaim-floor", |
| 3797 | "branch": "feat/hostclaim-floor", |
| 3798 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-floor", |
| 3799 | "commits": 1, |
| 3800 | "discussions": [ |
| 3801 | { |
| 3802 | "id": 250, |
| 3803 | "title": "Host floor guard: fix these before anyone runs guard-arm (Opus review of Plans 8/8b)", |
| 3804 | "state": "open" |
| 3805 | } |
| 3806 | ], |
| 3807 | "docs": [ |
| 3808 | "/docs/cli#host-lifecycle-guard" |
| 3809 | ], |
| 3810 | "credit": [ |
| 3811 | { |
| 3812 | "person": "Paul Campbell", |
| 3813 | "agents": [ |
| 3814 | "claude", |
| 3815 | "codex" |
| 3816 | ] |
| 3817 | } |
| 3818 | ] |
| 3819 | }, |
| 3820 | { |
| 3821 | "sha": "e0bec091ea188d93f06372dc8695b4f3f71742d2", |
| 3822 | "date": "2026-10-07", |
| 3823 | "subject": "GeoIP follow-up (#241): DirStore.Put CAS gate by Stat and streamed hash, so an oversized object at the key is never read into memory (Astra R2-1); restore the thirteen code-review reports lost with the build worktree; Astra round 14 merge-ready.", |
| 3824 | "branch": "geoip-followups", |
| 3825 | "branch_url": "https://amadan.net/carlos/platform/-/branch/geoip-followups", |
| 3826 | "commits": 2, |
| 3827 | "discussions": [ |
| 3828 | { |
| 3829 | "id": 241, |
| 3830 | "title": "Expose the platform's GeoIP lookup to apps (headers and/or lookup endpoint)", |
| 3831 | "state": "closed" |
| 3832 | } |
| 3833 | ], |
| 3834 | "credit": [ |
| 3835 | { |
| 3836 | "person": "Paul Campbell", |
| 3837 | "agents": [ |
| 3838 | "claude" |
| 3839 | ] |
| 3840 | } |
| 3841 | ] |
| 3842 | }, |
| 3843 | { |
| 3844 | "sha": "6bdaba34512cb7eaaa3276d7f96a56f43d41426e", |
| 3845 | "date": "2026-10-07", |
| 3846 | "subject": "Platform GeoIP for apps (#241): bucket-mirrored database with hot swap on every edge; X-Carlos-Geo-* headers set by the ingress edge and carried across hops and tunnels; analytics countries with attribution; carlos system geoip publish/status/off; auto-update feed (DB-IP Lite default, GeoLite2 or paid MaxMind GeoIP2); geoip box alert; console follower, GET /api/cli/apps/{a}/{app}/geo and carlos geo; untrusted .mmdb verified only in a killable, memory-capped child. Spec rev 13 (Astra-accepted), 13 Astra code-review rounds.", |
| 3847 | "branch": "geoip-for-apps", |
| 3848 | "branch_url": "https://amadan.net/carlos/platform/-/branch/geoip-for-apps", |
| 3849 | "commits": 59, |
| 3850 | "discussions": [ |
| 3851 | { |
| 3852 | "id": 241, |
| 3853 | "title": "Expose the platform's GeoIP lookup to apps (headers and/or lookup endpoint)", |
| 3854 | "state": "closed" |
| 3855 | }, |
| 3856 | { |
| 3857 | "id": 249, |
| 3858 | "title": "A carlos system verb to retire a box (delete its edges record)", |
| 3859 | "state": "open" |
| 3860 | } |
| 3861 | ], |
| 3862 | "docs": [ |
| 3863 | "/docs/cli#carlos-analytics", |
| 3864 | "/docs/cli#headers-your-app-receives", |
| 3865 | "/docs/cli#carlos-geo", |
| 3866 | "/docs/cli#platform-geoip" |
| 3867 | ], |
| 3868 | "credit": [ |
| 3869 | { |
| 3870 | "person": "Paul Campbell", |
| 3871 | "agents": [ |
| 3872 | "claude" |
| 3873 | ] |
| 3874 | } |
| 3875 | ] |
| 3876 | }, |
| 3877 | { |
| 3878 | "sha": "40b6f50c87d7d37ed87dd5c68380b0f0f293d914", |
| 3879 | "date": "2026-10-07", |
| 3880 | "subject": "Nested instances: a minimal init as PID 1 forwards stop signals and reaps, so apps stop cleanly (#126)", |
| 3881 | "branch": "fix-instance-init", |
| 3882 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-instance-init", |
| 3883 | "commits": 1, |
| 3884 | "discussions": [ |
| 3885 | { |
| 3886 | "id": 126, |
| 3887 | "title": "activator: exec-backed instances share one uid and one flat DataDir — cross-tenant and cross-app", |
| 3888 | "state": "open" |
| 3889 | } |
| 3890 | ], |
| 3891 | "docs": [ |
| 3892 | "/docs/cli#carlos-instance-exec" |
| 3893 | ], |
| 3894 | "credit": [ |
| 3895 | { |
| 3896 | "person": "Paul Campbell", |
| 3897 | "agents": [ |
| 3898 | "claude" |
| 3899 | ] |
| 3900 | } |
| 3901 | ] |
| 3902 | }, |
| 3903 | { |
| 3904 | "sha": "9e628024ee00acd9be606c90cf2b480f866238f7", |
| 3905 | "date": "2026-10-07", |
| 3906 | "subject": "Console release defences: D1 settle and rollback, D2 wrong-program refusal, D3 opt-in dev proofs (after the 2026-10-06 console outage)", |
| 3907 | "branch": "design-console-release-defences", |
| 3908 | "branch_url": "https://amadan.net/carlos/platform/-/branch/design-console-release-defences", |
| 3909 | "commits": 62, |
| 3910 | "discussions": [ |
| 3911 | { |
| 3912 | "id": 252, |
| 3913 | "title": "Console release defences: rulings and open items from the overnight build", |
| 3914 | "state": "open" |
| 3915 | } |
| 3916 | ], |
| 3917 | "docs": [ |
| 3918 | "/docs/cli#carlos-proof" |
| 3919 | ], |
| 3920 | "credit": [ |
| 3921 | { |
| 3922 | "person": "Paul Campbell", |
| 3923 | "agents": [ |
| 3924 | "claude" |
| 3925 | ] |
| 3926 | } |
| 3927 | ] |
| 3928 | }, |
| 3929 | { |
| 3930 | "sha": "3de0b0fca09e7022cfee5d397ffd3f30fdf34578", |
| 3931 | "date": "2026-10-07", |
| 3932 | "subject": "Probe: resolver checks no longer need netlink; the control service reads local addresses from /proc (#126)", |
| 3933 | "branch": "fix-probe-resolver-ports", |
| 3934 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-probe-resolver-ports", |
| 3935 | "commits": 1, |
| 3936 | "discussions": [ |
| 3937 | { |
| 3938 | "id": 126, |
| 3939 | "title": "activator: exec-backed instances share one uid and one flat DataDir — cross-tenant and cross-app", |
| 3940 | "state": "open" |
| 3941 | } |
| 3942 | ], |
| 3943 | "credit": [ |
| 3944 | { |
| 3945 | "person": "Paul Campbell", |
| 3946 | "agents": [ |
| 3947 | "claude" |
| 3948 | ] |
| 3949 | } |
| 3950 | ] |
| 3951 | }, |
| 3952 | { |
| 3953 | "sha": "1da67e63e481c3a7b1768c4309c42c20dea3c254", |
| 3954 | "date": "2026-10-07", |
| 3955 | "subject": "Temporary static sites: self-expiring tmp- apps, trashed at expiry, purged 3 days later", |
| 3956 | "branch": "design-temporary-sites", |
| 3957 | "branch_url": "https://amadan.net/carlos/platform/-/branch/design-temporary-sites", |
| 3958 | "commits": 1, |
| 3959 | "docs": [ |
| 3960 | "/docs/cli#carlos-apps", |
| 3961 | "/docs/cli#carlos-deploy" |
| 3962 | ], |
| 3963 | "credit": [ |
| 3964 | { |
| 3965 | "person": "Paul Campbell", |
| 3966 | "agents": [ |
| 3967 | "claude" |
| 3968 | ] |
| 3969 | } |
| 3970 | ] |
| 3971 | } |
| 3972 | ] |
| 3973 | }, |
| 3974 | { |
| 3975 | "tag": "v0.25.0", |
| 3976 | "date": "2026-10-07", |
| 3977 | "sha": "2b2cc879a669b850bf8ec410b13d20673709477d", |
| 3978 | "published": true, |
| 3979 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.25.0", |
| 3980 | "notes": { |
| 3981 | "form": "bullets", |
| 3982 | "sections": [ |
| 3983 | { |
| 3984 | "title": "", |
| 3985 | "bullets": [ |
| 3986 | { |
| 3987 | "md": "**Each instance runs in its own box.** Instances the platform starts on demand used to share one user and one data directory on a box, so one app could read another app's files. From this release, a box whose isolation checks pass moves every such instance into its own directory and its own mount and process namespace, where it sees its own files and nothing else. A sleeping instance moves at once; an awake one gets an hour to go to sleep, then is stopped briefly and moved. New instances on that box start out isolated. `carlos status --layout` shows where each box is.", |
| 3988 | "branches": [ |
| 3989 | "tenant-iso-default-nested", |
| 3990 | "tenant-iso-layout" |
| 3991 | ], |
| 3992 | "docs": [ |
| 3993 | "/docs/cli#carlos-status" |
| 3994 | ] |
| 3995 | }, |
| 3996 | { |
| 3997 | "md": "**`carlos system layout`** lets an operator choose instead: `migrate --box <label>` moves one box at a time, and `revert` moves everything back. `status` prints what is recorded.", |
| 3998 | "branches": [ |
| 3999 | "tenant-iso-plan5" |
| 4000 | ], |
| 4001 | "docs": [ |
| 4002 | "/docs/cli#carlos-system" |
| 4003 | ] |
| 4004 | }, |
| 4005 | { |
| 4006 | "md": "**Instances get CPU and IO limits** beside their memory cap, see only their own app's build, and can't reach loopback or private addresses on the box except its DNS resolver. New starts are refused while the disk is nearly full.", |
| 4007 | "branches": [ |
| 4008 | "tenant-iso-hardening" |
| 4009 | ] |
| 4010 | }, |
| 4011 | { |
| 4012 | "md": "**Custom domains can require proof.** On a deployment that sets `CONSOLE_DOMAIN_PROOF=true`, `carlos domains attach` reserves the name and prints a TXT record, and the name isn't served until `carlos domains verify` finds it. Names under another account's platform domain are refused everywhere.", |
| 4013 | "branches": [ |
| 4014 | "tenant-iso-domains" |
| 4015 | ], |
| 4016 | "docs": [ |
| 4017 | "/docs/cli#carlos-domains" |
| 4018 | ] |
| 4019 | }, |
| 4020 | { |
| 4021 | "md": "**Only a platform operator can add an upstream address** to an instance. Upstreams an instance already has keep working, and can be kept, reordered or removed.", |
| 4022 | "branches": [ |
| 4023 | "tenant-iso-routes" |
| 4024 | ] |
| 4025 | }, |
| 4026 | { |
| 4027 | "md": "**Cookies stay within their account.** On a platform hostname, a cookie whose `Domain` reaches beyond the app's own account is made host-only by the edge.", |
| 4028 | "branches": [ |
| 4029 | "tenant-iso-cookies" |
| 4030 | ] |
| 4031 | }, |
| 4032 | { |
| 4033 | "md": "**Instance catch-all domains.** `carlos domains attach --app <a> '*.<parent>'` gives every instance of the app a public name, `<slug>.<parent>`, with no per-instance claim or DNS.", |
| 4034 | "branches": [ |
| 4035 | "instance-catchall" |
| 4036 | ], |
| 4037 | "docs": [ |
| 4038 | "/docs/cli#carlos-domains" |
| 4039 | ] |
| 4040 | }, |
| 4041 | { |
| 4042 | "md": "**`carlos email test` sends HTML too.** The test message is now multipart, with a plain-text and an HTML part, so it shows that HTML mail gets through. Apps can send any MIME message over their credential.", |
| 4043 | "branches": [ |
| 4044 | "multipart-email-support" |
| 4045 | ], |
| 4046 | "docs": [ |
| 4047 | "/docs/cli#carlos-email" |
| 4048 | ] |
| 4049 | }, |
| 4050 | { |
| 4051 | "md": "**Smaller fixes.** Re-attaching a static site's own hostname to flip `--wildcard` or `--catchall` no longer turns its route into an alias of itself. A box no longer places a certificate order every hour for a platform domain whose DNS zone its provider doesn't hold.", |
| 4052 | "branches": [ |
| 4053 | "first-route-wildcard", |
| 4054 | "wildcard-zone-check" |
| 4055 | ] |
| 4056 | } |
| 4057 | ] |
| 4058 | }, |
| 4059 | { |
| 4060 | "title": "For operators", |
| 4061 | "bullets": [ |
| 4062 | { |
| 4063 | "md": "**Instances move to the nested layout on their own.** This is the first release on which isolated instances run. With no layout intent recorded, every box whose isolation probe passes starts moving its instances on the first change it sees after this release lands. Awake instances get an hour, then are stopped and moved. A move refused for a reason a tenant could have caused (a planted hard link, a symlinked directory) keeps that instance stopped until an operator clears it; `carlos status --layout` names it. **To keep control,** record `carlos system layout revert` before you roll, then `carlos system layout migrate --box <label>` one box at a time, or put `CARLOS_LAYOUT_DEFAULT=flat` in a box's host.env to leave that box alone.", |
| 4064 | "branches": [ |
| 4065 | "tenant-iso-default-nested" |
| 4066 | ], |
| 4067 | "docs": [ |
| 4068 | "/docs/cli#carlos-status", |
| 4069 | "/docs/cli#carlos-system" |
| 4070 | ] |
| 4071 | }, |
| 4072 | { |
| 4073 | "md": "**Before rolling, check one box:** `systemctl start carlos-instance-probe.service` then read `/run/carlos-control/probe.out`. It must say `ready: true`. Landlock must be in the booted kernel's `lsm=` list, and `/etc/resolv.conf` (or resolved's upstream list) must name a resolver that isn't on loopback. A box that fails any of these stays flat and says why.", |
| 4074 | "branches": [ |
| 4075 | "tenant-iso-layout", |
| 4076 | "tenant-iso-hardening" |
| 4077 | ] |
| 4078 | }, |
| 4079 | { |
| 4080 | "md": "**Roll the boxes before the console.** The console now trusts a loopback `X-Forwarded-For` only when the edge has signed it, and switches to requiring the signature after it first sees one. Domain proof needs boxes that understand pending claims.", |
| 4081 | "branches": [ |
| 4082 | "tenant-iso-routes" |
| 4083 | ] |
| 4084 | }, |
| 4085 | { |
| 4086 | "md": "**Rolling back** to a release before v0.25.0 is refused while any box has nested instances. Run `carlos system layout revert`, wait until `carlos status --layout` shows every instance `flat`, then roll back.", |
| 4087 | "branches": [ |
| 4088 | "tenant-iso-plan5" |
| 4089 | ], |
| 4090 | "docs": [ |
| 4091 | "/docs/cli#carlos-system", |
| 4092 | "/docs/cli#carlos-status" |
| 4093 | ] |
| 4094 | }, |
| 4095 | { |
| 4096 | "md": "**Settings worth turning on** for a deployment that hosts other people's apps: `CONSOLE_DOMAIN_PROOF=true` and `CONSOLE_RESERVE_PLATFORM_DOMAINS=true` on the console, after the boxes have rolled. `CONSOLE_SECRETS_ENVELOPE_V2=true` makes new secrets bound to their account and app; set it only once every box runs this release.", |
| 4097 | "branches": [ |
| 4098 | "tenant-iso-domains" |
| 4099 | ] |
| 4100 | } |
| 4101 | ] |
| 4102 | } |
| 4103 | ] |
| 4104 | }, |
| 4105 | "changes": [ |
| 4106 | { |
| 4107 | "sha": "2b2cc879a669b850bf8ec410b13d20673709477d", |
| 4108 | "date": "2026-10-07", |
| 4109 | "subject": "Isolated exec: nested is the default layout on a ready box; CARLOS_LAYOUT_DEFAULT=flat opts out (#126)", |
| 4110 | "branch": "tenant-iso-default-nested", |
| 4111 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-default-nested", |
| 4112 | "commits": 1, |
| 4113 | "discussions": [ |
| 4114 | { |
| 4115 | "id": 126, |
| 4116 | "title": "activator: exec-backed instances share one uid and one flat DataDir — cross-tenant and cross-app", |
| 4117 | "state": "open" |
| 4118 | } |
| 4119 | ], |
| 4120 | "docs": [ |
| 4121 | "/docs/cli#instance-layout" |
| 4122 | ], |
| 4123 | "credit": [ |
| 4124 | { |
| 4125 | "person": "Paul Campbell", |
| 4126 | "agents": [ |
| 4127 | "claude" |
| 4128 | ] |
| 4129 | } |
| 4130 | ] |
| 4131 | }, |
| 4132 | { |
| 4133 | "sha": "337b106216099ae7be9df3019b0ce6f9b6d816c3", |
| 4134 | "date": "2026-10-07", |
| 4135 | "subject": "Region HA contracts for the claim (L13) and moves sessions, dormant", |
| 4136 | "branch": "region-ha-contracts", |
| 4137 | "branch_url": "https://amadan.net/carlos/platform/-/branch/region-ha-contracts", |
| 4138 | "commits": 1, |
| 4139 | "credit": [ |
| 4140 | { |
| 4141 | "person": "Paul Campbell", |
| 4142 | "agents": [ |
| 4143 | "claude" |
| 4144 | ] |
| 4145 | } |
| 4146 | ] |
| 4147 | }, |
| 4148 | { |
| 4149 | "sha": "383fae0864c784cd1166e429db76638644cdb993", |
| 4150 | "date": "2026-10-06", |
| 4151 | "subject": "Edge: tenant cookies can't reach beyond their own account; never cache a trailer Set-Cookie (#217)", |
| 4152 | "branch": "tenant-iso-cookies", |
| 4153 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-cookies", |
| 4154 | "commits": 1, |
| 4155 | "discussions": [ |
| 4156 | { |
| 4157 | "id": 217, |
| 4158 | "title": "oncarlos.com is not on the Public Suffix List: tenants share cookies and count as same-site", |
| 4159 | "state": "open" |
| 4160 | } |
| 4161 | ], |
| 4162 | "docs": [ |
| 4163 | "/docs/cli#carlos-domains" |
| 4164 | ], |
| 4165 | "credit": [ |
| 4166 | { |
| 4167 | "person": "Paul Campbell", |
| 4168 | "agents": [ |
| 4169 | "claude" |
| 4170 | ] |
| 4171 | } |
| 4172 | ] |
| 4173 | }, |
| 4174 | { |
| 4175 | "sha": "f5ef8e3631a9185954e3b96886a914f1a11278b5", |
| 4176 | "date": "2026-10-06", |
| 4177 | "subject": "Isolated exec, plan 5: the console door and carlos system layout; nested minting; downgrade guards with LayoutFloor v0.25.0 (#126)", |
| 4178 | "branch": "tenant-iso-plan5", |
| 4179 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-plan5", |
| 4180 | "commits": 1, |
| 4181 | "discussions": [ |
| 4182 | { |
| 4183 | "id": 126, |
| 4184 | "title": "activator: exec-backed instances share one uid and one flat DataDir — cross-tenant and cross-app", |
| 4185 | "state": "open" |
| 4186 | }, |
| 4187 | { |
| 4188 | "id": 132, |
| 4189 | "title": "Authenticate maintenance workers and bind result publication", |
| 4190 | "state": "open" |
| 4191 | } |
| 4192 | ], |
| 4193 | "docs": [ |
| 4194 | "/docs/cli#the-platform-s-own-binary", |
| 4195 | "/docs/cli#instance-layout" |
| 4196 | ], |
| 4197 | "credit": [ |
| 4198 | { |
| 4199 | "person": "Paul Campbell", |
| 4200 | "agents": [ |
| 4201 | "claude" |
| 4202 | ] |
| 4203 | } |
| 4204 | ] |
| 4205 | }, |
| 4206 | { |
| 4207 | "sha": "84c80eba62407164546e5f70da1505e83ce7371b", |
| 4208 | "date": "2026-10-06", |
| 4209 | "subject": "hostbox: verify box identity with boxid.Verifier.Enroll (main build fix)", |
| 4210 | "branch": "fix/hostbox-boxid-enroll", |
| 4211 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fhostbox-boxid-enroll", |
| 4212 | "commits": 1, |
| 4213 | "credit": [ |
| 4214 | { |
| 4215 | "person": "Paul Campbell", |
| 4216 | "agents": [ |
| 4217 | "claude" |
| 4218 | ] |
| 4219 | } |
| 4220 | ] |
| 4221 | }, |
| 4222 | { |
| 4223 | "sha": "d649d8d44f0db98b4fb3e8cd813c3b02652b52b0", |
| 4224 | "date": "2026-10-06", |
| 4225 | "subject": "hostwrite: the inert selection interface for host-specific writers (claim Plan 6 Task 2)", |
| 4226 | "branch": "feat/hostclaim-box", |
| 4227 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-box", |
| 4228 | "commits": 12, |
| 4229 | "credit": [ |
| 4230 | { |
| 4231 | "person": "Paul Campbell", |
| 4232 | "agents": [ |
| 4233 | "claude", |
| 4234 | "codex" |
| 4235 | ] |
| 4236 | } |
| 4237 | ] |
| 4238 | }, |
| 4239 | { |
| 4240 | "sha": "3e12133ff47671eb67858ee6560e4a2c28c2495b", |
| 4241 | "date": "2026-10-06", |
| 4242 | "subject": "Region HA spec 1 rev 5.4 and plan 1b: claim readers and evidence, dormant", |
| 4243 | "branch": "design-region-ha-rev5", |
| 4244 | "branch_url": "https://amadan.net/carlos/platform/-/branch/design-region-ha-rev5", |
| 4245 | "commits": 1, |
| 4246 | "discussions": [ |
| 4247 | { |
| 4248 | "id": 236, |
| 4249 | "title": "Host claim Plan 8: three decisions for Paul (floor release, declare-lost attestation, actor roster)", |
| 4250 | "state": "open" |
| 4251 | } |
| 4252 | ], |
| 4253 | "credit": [ |
| 4254 | { |
| 4255 | "person": "Paul Campbell", |
| 4256 | "agents": [ |
| 4257 | "claude" |
| 4258 | ] |
| 4259 | } |
| 4260 | ] |
| 4261 | }, |
| 4262 | { |
| 4263 | "sha": "1c43c2ce82f621c6ac84a623db54f0ef63075603", |
| 4264 | "date": "2026-10-06", |
| 4265 | "subject": "Routes: only operators add instance upstreams; the console trusts loopback X-Forwarded-For only with the edge's host-bound proof (#214 items 4-5, #50)", |
| 4266 | "branch": "tenant-iso-routes", |
| 4267 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-routes", |
| 4268 | "commits": 1, |
| 4269 | "discussions": [ |
| 4270 | { |
| 4271 | "id": 50, |
| 4272 | "title": "member-stated TCP upstreams: decide the trust policy for addrs on the console door", |
| 4273 | "state": "open" |
| 4274 | }, |
| 4275 | { |
| 4276 | "id": 170, |
| 4277 | "title": "Reconcile's OnRecords hands over a partial record map without saying so", |
| 4278 | "state": "open" |
| 4279 | }, |
| 4280 | { |
| 4281 | "id": 214, |
| 4282 | "title": "Isolation the nested layout does not give: CPU/IO/disk limits, shared network, readable binaries, private route addrs, trusted XFF", |
| 4283 | "state": "closed" |
| 4284 | } |
| 4285 | ], |
| 4286 | "docs": [ |
| 4287 | "/docs/cli#carlos-instances" |
| 4288 | ], |
| 4289 | "credit": [ |
| 4290 | { |
| 4291 | "person": "Paul Campbell", |
| 4292 | "agents": [ |
| 4293 | "claude" |
| 4294 | ] |
| 4295 | } |
| 4296 | ] |
| 4297 | }, |
| 4298 | { |
| 4299 | "sha": "9bed97b50f08f78cd3eefefe30a154ad58b05b0d", |
| 4300 | "date": "2026-10-06", |
| 4301 | "subject": "Domains: opt-in proof of control; account namespaces are their own; fleet boxes see only their own claim bodies (#215)", |
| 4302 | "branch": "tenant-iso-domains", |
| 4303 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-domains", |
| 4304 | "commits": 1, |
| 4305 | "discussions": [ |
| 4306 | { |
| 4307 | "id": 209, |
| 4308 | "title": "domains attach: no supported way to put the platform's own apex (carloku.com) on a console app", |
| 4309 | "state": "closed" |
| 4310 | }, |
| 4311 | { |
| 4312 | "id": 215, |
| 4313 | "title": "Custom domain claims need proof of control: dangling-DNS takeover, squatting, unreserved account namespaces, claims readable fleet-wide", |
| 4314 | "state": "closed" |
| 4315 | } |
| 4316 | ], |
| 4317 | "docs": [ |
| 4318 | "/docs/cli#carlos-domains" |
| 4319 | ], |
| 4320 | "credit": [ |
| 4321 | { |
| 4322 | "person": "Paul Campbell", |
| 4323 | "agents": [ |
| 4324 | "claude" |
| 4325 | ] |
| 4326 | } |
| 4327 | ] |
| 4328 | }, |
| 4329 | { |
| 4330 | "sha": "09814f7f35c0ba7188ad4be8204cbfed8f67efd7", |
| 4331 | "date": "2026-10-06", |
| 4332 | "subject": "Nested instances: CPU/IO limits, a disk floor, own-build-only /opt/carlos, no loopback or private egress, private IPC and Landlock-scoped abstract sockets (#214 items 1-3, #178)", |
| 4333 | "branch": "tenant-iso-hardening", |
| 4334 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-hardening", |
| 4335 | "commits": 1, |
| 4336 | "discussions": [ |
| 4337 | { |
| 4338 | "id": 178, |
| 4339 | "title": "isolated exec: POSIX mqueues and abstract unix sockets are still shared between instances", |
| 4340 | "state": "closed" |
| 4341 | }, |
| 4342 | { |
| 4343 | "id": 214, |
| 4344 | "title": "Isolation the nested layout does not give: CPU/IO/disk limits, shared network, readable binaries, private route addrs, trusted XFF", |
| 4345 | "state": "closed" |
| 4346 | } |
| 4347 | ], |
| 4348 | "credit": [ |
| 4349 | { |
| 4350 | "person": "Paul Campbell", |
| 4351 | "agents": [ |
| 4352 | "claude" |
| 4353 | ] |
| 4354 | } |
| 4355 | ] |
| 4356 | }, |
| 4357 | { |
| 4358 | "sha": "01f890ce4ab6c057ed25ed51634f7b10bc3fcfcc", |
| 4359 | "date": "2026-10-06", |
| 4360 | "subject": "Isolated exec, plan 4: the nested layout and carlos layout migrate/revert (#126)", |
| 4361 | "branch": "tenant-iso-layout", |
| 4362 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-layout", |
| 4363 | "commits": 1, |
| 4364 | "discussions": [ |
| 4365 | { |
| 4366 | "id": 126, |
| 4367 | "title": "activator: exec-backed instances share one uid and one flat DataDir — cross-tenant and cross-app", |
| 4368 | "state": "open" |
| 4369 | } |
| 4370 | ], |
| 4371 | "docs": [ |
| 4372 | "/docs/cli#carlos-status", |
| 4373 | "/docs/cli#the-platform-s-own-binary" |
| 4374 | ], |
| 4375 | "credit": [ |
| 4376 | { |
| 4377 | "person": "Paul Campbell", |
| 4378 | "agents": [ |
| 4379 | "claude" |
| 4380 | ] |
| 4381 | } |
| 4382 | ] |
| 4383 | }, |
| 4384 | { |
| 4385 | "sha": "7143c7e00747f5d216a4ac75d5efc654d563421e", |
| 4386 | "date": "2026-10-06", |
| 4387 | "subject": "email test: send multipart/alternative, plain and HTML", |
| 4388 | "branch": "multipart-email-support", |
| 4389 | "branch_url": "https://amadan.net/carlos/platform/-/branch/multipart-email-support", |
| 4390 | "commits": 1, |
| 4391 | "docs": [ |
| 4392 | "/docs/cli#carlos-email" |
| 4393 | ], |
| 4394 | "credit": [ |
| 4395 | { |
| 4396 | "person": "James Adam", |
| 4397 | "agents": [ |
| 4398 | "claude" |
| 4399 | ] |
| 4400 | } |
| 4401 | ] |
| 4402 | }, |
| 4403 | { |
| 4404 | "sha": "67547f5a610469d6a869923bc5bf4c2775c6d9e6", |
| 4405 | "date": "2026-10-06", |
| 4406 | "subject": "hostclaim: a created incarnation's first admission declares nothing (moves 7.17 note 2)", |
| 4407 | "branch": "fix/hostclaim-r717", |
| 4408 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fhostclaim-r717", |
| 4409 | "commits": 1, |
| 4410 | "credit": [ |
| 4411 | { |
| 4412 | "person": "Paul Campbell", |
| 4413 | "agents": [ |
| 4414 | "claude" |
| 4415 | ] |
| 4416 | } |
| 4417 | ] |
| 4418 | }, |
| 4419 | { |
| 4420 | "sha": "1d1a6f131533becea704bb3de3c3522402c34ef0", |
| 4421 | "date": "2026-10-06", |
| 4422 | "subject": "Merge instance-catchall: *.<parent> serves each instance at <label>.<parent> (#233)", |
| 4423 | "branch": "instance-catchall", |
| 4424 | "branch_url": "https://amadan.net/carlos/platform/-/branch/instance-catchall", |
| 4425 | "commits": 1, |
| 4426 | "discussions": [ |
| 4427 | { |
| 4428 | "id": 233, |
| 4429 | "title": "Instance catch-alls: serve each instance of an app at <label>.<parent>", |
| 4430 | "state": "closed" |
| 4431 | } |
| 4432 | ], |
| 4433 | "docs": [ |
| 4434 | "/docs/cli#one-name-per-instance-parent" |
| 4435 | ], |
| 4436 | "credit": [ |
| 4437 | { |
| 4438 | "person": "James Adam", |
| 4439 | "agents": [ |
| 4440 | "claude" |
| 4441 | ] |
| 4442 | } |
| 4443 | ] |
| 4444 | }, |
| 4445 | { |
| 4446 | "sha": "e8d0328dea6fa5474ed432b34b577fd57f2b8c8e", |
| 4447 | "date": "2026-10-06", |
| 4448 | "subject": "Merge first-route-wildcard: a first-route claim stays first-route on a route-less re-attach (#238)", |
| 4449 | "branch": "first-route-wildcard", |
| 4450 | "branch_url": "https://amadan.net/carlos/platform/-/branch/first-route-wildcard", |
| 4451 | "commits": 1, |
| 4452 | "discussions": [ |
| 4453 | { |
| 4454 | "id": 238, |
| 4455 | "title": "domains attach --wildcard turns a first-route claim into a self-alias that detach no longer cleans up", |
| 4456 | "state": "closed" |
| 4457 | } |
| 4458 | ], |
| 4459 | "credit": [ |
| 4460 | { |
| 4461 | "person": "James Adam", |
| 4462 | "agents": [ |
| 4463 | "claude" |
| 4464 | ] |
| 4465 | } |
| 4466 | ] |
| 4467 | }, |
| 4468 | { |
| 4469 | "sha": "58be381129188e4cc52e79d8fc56985596f6d78c", |
| 4470 | "date": "2026-10-06", |
| 4471 | "subject": "Merge wildcard-zone-check: check the DNS-01 zone before placing a wildcard order (#237)", |
| 4472 | "branch": "wildcard-zone-check", |
| 4473 | "branch_url": "https://amadan.net/carlos/platform/-/branch/wildcard-zone-check", |
| 4474 | "commits": 1, |
| 4475 | "discussions": [ |
| 4476 | { |
| 4477 | "id": 237, |
| 4478 | "title": "Wildcard manager places hourly ACME orders for parents its DNS provider has no zone for", |
| 4479 | "state": "closed" |
| 4480 | } |
| 4481 | ], |
| 4482 | "credit": [ |
| 4483 | { |
| 4484 | "person": "James Adam", |
| 4485 | "agents": [ |
| 4486 | "claude" |
| 4487 | ] |
| 4488 | } |
| 4489 | ] |
| 4490 | }, |
| 4491 | { |
| 4492 | "sha": "c7e595be4a0291492fe5a37d3c375e910eceba72", |
| 4493 | "date": "2026-10-06", |
| 4494 | "subject": "park, hostclaim: scopes stay in their own namespace; the legacy session-0 loss identity (joint round 16)", |
| 4495 | "branch": "fix/hostclaim-r16", |
| 4496 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fhostclaim-r16", |
| 4497 | "commits": 1, |
| 4498 | "credit": [ |
| 4499 | { |
| 4500 | "person": "Paul Campbell", |
| 4501 | "agents": [ |
| 4502 | "claude", |
| 4503 | "codex" |
| 4504 | ] |
| 4505 | } |
| 4506 | ] |
| 4507 | } |
| 4508 | ] |
| 4509 | }, |
| 4510 | { |
| 4511 | "tag": "v0.24.2", |
| 4512 | "date": "2026-10-06", |
| 4513 | "sha": "7f403a77aa3f8bd615b79bf28596197920b8077e", |
| 4514 | "published": true, |
| 4515 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.24.2", |
| 4516 | "notes": { |
| 4517 | "form": "bullets", |
| 4518 | "sections": [ |
| 4519 | { |
| 4520 | "title": "", |
| 4521 | "bullets": [ |
| 4522 | { |
| 4523 | "md": "**CI can deploy through the console.** `carlos services create --role deploy --app <a> --rungs canary,edge <name>` mints a credential that can ship, and promote or roll back only the rungs you name: `canary`, `edge` and `beta`, never `stable`. In CI, set `CARLOS_SERVICE_TOKEN` and `CARLOS_CONSOLE` and run `carlos deploy` as usual. The first deploy of a new app still needs a person, because a deploy credential cannot create the app or set up its first host. It cannot hotfix, delete the app, or change retention or domains. `carlos services list` gains a RUNGS column. The CLI refuses to run with both `CARLOS_SERVICE_TOKEN` and `CARLOS_DEPLOYMENT_BUCKET` or `CARLOS_DEPLOYMENT_DIR` set.", |
| 4524 | "branches": [ |
| 4525 | "design-deploy-credential" |
| 4526 | ], |
| 4527 | "docs": [ |
| 4528 | "/docs/cli#carlos-services", |
| 4529 | "/docs/cli#carlos-deploy" |
| 4530 | ] |
| 4531 | }, |
| 4532 | { |
| 4533 | "md": "**A failed rollback says so.** When the console cannot sign a rollback, it now answers \"Nothing was rolled back.\" Before, it said \"Nothing was promoted.\"", |
| 4534 | "branches": [ |
| 4535 | "fix-deploy-rollback-copy" |
| 4536 | ] |
| 4537 | }, |
| 4538 | { |
| 4539 | "md": "**`carlos db` no longer panics.** If `carlos db pull` or `query` could not create its temporary file, the restore crashed. It now reports the error.", |
| 4540 | "branches": [ |
| 4541 | "feat/hostclaim-door" |
| 4542 | ], |
| 4543 | "docs": [ |
| 4544 | "/docs/cli#carlos-db" |
| 4545 | ] |
| 4546 | } |
| 4547 | ] |
| 4548 | }, |
| 4549 | { |
| 4550 | "title": "For operators", |
| 4551 | "bullets": [ |
| 4552 | { |
| 4553 | "md": "**The boxes come back onto the release train.** The flagship boxes have been running a hotfix build of v0.23.0 (f3f6cf73). It carried four fixes. Three are in v0.24.0, and their operator notes are there: a box runs its adopt work on its own loop, lists the bucket by app, and reads in parallel. The fourth is new in this release. When a box cannot stage a release itself, it asks a root pass to do it. That request used to be sent at most once a minute, and one made inside the minute was dropped, so a second release soon after the first waited for the next change to be noticed. On the flagship that was 98 extra seconds. The request is now limited to once every 15 seconds, and one made inside that window is sent at its end instead of dropped. Rolling this release moves those boxes off the hotfix with nothing lost.", |
| 4554 | "branches": [ |
| 4555 | "fix-stage-request-deferred" |
| 4556 | ] |
| 4557 | }, |
| 4558 | { |
| 4559 | "md": "**If your boxes are coming from v0.23.0 or a hotfix of it, read v0.24.0's operator notes first.** Its changes now apply to the boxes: the keyless config guard, the box with no deployment store, and alerts to SNS. The check that matters most is this one. Every box that runs placed instances must hold the right `CARLOS_SECRETS_KEY` before you roll. A box without it, or with a key that does not open an instance's sealed config, will not wake that instance." |
| 4560 | }, |
| 4561 | { |
| 4562 | "md": "**Leave `CARLOS_HOST_CLAIM` unset on the console.** Any value that is not blank turns it on, including `0` and `false`. The console reads it once, when it starts. Nothing writes host claims yet, so with it on, `carlos db pull` and `carlos db query` fail for every host.", |
| 4563 | "branches": [ |
| 4564 | "feat/hostclaim-door" |
| 4565 | ], |
| 4566 | "docs": [ |
| 4567 | "/docs/cli#carlos-db" |
| 4568 | ] |
| 4569 | }, |
| 4570 | { |
| 4571 | "md": "**Do not set `CARLOS_REGION_HA` on a box yet.** It is the switch for multi-box regions, which this release does not finish. Left unset, a box publishes no `region-ha-1` capability and no headroom, and nothing changes.", |
| 4572 | "branches": [ |
| 4573 | "design-region-ha" |
| 4574 | ] |
| 4575 | }, |
| 4576 | { |
| 4577 | "md": "**Deploy credentials need the console's signing key.** The console signs each deploy promote with a grant limited to the credential's rungs, so the console must hold its release key, as it already does for promotes. It adds a `rungs` column to its `cli_tokens` table when it starts. The change is additive.", |
| 4578 | "branches": [ |
| 4579 | "design-deploy-credential" |
| 4580 | ] |
| 4581 | }, |
| 4582 | { |
| 4583 | "md": "**Region HA foundations ship dormant.** Every box's edges file gains `box_id`, which is the box's label. Box bootstrap also creates `/run/carlos/hostguard` and `/data/hostguard`, mode 2770, owned by `carlos:carlos`, when tmpfiles next runs. Nothing uses them yet. The host claim, generation selection and park libraries have no callers, so the boxes behave as before.", |
| 4584 | "branches": [ |
| 4585 | "design-region-ha", |
| 4586 | "feat/hostclaim-library", |
| 4587 | "feat/hostclaim-genselect", |
| 4588 | "feat/hostclaim-boxguard", |
| 4589 | "feat/hostclaim-park" |
| 4590 | ] |
| 4591 | }, |
| 4592 | { |
| 4593 | "md": "**Read the plan before applying the infrastructure modules.** `region-host` gains a termination queue, an EventBridge rule and a box-role policy to read the queue, and its root volume is now deleted when the instance terminates. `deployment-buckets` gains a bucket policy that makes `control/boxes/*` create-only and undeletable. A bucket holds one policy, so check whether yours already has one before you apply. Nothing in this release needs them, so applying can wait. The own-bucket S3 version grants are split into separately named statements, with the same permissions.", |
| 4594 | "branches": [ |
| 4595 | "design-region-ha", |
| 4596 | "feat/hostclaim-door" |
| 4597 | ] |
| 4598 | }, |
| 4599 | { |
| 4600 | "md": "**The scanner host fix is in this release too.** It is the freshclam change from v0.24.1.", |
| 4601 | "branches": [ |
| 4602 | "fix/scanner-freshclam-apparmor" |
| 4603 | ] |
| 4604 | }, |
| 4605 | { |
| 4606 | "md": "**Either roll order works.** Nothing in this release needs the console and the boxes to roll in a particular order." |
| 4607 | } |
| 4608 | ] |
| 4609 | } |
| 4610 | ] |
| 4611 | }, |
| 4612 | "changes": [ |
| 4613 | { |
| 4614 | "sha": "7f403a77aa3f8bd615b79bf28596197920b8077e", |
| 4615 | "date": "2026-10-06", |
| 4616 | "subject": "park: the claim's park engine (claim Plan 4)", |
| 4617 | "branch": "feat/hostclaim-park", |
| 4618 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-park", |
| 4619 | "commits": 6, |
| 4620 | "credit": [ |
| 4621 | { |
| 4622 | "person": "Paul Campbell", |
| 4623 | "agents": [ |
| 4624 | "claude", |
| 4625 | "codex" |
| 4626 | ] |
| 4627 | } |
| 4628 | ] |
| 4629 | }, |
| 4630 | { |
| 4631 | "sha": "e112199786d0de810593e966c3d41335d0a02110", |
| 4632 | "date": "2026-10-06", |
| 4633 | "subject": "console, dbdoor: the claim-bracketed pull door (claim Plan 7)", |
| 4634 | "branch": "feat/hostclaim-door", |
| 4635 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-door", |
| 4636 | "commits": 7, |
| 4637 | "credit": [ |
| 4638 | { |
| 4639 | "person": "Paul Campbell", |
| 4640 | "agents": [ |
| 4641 | "claude", |
| 4642 | "codex" |
| 4643 | ] |
| 4644 | } |
| 4645 | ] |
| 4646 | }, |
| 4647 | { |
| 4648 | "sha": "b37f73e1a5a7ee11191ee2b90592cbe46d56cd6a", |
| 4649 | "date": "2026-10-06", |
| 4650 | "subject": "hostguard, stopevidence, cgroup: the box-local host guard and stop evidence (claim Plan 3)", |
| 4651 | "branch": "feat/hostclaim-boxguard", |
| 4652 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-boxguard", |
| 4653 | "commits": 9, |
| 4654 | "credit": [ |
| 4655 | { |
| 4656 | "person": "Paul Campbell", |
| 4657 | "agents": [ |
| 4658 | "claude", |
| 4659 | "codex" |
| 4660 | ] |
| 4661 | } |
| 4662 | ] |
| 4663 | }, |
| 4664 | { |
| 4665 | "sha": "4d13aec350284f8db384503714a5db3dc916cc7d", |
| 4666 | "date": "2026-10-06", |
| 4667 | "subject": "genselect: the shared read-only generation selector (claim Plan 7b, F)", |
| 4668 | "branch": "feat/hostclaim-genselect", |
| 4669 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-genselect", |
| 4670 | "commits": 5, |
| 4671 | "credit": [ |
| 4672 | { |
| 4673 | "person": "Paul Campbell", |
| 4674 | "agents": [ |
| 4675 | "claude", |
| 4676 | "codex" |
| 4677 | ] |
| 4678 | } |
| 4679 | ] |
| 4680 | }, |
| 4681 | { |
| 4682 | "sha": "99084d7a3aecb6cad47641e19c4642ef6cbae9c8", |
| 4683 | "date": "2026-10-06", |
| 4684 | "subject": "hostclaim: the host lifecycle claim library (Plan 1, E)", |
| 4685 | "branch": "feat/hostclaim-library", |
| 4686 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-library", |
| 4687 | "commits": 19, |
| 4688 | "credit": [ |
| 4689 | { |
| 4690 | "person": "Paul Campbell", |
| 4691 | "agents": [ |
| 4692 | "claude", |
| 4693 | "codex" |
| 4694 | ] |
| 4695 | } |
| 4696 | ] |
| 4697 | }, |
| 4698 | { |
| 4699 | "sha": "55e3c1d959d5b5b2636f0311bc234e7192c47711", |
| 4700 | "date": "2026-10-06", |
| 4701 | "subject": "console: a failed deploy rollback says nothing was rolled back (#229)", |
| 4702 | "branch": "fix-deploy-rollback-copy", |
| 4703 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-deploy-rollback-copy", |
| 4704 | "commits": 1, |
| 4705 | "discussions": [ |
| 4706 | { |
| 4707 | "id": 229, |
| 4708 | "title": "CI cannot promote through the console without gaining beta: service credentials need a channel scope (or direct promotes need to reach fast converge)", |
| 4709 | "state": "open" |
| 4710 | } |
| 4711 | ], |
| 4712 | "credit": [ |
| 4713 | { |
| 4714 | "person": "Paul Campbell", |
| 4715 | "agents": [ |
| 4716 | "claude" |
| 4717 | ] |
| 4718 | } |
| 4719 | ] |
| 4720 | }, |
| 4721 | { |
| 4722 | "sha": "592b667a7bb6c35fd8d6134161928e36ad94681a", |
| 4723 | "date": "2026-10-06", |
| 4724 | "subject": "scanner-host: run the first freshclam with its packaged config (AppArmor denies any other)", |
| 4725 | "branch": "fix/scanner-freshclam-apparmor", |
| 4726 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fscanner-freshclam-apparmor", |
| 4727 | "commits": 2, |
| 4728 | "credit": [ |
| 4729 | { |
| 4730 | "person": "Paul Campbell", |
| 4731 | "agents": [ |
| 4732 | "claude" |
| 4733 | ] |
| 4734 | } |
| 4735 | ] |
| 4736 | }, |
| 4737 | { |
| 4738 | "sha": "1a17848ae8c43c26171d6e233b10d3580d8ae218", |
| 4739 | "date": "2026-10-06", |
| 4740 | "subject": "host: a throttled stage request is deferred, not dropped; a blocked stage stays in the fast sweep", |
| 4741 | "branch": "fix-stage-request-deferred", |
| 4742 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-stage-request-deferred", |
| 4743 | "commits": 4, |
| 4744 | "discussions": [ |
| 4745 | { |
| 4746 | "id": 231, |
| 4747 | "title": "An awake exec instance is not restarted when a release is adopted: it serves the old build for 110-200s", |
| 4748 | "state": "open" |
| 4749 | } |
| 4750 | ], |
| 4751 | "credit": [ |
| 4752 | { |
| 4753 | "person": "Paul Campbell", |
| 4754 | "agents": [ |
| 4755 | "claude" |
| 4756 | ] |
| 4757 | } |
| 4758 | ] |
| 4759 | }, |
| 4760 | { |
| 4761 | "sha": "d1dab9a91fbe716a9f7fc9343fa92ca1c81ea33e", |
| 4762 | "date": "2026-10-06", |
| 4763 | "subject": "deploy-credential: a rung-scoped deploy credential so CI promotes through the console (#229)", |
| 4764 | "branch": "design-deploy-credential", |
| 4765 | "branch_url": "https://amadan.net/carlos/platform/-/branch/design-deploy-credential", |
| 4766 | "commits": 27, |
| 4767 | "discussions": [ |
| 4768 | { |
| 4769 | "id": 229, |
| 4770 | "title": "CI cannot promote through the console without gaining beta: service credentials need a channel scope (or direct promotes need to reach fast converge)", |
| 4771 | "state": "open" |
| 4772 | } |
| 4773 | ], |
| 4774 | "docs": [ |
| 4775 | "/docs/cli#carlos-services" |
| 4776 | ], |
| 4777 | "credit": [ |
| 4778 | { |
| 4779 | "person": "Paul Campbell", |
| 4780 | "agents": [ |
| 4781 | "claude" |
| 4782 | ] |
| 4783 | } |
| 4784 | ] |
| 4785 | }, |
| 4786 | { |
| 4787 | "sha": "aadb86008f3e9661b348b688d6222faf845eea99", |
| 4788 | "date": "2026-10-06", |
| 4789 | "subject": "Region HA plan 1a: the foundations for running instances on any box in a region", |
| 4790 | "branch": "design-region-ha", |
| 4791 | "branch_url": "https://amadan.net/carlos/platform/-/branch/design-region-ha", |
| 4792 | "commits": 1, |
| 4793 | "discussions": [ |
| 4794 | { |
| 4795 | "id": 223, |
| 4796 | "title": "Region HA needs eleven changes from the host lifecycle claim and move-any-app (K1-K11)", |
| 4797 | "state": "closed" |
| 4798 | } |
| 4799 | ], |
| 4800 | "credit": [ |
| 4801 | { |
| 4802 | "person": "Paul Campbell", |
| 4803 | "agents": [ |
| 4804 | "claude" |
| 4805 | ] |
| 4806 | } |
| 4807 | ] |
| 4808 | } |
| 4809 | ] |
| 4810 | }, |
| 4811 | { |
| 4812 | "tag": "v0.24.1", |
| 4813 | "date": "2026-10-06", |
| 4814 | "sha": "f4478b15f96c0e3e904cf805cfc15ddaa1c12171", |
| 4815 | "published": true, |
| 4816 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.24.1", |
| 4817 | "notes": { |
| 4818 | "form": "bullets", |
| 4819 | "sections": [ |
| 4820 | { |
| 4821 | "title": "", |
| 4822 | "bullets": [ |
| 4823 | { |
| 4824 | "md": "**Nothing new for the CLI.** The carlos binary is the same code as v0.24.0. This release only fixes a deployment module." |
| 4825 | } |
| 4826 | ] |
| 4827 | }, |
| 4828 | { |
| 4829 | "title": "For operators", |
| 4830 | "bullets": [ |
| 4831 | { |
| 4832 | "md": "**The scanner host boots.** In v0.24.0, a new `scanner-host` box failed its first boot with `SCANNER-HOST FAILED: first freshclam failed 3 times`. Debian's AppArmor profile only lets freshclam read its own config under `/etc/clamav`, and the boot script gave it a copy elsewhere. It now uses the packaged config. A box from v0.24.0 never opened its port, so nothing was ever scanned through it. Pin `scanner-host` to v0.24.1 and replace the box with `tofu apply -replace=module.<name>.aws_instance.scanner`." |
| 4833 | } |
| 4834 | ] |
| 4835 | } |
| 4836 | ] |
| 4837 | }, |
| 4838 | "changes": [ |
| 4839 | { |
| 4840 | "sha": "f4478b15f96c0e3e904cf805cfc15ddaa1c12171", |
| 4841 | "date": "2026-10-06", |
| 4842 | "subject": "scanner-host: run the first freshclam with its packaged config (AppArmor denies any other)", |
| 4843 | "commits": 1, |
| 4844 | "credit": [ |
| 4845 | { |
| 4846 | "person": "Paul Campbell", |
| 4847 | "agents": [ |
| 4848 | "claude" |
| 4849 | ] |
| 4850 | } |
| 4851 | ] |
| 4852 | } |
| 4853 | ] |
| 4854 | }, |
| 4855 | { |
| 4856 | "tag": "v0.24.0", |
| 4857 | "date": "2026-10-06", |
| 4858 | "sha": "eef3e1217cfe038be75581496ca23d72824289d0", |
| 4859 | "published": true, |
| 4860 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.24.0", |
| 4861 | "notes": { |
| 4862 | "form": "bullets", |
| 4863 | "sections": [ |
| 4864 | { |
| 4865 | "title": "", |
| 4866 | "bullets": [ |
| 4867 | { |
| 4868 | "md": "**Canaries have a one-label address, and can be created again.** A canary's host is now `<name>-<app>.<your account>.<apps domain>`, so canary `new-queue` of app `jam` is `new-queue-jam.bab.oncarlos.com`. The old address put a dot between the name and the app. The console refused that, so `carlos canary` could not create a canary for an app that runs a process. The name and the app together can be at most 63 characters. You need this release's CLI.", |
| 4869 | "branches": [ |
| 4870 | "fix/canary-one-label" |
| 4871 | ], |
| 4872 | "docs": [ |
| 4873 | "/docs/cli#carlos-canary" |
| 4874 | ] |
| 4875 | }, |
| 4876 | { |
| 4877 | "md": "**Deploys reach running instances sooner on busy boxes.** A box notices a promote sooner, and it restarts an awake instance onto the new release on its own two-second check instead of waiting for the rest of its work. On the flagship, noticing a promote had taken 16 to 43 seconds, and the restart then waited about 48 seconds more.", |
| 4878 | "branches": [ |
| 4879 | "fix-converge-own-loop", |
| 4880 | "fix-reconcile-listing", |
| 4881 | "fix-reconcile-parallel-reads" |
| 4882 | ] |
| 4883 | }, |
| 4884 | { |
| 4885 | "md": "**An instance never starts without its secrets.** A box that cannot open an instance's sealed secrets no longer wakes it or takes it on. A box that can takes it instead. If none can, it does not start. Before, it could start with none of its config or secrets.", |
| 4886 | "branches": [ |
| 4887 | "fix/keyless-box-refuses" |
| 4888 | ] |
| 4889 | }, |
| 4890 | { |
| 4891 | "md": "**One address, one app.** `carlos instances create` and `carlos canary` are refused when another app in your account already holds the host, including an app in the Trash, or when the host is a domain attached to another app. Before, both creates succeeded and one of them served nothing.", |
| 4892 | "branches": [ |
| 4893 | "fix/canary-one-label" |
| 4894 | ], |
| 4895 | "docs": [ |
| 4896 | "/docs/cli#carlos-instances", |
| 4897 | "/docs/cli#carlos-canary" |
| 4898 | ] |
| 4899 | }, |
| 4900 | { |
| 4901 | "md": "**Nothing new to type.** The CLI has no new commands or flags in this release." |
| 4902 | } |
| 4903 | ] |
| 4904 | }, |
| 4905 | { |
| 4906 | "title": "For operators", |
| 4907 | "bullets": [ |
| 4908 | { |
| 4909 | "md": "**Check every box's secrets key before rolling the boxes.** A box now takes an exec instance only if it can open that instance's sealed config. Without `CARLOS_SECRETS_KEY`, or with a key that does not open the config, it does not wake the instance or mint its record. It logs `agent: config guard: refusing <host>` and lists the host under `metrics.config_refusals` in its private snapshot, `status/boxes/<box>.json`. A box that cannot read the deployment store to check refuses too, and asks again after 30 seconds. Instances with no sealed config are not affected.", |
| 4910 | "branches": [ |
| 4911 | "fix/keyless-box-refuses" |
| 4912 | ] |
| 4913 | }, |
| 4914 | { |
| 4915 | "md": "**A box with no deployment store refuses exec instances.** With `CARLOS_HIBERNATE_BUCKET` set and neither `CARLOS_DEPLOYMENT_BUCKET` nor `CARLOS_DEPLOYMENT_DIR`, a box cannot tell whether an instance's config is sealed, so it refuses. On a deployment with no sealed config at all, set `CARLOS_NO_SEALED_CONFIG=1`. Never set it on a box that serves tenants. The box then logs that the check is bypassed and says so in its snapshot. With a deployment store configured, the setting is ignored.", |
| 4916 | "branches": [ |
| 4917 | "fix/keyless-box-refuses" |
| 4918 | ] |
| 4919 | }, |
| 4920 | { |
| 4921 | "md": "**Roll the console to this release before pointing it at a scanner host.** An older console records an archive that clamd could only partly scan as infected. This release records it as not scanned, and a scan time-out as failed, so the next sweep tries it again. A real signature match is still infected.", |
| 4922 | "branches": [ |
| 4923 | "worktree-scanner-host" |
| 4924 | ] |
| 4925 | }, |
| 4926 | { |
| 4927 | "md": "**Object-storage scanning has its own box.** The new `infra/modules/scanner-host` module runs clamd on one box per deployment, reachable only from the console's security group. Set its outputs on the console: `clamd_addr` as `CARLOS_CLAMD_ADDR` and `stream_max_bytes` as `CARLOS_CLAMD_MAX_BYTES`. The console also needs `CARLOS_SCAN_TAG_KEY`, and refuses to boot with an address and no key. Set `store_scanning = true` on the console box's `region-host` so its role can read and tag store objects. It is off by default, and a deployment that leaves it off plans no change. Wiring the engine does not switch scanning on. `carlos system antivirus enable` does. A replaced scanner box gets a new private IP, so update `CARLOS_CLAMD_ADDR` after any `-replace`. Pin modules to v0.24.0: v0.23.0 does not contain `scanner-host`.", |
| 4928 | "branches": [ |
| 4929 | "worktree-scanner-host" |
| 4930 | ], |
| 4931 | "docs": [ |
| 4932 | "/docs/cli#carlos-system" |
| 4933 | ] |
| 4934 | }, |
| 4935 | { |
| 4936 | "md": "**The app regions rollback floor is v0.23.0.** v0.23.0 is the first release that understands app regions. Once any app holds a region other than the home, do not roll the console below v0.23.0.", |
| 4937 | "branches": [ |
| 4938 | "docs-regions-floor-v0.23.0" |
| 4939 | ] |
| 4940 | }, |
| 4941 | { |
| 4942 | "md": "**Boxes can send alerts to SNS.** Set `CARLOS_ALERT_SNS_TOPIC_ARN` to the box's own region's alerts topic, and anyone subscribed gets each fire and clear by email. The box's instance role needs `sns:Publish` on that topic. The modules in this repo do not grant it. A box with neither this nor `CARLOS_ALERT_WEBHOOK` logs `NO SINK CONFIGURED` when it starts. `carlos status --live` gains a last column: `alerts=sns`, `alerts=webhook`, `alerts=webhook+sns`, `alerts=not-delivered`, or `alerts=sns-unavailable` when a topic is set but the box could not build its SNS client. A dash means the box runs an older release.", |
| 4943 | "branches": [ |
| 4944 | "feat/alerts-sns" |
| 4945 | ], |
| 4946 | "docs": [ |
| 4947 | "/docs/cli#carlos-status" |
| 4948 | ] |
| 4949 | }, |
| 4950 | { |
| 4951 | "md": "**Boxes list the bucket by app.** To find instance records, a box now lists each account's apps and each app's `instances/` prefix, eight requests at a time, instead of every object under `apps/`. If one app's listing fails, the box logs a `provision: listing` line, converges everything it did see, and removes no route on that pass. The agent also logs an `agent: fast converge:` line when a step of its fast loop takes longer than five seconds.", |
| 4952 | "branches": [ |
| 4953 | "fix-reconcile-listing", |
| 4954 | "fix-reconcile-parallel-reads" |
| 4955 | ] |
| 4956 | }, |
| 4957 | { |
| 4958 | "md": "**Either roll order works.** Nothing in this release needs the console and the boxes to roll in a particular order." |
| 4959 | } |
| 4960 | ] |
| 4961 | } |
| 4962 | ] |
| 4963 | }, |
| 4964 | "changes": [ |
| 4965 | { |
| 4966 | "sha": "eef3e1217cfe038be75581496ca23d72824289d0", |
| 4967 | "date": "2026-10-06", |
| 4968 | "subject": "provision: read records eight at a time in the reconcile and record passes", |
| 4969 | "branch": "fix-reconcile-parallel-reads", |
| 4970 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-reconcile-parallel-reads", |
| 4971 | "commits": 4, |
| 4972 | "credit": [ |
| 4973 | { |
| 4974 | "person": "Paul Campbell", |
| 4975 | "agents": [ |
| 4976 | "claude" |
| 4977 | ] |
| 4978 | } |
| 4979 | ] |
| 4980 | }, |
| 4981 | { |
| 4982 | "sha": "91bb1a2ea13b8de969dfe9ad3cbe61e40374c01b", |
| 4983 | "date": "2026-10-05", |
| 4984 | "subject": "provision: find instance and sidecar records by walking app directories, not by listing all of apps/", |
| 4985 | "branch": "fix-reconcile-listing", |
| 4986 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-reconcile-listing", |
| 4987 | "commits": 3, |
| 4988 | "discussions": [ |
| 4989 | { |
| 4990 | "id": 231, |
| 4991 | "title": "An awake exec instance is not restarted when a release is adopted: it serves the old build for 110-200s", |
| 4992 | "state": "open" |
| 4993 | } |
| 4994 | ], |
| 4995 | "credit": [ |
| 4996 | { |
| 4997 | "person": "Paul Campbell", |
| 4998 | "agents": [ |
| 4999 | "claude" |
| 5000 | ] |
| 5001 | } |
| 5002 | ] |
| 5003 | }, |
| 5004 | { |
| 5005 | "sha": "b2a76df9108f9d252359045f0cb77b5060f2e194", |
| 5006 | "date": "2026-10-05", |
| 5007 | "subject": "host: the converge leg runs on its own loop; slow fast-loop legs are logged", |
| 5008 | "branch": "fix-converge-own-loop", |
| 5009 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-converge-own-loop", |
| 5010 | "commits": 3, |
| 5011 | "discussions": [ |
| 5012 | { |
| 5013 | "id": 231, |
| 5014 | "title": "An awake exec instance is not restarted when a release is adopted: it serves the old build for 110-200s", |
| 5015 | "state": "open" |
| 5016 | } |
| 5017 | ], |
| 5018 | "credit": [ |
| 5019 | { |
| 5020 | "person": "Paul Campbell", |
| 5021 | "agents": [ |
| 5022 | "claude" |
| 5023 | ] |
| 5024 | } |
| 5025 | ] |
| 5026 | }, |
| 5027 | { |
| 5028 | "sha": "e58a0d821ceb5a0e31650dbaddc3b24bbc436ec7", |
| 5029 | "date": "2026-10-05", |
| 5030 | "subject": "README: v0.23.0 is the app-regions rollback floor", |
| 5031 | "branch": "docs-regions-floor-v0.23.0", |
| 5032 | "branch_url": "https://amadan.net/carlos/platform/-/branch/docs-regions-floor-v0.23.0", |
| 5033 | "commits": 1, |
| 5034 | "credit": [ |
| 5035 | { |
| 5036 | "person": "Paul Campbell", |
| 5037 | "agents": [ |
| 5038 | "claude" |
| 5039 | ] |
| 5040 | } |
| 5041 | ] |
| 5042 | }, |
| 5043 | { |
| 5044 | "sha": "562f3dfcb4934c0dec027f730e34bbff08bbbd15", |
| 5045 | "date": "2026-10-05", |
| 5046 | "subject": "spec: scanner host, getting object-storage scanning running on Carloku and Tito", |
| 5047 | "branch": "worktree-scanner-host", |
| 5048 | "branch_url": "https://amadan.net/carlos/platform/-/branch/worktree-scanner-host", |
| 5049 | "commits": 19, |
| 5050 | "discussions": [ |
| 5051 | { |
| 5052 | "id": 235, |
| 5053 | "title": "Scanner host: object-storage scanning on Carloku and Tito", |
| 5054 | "state": "open" |
| 5055 | } |
| 5056 | ], |
| 5057 | "docs": [ |
| 5058 | "/docs/cli#carlos-store-scan" |
| 5059 | ], |
| 5060 | "credit": [ |
| 5061 | { |
| 5062 | "person": "Paul Campbell", |
| 5063 | "agents": [ |
| 5064 | "claude" |
| 5065 | ] |
| 5066 | } |
| 5067 | ] |
| 5068 | }, |
| 5069 | { |
| 5070 | "sha": "04cd2d7856772fd8ae63d2593a269051100e2b1e", |
| 5071 | "date": "2026-10-05", |
| 5072 | "subject": "console: the instance create door refuses a host another app holds", |
| 5073 | "branch": "fix/canary-one-label", |
| 5074 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fcanary-one-label", |
| 5075 | "commits": 7, |
| 5076 | "discussions": [ |
| 5077 | { |
| 5078 | "id": 207, |
| 5079 | "title": "carlos canary: canaryHost builds a two-label host the create door refuses", |
| 5080 | "state": "closed" |
| 5081 | }, |
| 5082 | { |
| 5083 | "id": 232, |
| 5084 | "title": "Instance create door: one app can claim a hostname another app in the same account holds (race and aliases)", |
| 5085 | "state": "open" |
| 5086 | } |
| 5087 | ], |
| 5088 | "docs": [ |
| 5089 | "/docs/cli#carlos-canary", |
| 5090 | "/docs/cli#carlos-instances" |
| 5091 | ], |
| 5092 | "credit": [ |
| 5093 | { |
| 5094 | "person": "Paul Campbell", |
| 5095 | "agents": [ |
| 5096 | "claude" |
| 5097 | ] |
| 5098 | } |
| 5099 | ] |
| 5100 | }, |
| 5101 | { |
| 5102 | "sha": "5cd92594f97cf8ac3005e990cf20fb8a584b0292", |
| 5103 | "date": "2026-10-05", |
| 5104 | "subject": "appconfig: CanProvideConfig, can this box provide an instance's config (#213)", |
| 5105 | "branch": "fix/keyless-box-refuses", |
| 5106 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fkeyless-box-refuses", |
| 5107 | "commits": 7, |
| 5108 | "discussions": [ |
| 5109 | { |
| 5110 | "id": 213, |
| 5111 | "title": "A box that cannot open an instance's sealed config must not take its lease (gates CONSOLE_APP_REGIONS)", |
| 5112 | "state": "closed" |
| 5113 | } |
| 5114 | ], |
| 5115 | "credit": [ |
| 5116 | { |
| 5117 | "person": "Paul Campbell", |
| 5118 | "agents": [ |
| 5119 | "claude" |
| 5120 | ] |
| 5121 | } |
| 5122 | ] |
| 5123 | }, |
| 5124 | { |
| 5125 | "sha": "6956db67baa5b96cc7da731a02794f00f6f8fc66", |
| 5126 | "date": "2026-10-05", |
| 5127 | "subject": "Deliver platform alerts to an SNS topic, and say when a box has no sink", |
| 5128 | "branch": "feat/alerts-sns", |
| 5129 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Falerts-sns", |
| 5130 | "commits": 3, |
| 5131 | "discussions": [ |
| 5132 | { |
| 5133 | "id": 192, |
| 5134 | "title": "Fleet status: say which box makes the fleet at-capacity", |
| 5135 | "state": "open" |
| 5136 | } |
| 5137 | ], |
| 5138 | "docs": [ |
| 5139 | "/docs/cli#carlos-status" |
| 5140 | ], |
| 5141 | "credit": [ |
| 5142 | { |
| 5143 | "person": "Paul Campbell", |
| 5144 | "agents": [ |
| 5145 | "claude" |
| 5146 | ] |
| 5147 | } |
| 5148 | ] |
| 5149 | } |
| 5150 | ] |
| 5151 | }, |
| 5152 | { |
| 5153 | "tag": "v0.23.0", |
| 5154 | "date": "2026-10-05", |
| 5155 | "sha": "3ca43d338643a8ca17290c6896e97e5cfc251cb3", |
| 5156 | "published": true, |
| 5157 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.23.0", |
| 5158 | "notes": { |
| 5159 | "form": "bullets", |
| 5160 | "sections": [ |
| 5161 | { |
| 5162 | "title": "", |
| 5163 | "bullets": [ |
| 5164 | { |
| 5165 | "md": "**A deploy reaches a running instance in seconds.** When a box adopts a new release, an instance that is awake restarts onto it within a few seconds. Before, it kept serving the old build for about two minutes, longer than `carlos deploy` waits, so a deploy could report a timeout and a restart seemed to be needed. Instances on one box restart one at a time, two seconds apart.", |
| 5166 | "branches": [ |
| 5167 | "fix-adopted-exec-restart" |
| 5168 | ], |
| 5169 | "docs": [ |
| 5170 | "/docs/cli#carlos-deploy" |
| 5171 | ] |
| 5172 | }, |
| 5173 | { |
| 5174 | "md": "**Static sites show a deploy on the next page load.** Browsers now check with the edge before reusing a page or file from a static site, and get a quick \"not modified\" answer while nothing has changed. Before, a browser could keep showing the old page for hours or days after a deploy.", |
| 5175 | "branches": [ |
| 5176 | "static-cache-control" |
| 5177 | ] |
| 5178 | }, |
| 5179 | { |
| 5180 | "md": "**Read a copy of an instance's database.** `carlos db pull --app <a> --out <file>` saves a copy of a sleeping instance's database on your machine, and `carlos db query --app <a> --sql \"…\"` runs one query against a fresh copy. Both say how recent the copy is. The copy is read-only and never touches the live database. Name an instance with `--instance` when the app has more than one.", |
| 5181 | "branches": [ |
| 5182 | "feat/carlos-db-read" |
| 5183 | ], |
| 5184 | "docs": [ |
| 5185 | "/docs/cli#carlos-db" |
| 5186 | ] |
| 5187 | }, |
| 5188 | { |
| 5189 | "md": "**Region flags.** `carlos apps create`, `carlos deploy` and `carlos canary` take `--region`. A console that is not assigning app regions yet says so and starts the app in its home region. `carlos deploy --region` on an existing app stops before shipping if the region differs from the app's own. The line `carlos instances create` prints now names the place the instance runs.", |
| 5190 | "branches": [ |
| 5191 | "design-nearest-region" |
| 5192 | ], |
| 5193 | "docs": [ |
| 5194 | "/docs/cli#carlos-apps", |
| 5195 | "/docs/cli#carlos-deploy", |
| 5196 | "/docs/cli#carlos-canary", |
| 5197 | "/docs/cli#carlos-instances" |
| 5198 | ] |
| 5199 | }, |
| 5200 | { |
| 5201 | "md": "**Invite links ask before you join.** Opening an invite link shows who invited you and a Join button. Nothing happens until you press it.", |
| 5202 | "branches": [ |
| 5203 | "tenant-iso-leftovers" |
| 5204 | ] |
| 5205 | }, |
| 5206 | { |
| 5207 | "md": "**Sending domains you did not set up.** If a domain already has a sending identity that your account did not create, `carlos email domains add` asks you to prove you control it: publish a TXT record at `_carlos-mail.<domain>` with the value `carlos-mail-account=<account>`, then add the domain again. A domain another account holds now reads \"sending domain unavailable\". A claim that is not verified within 7 days can be taken by another account.", |
| 5208 | "branches": [ |
| 5209 | "tenant-iso-mail" |
| 5210 | ], |
| 5211 | "docs": [ |
| 5212 | "/docs/cli#carlos-email" |
| 5213 | ] |
| 5214 | }, |
| 5215 | { |
| 5216 | "md": "**Stores no longer share a bucket by accident.** App and environment names are joined with \"-\", so app `shop` with environment `eu` and app `shop-eu` used to map to the same bucket. The second one is now refused with a 409, and nothing is created.", |
| 5217 | "branches": [ |
| 5218 | "tenant-iso-objstore" |
| 5219 | ] |
| 5220 | }, |
| 5221 | { |
| 5222 | "md": "**Platform domains.** An operator can attach one of the deployment's own domains to an app with `carlos domains attach --platform`. Members cannot attach, change or detach those names.", |
| 5223 | "branches": [ |
| 5224 | "platform-domain-claims-209" |
| 5225 | ], |
| 5226 | "docs": [ |
| 5227 | "/docs/cli#carlos-domains" |
| 5228 | ] |
| 5229 | } |
| 5230 | ] |
| 5231 | }, |
| 5232 | { |
| 5233 | "title": "For operators", |
| 5234 | "bullets": [ |
| 5235 | { |
| 5236 | "md": "**Roll the boxes, then the console.** With the new switches left off, either order is safe. The two switches below need every box on v0.23.0 first." |
| 5237 | }, |
| 5238 | { |
| 5239 | "md": "**Leave `CONSOLE_SECRETS_ENVELOPE_V2` off until every box runs v0.23.0.** When it is on, the console seals new secrets so they open only for their own account and app. A box on an older release cannot open them, and the app's whole config stops updating on that box. Rolling a box back below v0.23.0 after turning it on does the same. A value that is not true or false stops the console from starting.", |
| 5240 | "branches": [ |
| 5241 | "tenant-iso-binding" |
| 5242 | ] |
| 5243 | }, |
| 5244 | { |
| 5245 | "md": "**v0.23.0 is the first release that understands app regions.** That makes it the rollback floor the README describes: once any app holds a region other than the home, do not roll the console below v0.23.0. `CONSOLE_APP_REGIONS` is off by default. Turn it on only by the README's steps. Boxes now publish `serves_shared_pool`, `accepts_inbound` and, where they hold the secrets key, `secrets_key_fp` in their edges file.", |
| 5246 | "branches": [ |
| 5247 | "design-nearest-region" |
| 5248 | ] |
| 5249 | }, |
| 5250 | { |
| 5251 | "md": "**Boxes restart awake instances when they adopt a release.** The agent checks every two seconds and restarts at most one instance per check. Workers still converge on the old 90-second timer. A restart drains the old process as before: new requests wait for the new one.", |
| 5252 | "branches": [ |
| 5253 | "fix-adopted-exec-restart" |
| 5254 | ] |
| 5255 | }, |
| 5256 | { |
| 5257 | "md": "**Static responses change their headers.** They now carry `Cache-Control: no-cache` and a weak `ETag` worked out from each file's bytes and type, and no `Last-Modified`. The first request for a file after a deploy reads it once to work out the tag. The edge's own cache still does not store static responses.", |
| 5258 | "branches": [ |
| 5259 | "static-cache-control" |
| 5260 | ] |
| 5261 | }, |
| 5262 | { |
| 5263 | "md": "**Pin infrastructure modules to v0.23.0.** The box role gains permission to list, read and delete object versions in its own data bucket. Nothing uses it yet, so applying it can wait. Check also that nothing in your policies denies `s3:DeleteObject` on the deployment bucket: purges, store teardown and mail claim release delete objects, and fail without it.", |
| 5264 | "branches": [ |
| 5265 | "feat/hostclaim-storage" |
| 5266 | ] |
| 5267 | }, |
| 5268 | { |
| 5269 | "md": "**Run `carlos accounts migrate` with a v0.23.0 CLI.** Pointers are now signed for their account, and migrating re-signs them, which needs the root `CARLOS_RELEASE_KEY`. An older CLI copies them unchanged, and the moved app stops adopting releases.", |
| 5270 | "branches": [ |
| 5271 | "tenant-iso-binding" |
| 5272 | ], |
| 5273 | "docs": [ |
| 5274 | "/docs/cli#carlos-accounts" |
| 5275 | ] |
| 5276 | }, |
| 5277 | { |
| 5278 | "md": "**Existing data is left in place.** Purging an app now also deletes its tokens, door keys and ledgers, but apps purged before this release keep theirs. Removing a sending domain that was added before this release leaves its SES identity in SES. Moving an app revokes its door keys, so moved apps need new ones.", |
| 5279 | "branches": [ |
| 5280 | "tenant-iso-leftovers", |
| 5281 | "tenant-iso-mail" |
| 5282 | ] |
| 5283 | } |
| 5284 | ] |
| 5285 | } |
| 5286 | ] |
| 5287 | }, |
| 5288 | "changes": [ |
| 5289 | { |
| 5290 | "sha": "3ca43d338643a8ca17290c6896e97e5cfc251cb3", |
| 5291 | "date": "2026-10-05", |
| 5292 | "subject": "lease: versioned storage primitives for the host lifecycle claim (Plan 2)", |
| 5293 | "branch": "feat/hostclaim-storage", |
| 5294 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fhostclaim-storage", |
| 5295 | "commits": 5, |
| 5296 | "credit": [ |
| 5297 | { |
| 5298 | "person": "Paul Campbell", |
| 5299 | "agents": [ |
| 5300 | "claude", |
| 5301 | "codex" |
| 5302 | ] |
| 5303 | } |
| 5304 | ] |
| 5305 | }, |
| 5306 | { |
| 5307 | "sha": "b58e1275c08664f4d059e24b9488d0175c723807", |
| 5308 | "date": "2026-10-05", |
| 5309 | "subject": "edge: static responses revalidate, on a version ETag", |
| 5310 | "branch": "static-cache-control", |
| 5311 | "branch_url": "https://amadan.net/carlos/platform/-/branch/static-cache-control", |
| 5312 | "commits": 5, |
| 5313 | "discussions": [ |
| 5314 | { |
| 5315 | "id": 195, |
| 5316 | "title": "Static apps: send Cache-Control (HTML revalidates; let an app say what is immutable)", |
| 5317 | "state": "open" |
| 5318 | } |
| 5319 | ], |
| 5320 | "credit": [ |
| 5321 | { |
| 5322 | "person": "Paul Campbell", |
| 5323 | "agents": [ |
| 5324 | "claude" |
| 5325 | ] |
| 5326 | } |
| 5327 | ] |
| 5328 | }, |
| 5329 | { |
| 5330 | "sha": "3a86f34855599a2ac30bff977491b8998f39e6ba", |
| 5331 | "date": "2026-10-05", |
| 5332 | "subject": "host, activator: the agent finishes an adoption the root pass performed", |
| 5333 | "branch": "fix-adopted-exec-restart", |
| 5334 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-adopted-exec-restart", |
| 5335 | "commits": 4, |
| 5336 | "discussions": [ |
| 5337 | { |
| 5338 | "id": 231, |
| 5339 | "title": "An awake exec instance is not restarted when a release is adopted: it serves the old build for 110-200s", |
| 5340 | "state": "open" |
| 5341 | } |
| 5342 | ], |
| 5343 | "credit": [ |
| 5344 | { |
| 5345 | "person": "Paul Campbell", |
| 5346 | "agents": [ |
| 5347 | "claude" |
| 5348 | ] |
| 5349 | } |
| 5350 | ] |
| 5351 | }, |
| 5352 | { |
| 5353 | "sha": "8d8e4baef3421c20e2411824fb2884099c081926", |
| 5354 | "date": "2026-10-04", |
| 5355 | "subject": "console tests: untangle #208 and nearest-region on main", |
| 5356 | "branch": "fix/console-capturelog", |
| 5357 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fconsole-capturelog", |
| 5358 | "commits": 1, |
| 5359 | "discussions": [ |
| 5360 | { |
| 5361 | "id": 208, |
| 5362 | "title": "status --instances closes the console's shared registry handle; app create then fails for everyone until restart", |
| 5363 | "state": "closed" |
| 5364 | } |
| 5365 | ], |
| 5366 | "credit": [ |
| 5367 | { |
| 5368 | "person": "Paul Campbell", |
| 5369 | "agents": [ |
| 5370 | "claude" |
| 5371 | ] |
| 5372 | } |
| 5373 | ] |
| 5374 | }, |
| 5375 | { |
| 5376 | "sha": "be3338d4fbe477dc1f34ab46956cb1b5401ef53a", |
| 5377 | "date": "2026-10-04", |
| 5378 | "subject": "Mail: members can't adopt another party's SES identity; unverified sending-domain claims lapse (#216)", |
| 5379 | "branch": "tenant-iso-mail", |
| 5380 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-mail", |
| 5381 | "commits": 1, |
| 5382 | "discussions": [ |
| 5383 | { |
| 5384 | "id": 216, |
| 5385 | "title": "Mail: a member can adopt another party's verified SES domain; sending-domain claims never expire", |
| 5386 | "state": "open" |
| 5387 | } |
| 5388 | ], |
| 5389 | "docs": [ |
| 5390 | "/docs/cli#carlos-email" |
| 5391 | ], |
| 5392 | "credit": [ |
| 5393 | { |
| 5394 | "person": "Paul Campbell", |
| 5395 | "agents": [ |
| 5396 | "claude" |
| 5397 | ] |
| 5398 | } |
| 5399 | ] |
| 5400 | }, |
| 5401 | { |
| 5402 | "sha": "f36ad36ab252f9c090a766dc063f5efe9c3f661e", |
| 5403 | "date": "2026-10-04", |
| 5404 | "subject": "Purge and membership leftovers: credentials, door keys and ledgers end with their app; invite accept by POST (#219)", |
| 5405 | "branch": "tenant-iso-leftovers", |
| 5406 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-leftovers", |
| 5407 | "commits": 1, |
| 5408 | "discussions": [ |
| 5409 | { |
| 5410 | "id": 219, |
| 5411 | "title": "Purge and membership leftovers: tokens, door keys and ledgers outlive their app; GET invite accept; global fleet names", |
| 5412 | "state": "open" |
| 5413 | } |
| 5414 | ], |
| 5415 | "credit": [ |
| 5416 | { |
| 5417 | "person": "Paul Campbell", |
| 5418 | "agents": [ |
| 5419 | "claude" |
| 5420 | ] |
| 5421 | } |
| 5422 | ] |
| 5423 | }, |
| 5424 | { |
| 5425 | "sha": "b94ad230f43e00bd57355f86e6da37d4a4a2a512", |
| 5426 | "date": "2026-10-04", |
| 5427 | "subject": "Bind release pointers and secret envelopes to their account; close relay deny-list gaps (#220)", |
| 5428 | "branch": "tenant-iso-binding", |
| 5429 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-binding", |
| 5430 | "commits": 1, |
| 5431 | "discussions": [ |
| 5432 | { |
| 5433 | "id": 220, |
| 5434 | "title": "Bind release pointers and secret envelopes to their account; close relay deny-list gaps", |
| 5435 | "state": "open" |
| 5436 | } |
| 5437 | ], |
| 5438 | "credit": [ |
| 5439 | { |
| 5440 | "person": "Paul Campbell", |
| 5441 | "agents": [ |
| 5442 | "claude" |
| 5443 | ] |
| 5444 | } |
| 5445 | ] |
| 5446 | }, |
| 5447 | { |
| 5448 | "sha": "2129e26ed9edc4b451f31ac52eca185b3e4e9c89", |
| 5449 | "date": "2026-10-04", |
| 5450 | "subject": "objstore: bucket and IAM user names can't collide across stores (#218, #191)", |
| 5451 | "branch": "tenant-iso-objstore", |
| 5452 | "branch_url": "https://amadan.net/carlos/platform/-/branch/tenant-iso-objstore", |
| 5453 | "commits": 1, |
| 5454 | "discussions": [ |
| 5455 | { |
| 5456 | "id": 191, |
| 5457 | "title": "A retried store teardown can delete a bucket another app has since been granted", |
| 5458 | "state": "closed" |
| 5459 | }, |
| 5460 | { |
| 5461 | "id": 218, |
| 5462 | "title": "objstore: app shop + environment eu and app shop-eu share one bucket and IAM user", |
| 5463 | "state": "closed" |
| 5464 | } |
| 5465 | ], |
| 5466 | "credit": [ |
| 5467 | { |
| 5468 | "person": "Paul Campbell", |
| 5469 | "agents": [ |
| 5470 | "claude" |
| 5471 | ] |
| 5472 | } |
| 5473 | ] |
| 5474 | }, |
| 5475 | { |
| 5476 | "sha": "a6e4cd41d0f9c5db5ed5e0c69d745b675bd86bbf", |
| 5477 | "date": "2026-10-04", |
| 5478 | "subject": "domains: the operator's door for platform hostnames (#209)", |
| 5479 | "branch": "platform-domain-claims-209", |
| 5480 | "branch_url": "https://amadan.net/carlos/platform/-/branch/platform-domain-claims-209", |
| 5481 | "commits": 2, |
| 5482 | "discussions": [ |
| 5483 | { |
| 5484 | "id": 209, |
| 5485 | "title": "domains attach: no supported way to put the platform's own apex (carloku.com) on a console app", |
| 5486 | "state": "closed" |
| 5487 | } |
| 5488 | ], |
| 5489 | "credit": [ |
| 5490 | { |
| 5491 | "person": "Paul Campbell", |
| 5492 | "agents": [ |
| 5493 | "claude" |
| 5494 | ] |
| 5495 | } |
| 5496 | ] |
| 5497 | }, |
| 5498 | { |
| 5499 | "sha": "3f4a9bfdfb3bd7791a5cdf6d122a69e43b62e894", |
| 5500 | "date": "2026-10-03", |
| 5501 | "subject": "docs: nearest-region default design spec", |
| 5502 | "branch": "design-nearest-region", |
| 5503 | "branch_url": "https://amadan.net/carlos/platform/-/branch/design-nearest-region", |
| 5504 | "commits": 72, |
| 5505 | "discussions": [ |
| 5506 | { |
| 5507 | "id": 169, |
| 5508 | "title": "Latency steering is armed nowhere: CARLOS_STEERING_ZONE_ID is unset in every infra root module", |
| 5509 | "state": "open" |
| 5510 | } |
| 5511 | ], |
| 5512 | "docs": [ |
| 5513 | "/docs/cli#carlos-apps", |
| 5514 | "/docs/cli#carlos-deploy", |
| 5515 | "/docs/cli#carlos-canary", |
| 5516 | "/docs/cli#carlos-instances", |
| 5517 | "/docs/cli#carlos-services" |
| 5518 | ], |
| 5519 | "credit": [ |
| 5520 | { |
| 5521 | "person": "Paul Campbell", |
| 5522 | "agents": [ |
| 5523 | "claude" |
| 5524 | ] |
| 5525 | } |
| 5526 | ] |
| 5527 | }, |
| 5528 | { |
| 5529 | "sha": "78fc8d40133a9c1ab538c5566ce6fa6b5149127f", |
| 5530 | "date": "2026-10-03", |
| 5531 | "subject": "console: protect shared registry lifetime (#208)", |
| 5532 | "branch": "fix-console-registry-208", |
| 5533 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-console-registry-208", |
| 5534 | "commits": 1, |
| 5535 | "discussions": [ |
| 5536 | { |
| 5537 | "id": 208, |
| 5538 | "title": "status --instances closes the console's shared registry handle; app create then fails for everyone until restart", |
| 5539 | "state": "closed" |
| 5540 | }, |
| 5541 | { |
| 5542 | "id": 210, |
| 5543 | "title": "Review: fix-console-registry-208", |
| 5544 | "state": "closed" |
| 5545 | } |
| 5546 | ], |
| 5547 | "credit": [ |
| 5548 | { |
| 5549 | "person": "Paul Campbell", |
| 5550 | "agents": [ |
| 5551 | "codex" |
| 5552 | ] |
| 5553 | } |
| 5554 | ] |
| 5555 | }, |
| 5556 | { |
| 5557 | "sha": "fe2088e3c7ce6879bc3a9f974964a3623f1ce431", |
| 5558 | "date": "2026-10-02", |
| 5559 | "subject": "console: create refuses a host that still holds a deleted instance's replica (#199 stopgap)", |
| 5560 | "branch": "fix/199-create-refuses-leftovers", |
| 5561 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2F199-create-refuses-leftovers", |
| 5562 | "commits": 2, |
| 5563 | "discussions": [ |
| 5564 | { |
| 5565 | "id": 199, |
| 5566 | "title": "A deleted instance's replica is inherited by whoever next creates the same host, in any account", |
| 5567 | "state": "open" |
| 5568 | } |
| 5569 | ], |
| 5570 | "credit": [ |
| 5571 | { |
| 5572 | "person": "Paul Campbell", |
| 5573 | "agents": [ |
| 5574 | "claude" |
| 5575 | ] |
| 5576 | } |
| 5577 | ] |
| 5578 | }, |
| 5579 | { |
| 5580 | "sha": "a7a2aaa2eea6a8ea17b39563a2236f5eb37aaa52", |
| 5581 | "date": "2026-10-02", |
| 5582 | "subject": "console: system operators can roll signed platform releases (#176)", |
| 5583 | "branch": "system-operators-176", |
| 5584 | "branch_url": "https://amadan.net/carlos/platform/-/branch/system-operators-176", |
| 5585 | "commits": 2, |
| 5586 | "discussions": [ |
| 5587 | { |
| 5588 | "id": 176, |
| 5589 | "title": "A system operator role for rolling platform releases", |
| 5590 | "state": "open" |
| 5591 | }, |
| 5592 | { |
| 5593 | "id": 201, |
| 5594 | "title": "Move Tito's console from cf02a4d5-tito back onto main", |
| 5595 | "state": "closed" |
| 5596 | } |
| 5597 | ], |
| 5598 | "docs": [ |
| 5599 | "/docs/cli#the-platform-s-own-binary" |
| 5600 | ], |
| 5601 | "credit": [ |
| 5602 | { |
| 5603 | "person": "Paul Campbell", |
| 5604 | "agents": [ |
| 5605 | "claude" |
| 5606 | ] |
| 5607 | } |
| 5608 | ] |
| 5609 | }, |
| 5610 | { |
| 5611 | "sha": "da866a929171673a29ad99004dc07d53e42f9d4a", |
| 5612 | "date": "2026-10-02", |
| 5613 | "subject": "carlos db pull and query: read an instance's database from its replica (spec 2026-09-02, unit 1)", |
| 5614 | "branch": "feat/carlos-db-read", |
| 5615 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feat%2Fcarlos-db-read", |
| 5616 | "commits": 24, |
| 5617 | "docs": [ |
| 5618 | "/docs/cli#carlos-db" |
| 5619 | ], |
| 5620 | "credit": [ |
| 5621 | { |
| 5622 | "person": "Paul Campbell", |
| 5623 | "agents": [ |
| 5624 | "claude" |
| 5625 | ] |
| 5626 | }, |
| 5627 | { |
| 5628 | "person": "Tony Wood" |
| 5629 | } |
| 5630 | ] |
| 5631 | } |
| 5632 | ] |
| 5633 | }, |
| 5634 | { |
| 5635 | "tag": "v0.22.2", |
| 5636 | "date": "2026-10-01", |
| 5637 | "sha": "7edd4b33907a7bfa14394c3755b3e97eee06a5ed", |
| 5638 | "published": true, |
| 5639 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.22.2", |
| 5640 | "notes": { |
| 5641 | "form": "bullets", |
| 5642 | "sections": [ |
| 5643 | { |
| 5644 | "title": "", |
| 5645 | "bullets": [ |
| 5646 | { |
| 5647 | "md": "**Database size on the app Overview.** A new tile shows how much disk your app's databases use, including copies that are asleep.", |
| 5648 | "branches": [ |
| 5649 | "feature/instance-db-stats-card" |
| 5650 | ] |
| 5651 | }, |
| 5652 | { |
| 5653 | "md": "**Busy and large instances can finish a move.** An instance that is awake and writing, or that keeps large database files, can now finish moving to another region. Before, such a move could wait in `preparing` and never become ready. The cut still copies everything that is left, exactly, before the instance serves from its new region.", |
| 5654 | "branches": [ |
| 5655 | "move-ready-delta-threshold" |
| 5656 | ] |
| 5657 | }, |
| 5658 | { |
| 5659 | "md": "**Nothing new to type.** The CLI has no new commands or flags in this release." |
| 5660 | } |
| 5661 | ] |
| 5662 | }, |
| 5663 | { |
| 5664 | "title": "For operators", |
| 5665 | "bullets": [ |
| 5666 | { |
| 5667 | "md": "**v0.22.1 was tagged but never published.** v0.22.2 supersedes it, so roll v0.22.2 and pin modules to v0.22.2." |
| 5668 | }, |
| 5669 | { |
| 5670 | "md": "**A move becomes ready when little is left to copy.** By default, a preparing round now promotes when it copied 16 MiB or less. To change that bar, set `CARLOS_MOVE_READY_DELTA_BYTES` in `/etc/carlos/host.env`; the agent reads it when it starts. `0` restores the old rule that a round must copy nothing. A value that is not a whole number of bytes is ignored with a log line, and the default stays. The ready log line now shows the bytes copied, the number of changes and the bar.", |
| 5671 | "branches": [ |
| 5672 | "move-ready-delta-threshold" |
| 5673 | ] |
| 5674 | }, |
| 5675 | { |
| 5676 | "md": "**Copy receipts in the source box's data bucket.** A box moving an instance away keeps receipts at `move-receipts/<host>.json` in its own data bucket, so large objects that have not changed are not copied again. The cut and an abort delete them. A deployment whose data-bucket policy denies DeleteObject keeps stale receipts, which are harmless. The box policy in this repo already allows the prefix.", |
| 5677 | "branches": [ |
| 5678 | "move-ready-delta-threshold" |
| 5679 | ] |
| 5680 | }, |
| 5681 | { |
| 5682 | "md": "**The cut is still exact.** It copies everything that is left before it flips the record. If an object changes during that final copy, the cut waits for the next pass instead of landing an incomplete copy.", |
| 5683 | "branches": [ |
| 5684 | "move-ready-delta-threshold" |
| 5685 | ] |
| 5686 | }, |
| 5687 | { |
| 5688 | "md": "**The Database tile is console only.** It reads the database sizes boxes have reported since v0.21.0, so it needs no box roll and no env or IAM change. A slow read shows a dash and never holds up the page.", |
| 5689 | "branches": [ |
| 5690 | "feature/instance-db-stats-card" |
| 5691 | ] |
| 5692 | } |
| 5693 | ] |
| 5694 | } |
| 5695 | ] |
| 5696 | }, |
| 5697 | "changes": [ |
| 5698 | { |
| 5699 | "sha": "7edd4b33907a7bfa14394c3755b3e97eee06a5ed", |
| 5700 | "date": "2026-10-01", |
| 5701 | "subject": "lease: MirrorPrefix reports the bytes a round copied", |
| 5702 | "branch": "move-ready-delta-threshold", |
| 5703 | "branch_url": "https://amadan.net/carlos/platform/-/branch/move-ready-delta-threshold", |
| 5704 | "commits": 4, |
| 5705 | "discussions": [ |
| 5706 | { |
| 5707 | "id": 175, |
| 5708 | "title": "Instance moves for every app: the platform runs the move (Tito Go is the first adopter)", |
| 5709 | "state": "open" |
| 5710 | } |
| 5711 | ], |
| 5712 | "credit": [ |
| 5713 | { |
| 5714 | "person": "Paul Campbell", |
| 5715 | "agents": [ |
| 5716 | "claude" |
| 5717 | ] |
| 5718 | } |
| 5719 | ] |
| 5720 | }, |
| 5721 | { |
| 5722 | "sha": "abe897e017f7a9d6b706e9b5a42378a58bd1c355", |
| 5723 | "date": "2026-10-01", |
| 5724 | "subject": "console: a Database tile on the app Overview (size on disk, including sleeping copies)", |
| 5725 | "branch": "feature/instance-db-stats-card", |
| 5726 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feature%2Finstance-db-stats-card", |
| 5727 | "commits": 2, |
| 5728 | "discussions": [ |
| 5729 | { |
| 5730 | "id": 197, |
| 5731 | "title": "Review: tile shows the DB size only; box disk is not tenant data", |
| 5732 | "state": "open" |
| 5733 | } |
| 5734 | ], |
| 5735 | "credit": [ |
| 5736 | { |
| 5737 | "person": "Paul Campbell", |
| 5738 | "agents": [ |
| 5739 | "claude" |
| 5740 | ] |
| 5741 | }, |
| 5742 | { |
| 5743 | "person": "Tony Wood", |
| 5744 | "agents": [ |
| 5745 | "claude" |
| 5746 | ] |
| 5747 | } |
| 5748 | ] |
| 5749 | } |
| 5750 | ] |
| 5751 | }, |
| 5752 | { |
| 5753 | "tag": "v0.22.1", |
| 5754 | "date": "2026-10-01", |
| 5755 | "sha": "abe897e017f7a9d6b706e9b5a42378a58bd1c355", |
| 5756 | "published": false, |
| 5757 | "notes": null, |
| 5758 | "changes": [ |
| 5759 | { |
| 5760 | "sha": "abe897e017f7a9d6b706e9b5a42378a58bd1c355", |
| 5761 | "date": "2026-10-01", |
| 5762 | "subject": "console: a Database tile on the app Overview (size on disk, including sleeping copies)", |
| 5763 | "branch": "feature/instance-db-stats-card", |
| 5764 | "branch_url": "https://amadan.net/carlos/platform/-/branch/feature%2Finstance-db-stats-card", |
| 5765 | "commits": 2, |
| 5766 | "discussions": [ |
| 5767 | { |
| 5768 | "id": 197, |
| 5769 | "title": "Review: tile shows the DB size only; box disk is not tenant data", |
| 5770 | "state": "open" |
| 5771 | } |
| 5772 | ], |
| 5773 | "credit": [ |
| 5774 | { |
| 5775 | "person": "Paul Campbell", |
| 5776 | "agents": [ |
| 5777 | "claude" |
| 5778 | ] |
| 5779 | }, |
| 5780 | { |
| 5781 | "person": "Tony Wood", |
| 5782 | "agents": [ |
| 5783 | "claude" |
| 5784 | ] |
| 5785 | } |
| 5786 | ] |
| 5787 | } |
| 5788 | ] |
| 5789 | }, |
| 5790 | { |
| 5791 | "tag": "v0.22.0", |
| 5792 | "date": "2026-10-01", |
| 5793 | "sha": "91fc2c432f390fbe55e4b8210a3e070db92f297e", |
| 5794 | "published": true, |
| 5795 | "notes_url": "https://github.com/carlosframework/releases/releases/tag/v0.22.0", |
| 5796 | "notes": { |
| 5797 | "form": "bullets", |
| 5798 | "sections": [ |
| 5799 | { |
| 5800 | "title": "", |
| 5801 | "bullets": [ |
| 5802 | { |
| 5803 | "md": "**Availability, apart from errors.** `carlos availability` lists the requests an app's instances could not answer, every 502, 503 and 504 the edge saw, grouped by cause instead of by page. One outage is one row, however many pages it hit. `--fp <id>` expands a cause to each request and the path it asked for. The same view is the new Availability tab beside Errors.", |
| 5804 | "branches": [ |
| 5805 | "availability-tab" |
| 5806 | ], |
| 5807 | "docs": [ |
| 5808 | "/docs/cli#carlos-availability" |
| 5809 | ] |
| 5810 | }, |
| 5811 | { |
| 5812 | "md": "**Errors is shorter.** `carlos errors` and the Errors tab keep the app's own 500s and the error lines in its logs. Edge 502s, 503s and 504s, failed wakes and exits have moved to Availability.", |
| 5813 | "branches": [ |
| 5814 | "availability-tab" |
| 5815 | ], |
| 5816 | "docs": [ |
| 5817 | "/docs/cli#carlos-errors" |
| 5818 | ] |
| 5819 | }, |
| 5820 | { |
| 5821 | "md": "**Replica instances.** `carlos instances create --role replica --region <r>` makes a second instance of an app, holding a one-way copy of the live instance's data, in a region near its buyers. The live instance names the regions it allows replicas in with `--replicas ie,uk` when it is created. Until a batch of orders drains home, a replica holds order data in its own region, so the regions are always a decision on the live instance, never a default.", |
| 5822 | "branches": [ |
| 5823 | "edge-replica-placements" |
| 5824 | ], |
| 5825 | "docs": [ |
| 5826 | "/docs/cli#carlos-instances" |
| 5827 | ] |
| 5828 | }, |
| 5829 | { |
| 5830 | "md": "**Door keys.** `carlos instances door-key create`, `list` and `revoke` manage keys for the edge-local door. That is one socket on a box that a process running beside an app's instances can dial to reach any of them, whether it is asleep, moved to another box or awake. A key is shown once, when it is created. The door is off until the box's operator turns it on.", |
| 5831 | "branches": [ |
| 5832 | "instance-moves-p7" |
| 5833 | ], |
| 5834 | "docs": [ |
| 5835 | "/docs/cli#carlos-instances" |
| 5836 | ] |
| 5837 | }, |
| 5838 | { |
| 5839 | "md": "**Faster log reads.** Log chunks are now fetched 16 at a time instead of one by one, which speeds up `carlos logs`, Errors and Availability.", |
| 5840 | "branches": [ |
| 5841 | "parallel-chunk-read" |
| 5842 | ], |
| 5843 | "docs": [ |
| 5844 | "/docs/cli#carlos-logs" |
| 5845 | ] |
| 5846 | }, |
| 5847 | { |
| 5848 | "md": "**A restored app keeps its pipeline.** When the console registers an app whose files are already in the bucket, it keeps that app's release pipeline instead of resetting it to the default.", |
| 5849 | "branches": [ |
| 5850 | "fix/preserve-adopted-app-pipeline" |
| 5851 | ] |
| 5852 | } |
| 5853 | ] |
| 5854 | }, |
| 5855 | { |
| 5856 | "title": "For operators", |
| 5857 | "bullets": [ |
| 5858 | { |
| 5859 | "md": "**Roll the console first, then the boxes, close together.** The boxes record why the edge had no answer and the console shows it. A console on its own groups stored 502s under \"cause not recorded\", and new ones too until the boxes roll. Boxes on their own, under an old console, list each cause as its own row on Errors. Rolling the console back is safe: nothing in the bucket is rewritten.", |
| 5860 | "branches": [ |
| 5861 | "availability-tab" |
| 5862 | ] |
| 5863 | }, |
| 5864 | { |
| 5865 | "md": "**A new CLI against an old console.** `carlos availability` fails with `not found: check --account and --app, and that your token's address is a member`. Until the console rolls, that message means the console predates the command, not that the app or your membership is missing. An old console silently ignores `carlos instances create --role replica` and creates an ordinary instance in that region instead.", |
| 5866 | "branches": [ |
| 5867 | "availability-tab", |
| 5868 | "edge-replica-placements" |
| 5869 | ], |
| 5870 | "docs": [ |
| 5871 | "/docs/cli#carlos-availability", |
| 5872 | "/docs/cli#carlos-instances" |
| 5873 | ] |
| 5874 | }, |
| 5875 | { |
| 5876 | "md": "**No replicas until every box has rolled.** Only this release keeps replicas out of DNS latency routing. Each box adds two columns to its registry when it starts (`routes.replicas` and `routes.replica`). There is nothing to migrate, and a box rolled back ignores them.", |
| 5877 | "branches": [ |
| 5878 | "edge-replica-placements" |
| 5879 | ] |
| 5880 | }, |
| 5881 | { |
| 5882 | "md": "**Long polls show up in Availability.** A visitor who gives up after waiting five seconds or more, before the instance has sent response headers, is filed as an outage. On a sleeping route the five seconds include the wake. An endpoint that holds its headers longer by design, like a long poll, shows a standing row, and that row is expected. A visitor who leaves sooner is no longer filed at all, so expect fewer one-off 502s on static files.", |
| 5883 | "branches": [ |
| 5884 | "availability-tab" |
| 5885 | ] |
| 5886 | }, |
| 5887 | { |
| 5888 | "md": "**Tunnelled failures are filed once.** On a route a box reaches over a tunnel or a fleet, the front box files only its own hop failures, and the box serving the app files the rest.", |
| 5889 | "branches": [ |
| 5890 | "availability-tab" |
| 5891 | ] |
| 5892 | }, |
| 5893 | { |
| 5894 | "md": "**Instance moves.** A box cutting a move now fences the instance so a scheduled wake cannot start it again mid-move. A move past ready can no longer be aborted, and a replica cannot be moved: delete it and create one in the new region. A later release's boxes rely on this console's abort rule, which is one more reason to roll the console first.", |
| 5895 | "branches": [ |
| 5896 | "instance-moves-p0" |
| 5897 | ] |
| 5898 | }, |
| 5899 | { |
| 5900 | "md": "**The edge-local door is off by default.** It stays off until a box sets `CARLOS_EDGE_DOOR=/run/carlos/edge-local.sock` and its agent restarts. The calling process's user must also be enrolled with `carlos bootstrap --socket-consumer <user>`. The console re-signs door keys every 12 hours, and a key whose record has not been re-signed for 72 hours stops working, so a console down that long closes every door.", |
| 5901 | "branches": [ |
| 5902 | "instance-moves-p7" |
| 5903 | ], |
| 5904 | "docs": [ |
| 5905 | "/docs/cli#carlos-bootstrap" |
| 5906 | ] |
| 5907 | }, |
| 5908 | { |
| 5909 | "md": "**Each instance gets its own `/dev/shm`.** Instance units no longer see the host's `/dev/shm`, so an instance cannot reach another's shared memory. They also no longer set `RestrictSUIDSGID=`, which broke `openat2` on systemd 257 and kept the isolated exec probe from reporting ready. `carlos system update` installs the new units, and a running instance picks them up when it next restarts.", |
| 5910 | "branches": [ |
| 5911 | "isolated-exec-probe-fixes" |
| 5912 | ], |
| 5913 | "docs": [ |
| 5914 | "/docs/cli#carlos-system" |
| 5915 | ] |
| 5916 | } |
| 5917 | ] |
| 5918 | } |
| 5919 | ] |
| 5920 | }, |
| 5921 | "changes": [ |
| 5922 | { |
| 5923 | "sha": "91fc2c432f390fbe55e4b8210a3e070db92f297e", |
| 5924 | "date": "2026-10-01", |
| 5925 | "subject": "Bound worker assignment storage versions and reject enabled no-op writes", |
| 5926 | "branch": "fix-worker-store-bounds", |
| 5927 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix-worker-store-bounds", |
| 5928 | "commits": 1, |
| 5929 | "discussions": [ |
| 5930 | { |
| 5931 | "id": 146, |
| 5932 | "title": "Bound worker assignment storage versions", |
| 5933 | "state": "closed" |
| 5934 | } |
| 5935 | ], |
| 5936 | "credit": [ |
| 5937 | { |
| 5938 | "person": "Paul Campbell" |
| 5939 | } |
| 5940 | ] |
| 5941 | }, |
| 5942 | { |
| 5943 | "sha": "e8406ce6bf2b09bf5b2ae16bdcb00883870ba6ca", |
| 5944 | "date": "2026-10-01", |
| 5945 | "subject": "AGENTS.md: the flagship root lives in carloku-infrastructure, pinned to release tags", |
| 5946 | "branch": "docs-carloku-infra-split", |
| 5947 | "branch_url": "https://amadan.net/carlos/platform/-/branch/docs-carloku-infra-split", |
| 5948 | "commits": 1, |
| 5949 | "credit": [ |
| 5950 | { |
| 5951 | "person": "Paul Campbell", |
| 5952 | "agents": [ |
| 5953 | "claude" |
| 5954 | ] |
| 5955 | } |
| 5956 | ] |
| 5957 | }, |
| 5958 | { |
| 5959 | "sha": "88abfae2e9e3def544eb6415b2d71bf8bff888c0", |
| 5960 | "date": "2026-09-29", |
| 5961 | "subject": "instance moves P7 (#175): the edge-local door, dormant until CARLOS_EDGE_DOOR", |
| 5962 | "branch": "instance-moves-p7", |
| 5963 | "branch_url": "https://amadan.net/carlos/platform/-/branch/instance-moves-p7", |
| 5964 | "commits": 15, |
| 5965 | "discussions": [ |
| 5966 | { |
| 5967 | "id": 175, |
| 5968 | "title": "Instance moves for every app: the platform runs the move (Tito Go is the first adopter)", |
| 5969 | "state": "open" |
| 5970 | } |
| 5971 | ], |
| 5972 | "docs": [ |
| 5973 | "/docs/cli#storage-of-its-own-for-every-instance" |
| 5974 | ], |
| 5975 | "credit": [ |
| 5976 | { |
| 5977 | "person": "Paul Campbell", |
| 5978 | "agents": [ |
| 5979 | "claude" |
| 5980 | ] |
| 5981 | } |
| 5982 | ] |
| 5983 | }, |
| 5984 | { |
| 5985 | "sha": "52f7114351a0dd0dbd6097276c4b7d2f3913cfe6", |
| 5986 | "date": "2026-09-25", |
| 5987 | "subject": "isolated exec: the probe goes ready, and each instance gets its own /dev/shm (#126)", |
| 5988 | "branch": "isolated-exec-probe-fixes", |
| 5989 | "branch_url": "https://amadan.net/carlos/platform/-/branch/isolated-exec-probe-fixes", |
| 5990 | "commits": 2, |
| 5991 | "discussions": [ |
| 5992 | { |
| 5993 | "id": 126, |
| 5994 | "title": "activator: exec-backed instances share one uid and one flat DataDir — cross-tenant and cross-app", |
| 5995 | "state": "open" |
| 5996 | }, |
| 5997 | { |
| 5998 | "id": 178, |
| 5999 | "title": "isolated exec: POSIX mqueues and abstract unix sockets are still shared between instances", |
| 6000 | "state": "closed" |
| 6001 | } |
| 6002 | ], |
| 6003 | "credit": [ |
| 6004 | { |
| 6005 | "person": "Paul Campbell", |
| 6006 | "agents": [ |
| 6007 | "claude" |
| 6008 | ] |
| 6009 | } |
| 6010 | ] |
| 6011 | }, |
| 6012 | { |
| 6013 | "sha": "408db5effd3e65e19ec09c383faa3ce16378c383", |
| 6014 | "date": "2026-09-25", |
| 6015 | "subject": "instance moves P0 (#175): fence the cut against tick wakes, refuse abort past ready, refuse moving a replica", |
| 6016 | "branch": "instance-moves-p0", |
| 6017 | "branch_url": "https://amadan.net/carlos/platform/-/branch/instance-moves-p0", |
| 6018 | "commits": 2, |
| 6019 | "discussions": [ |
| 6020 | { |
| 6021 | "id": 175, |
| 6022 | "title": "Instance moves for every app: the platform runs the move (Tito Go is the first adopter)", |
| 6023 | "state": "open" |
| 6024 | } |
| 6025 | ], |
| 6026 | "credit": [ |
| 6027 | { |
| 6028 | "person": "Paul Campbell", |
| 6029 | "agents": [ |
| 6030 | "claude" |
| 6031 | ] |
| 6032 | } |
| 6033 | ] |
| 6034 | }, |
| 6035 | { |
| 6036 | "sha": "4d5eab8a2cbe72dfcb3a2d727b1f5b42f7210602", |
| 6037 | "date": "2026-09-24", |
| 6038 | "subject": "Preserve existing release pipelines when restoring app registration", |
| 6039 | "branch": "fix/preserve-adopted-app-pipeline", |
| 6040 | "branch_url": "https://amadan.net/carlos/platform/-/branch/fix%2Fpreserve-adopted-app-pipeline", |
| 6041 | "commits": 1, |
| 6042 | "credit": [ |
| 6043 | { |
| 6044 | "person": "Paul Campbell", |
| 6045 | "agents": [ |
| 6046 | "codex" |
| 6047 | ] |
| 6048 | } |
| 6049 | ] |
| 6050 | }, |
| 6051 | { |
| 6052 | "sha": "8c54ec7a8ecdb8428d1850ee48867096f01bbba8", |
| 6053 | "date": "2026-09-24", |
| 6054 | "subject": ".claude: install amadan's agent skill; ignore local Claude settings", |
| 6055 | "branch": "amadan-agent-skill", |
| 6056 | "branch_url": "https://amadan.net/carlos/platform/-/branch/amadan-agent-skill", |
| 6057 | "commits": 1, |
| 6058 | "credit": [ |
| 6059 | { |
| 6060 | "person": "Bill Horsman", |
| 6061 | "agents": [ |
| 6062 | "claude" |
| 6063 | ] |
| 6064 | } |
| 6065 | ] |
| 6066 | }, |
| 6067 | { |
| 6068 | "sha": "2158949f7597b65bbd4ddc4be541eb9b20ded78e", |
| 6069 | "date": "2026-09-24", |
| 6070 | "subject": "README: operator note for v0.22.0 (Availability, replica placements)", |
| 6071 | "branch": "release-notes-v0.22.0", |
| 6072 | "branch_url": "https://amadan.net/carlos/platform/-/branch/release-notes-v0.22.0", |
| 6073 | "commits": 1, |
| 6074 | "credit": [ |
| 6075 | { |
| 6076 | "person": "Bill Horsman", |
| 6077 | "agents": [ |
| 6078 | "claude" |
| 6079 | ] |
| 6080 | } |
| 6081 | ] |
| 6082 | }, |
| 6083 | { |
| 6084 | "sha": "1786da9c91449b98e453d809219926aee38c517a", |
| 6085 | "date": "2026-09-24", |
| 6086 | "subject": "spec: request references — one ID a customer can read out, and we can find", |
| 6087 | "branch": "refs-design", |
| 6088 | "branch_url": "https://amadan.net/carlos/platform/-/branch/refs-design", |
| 6089 | "commits": 1, |
| 6090 | "credit": [ |
| 6091 | { |
| 6092 | "person": "Bill Horsman", |
| 6093 | "agents": [ |
| 6094 | "claude" |
| 6095 | ] |
| 6096 | } |
| 6097 | ] |
| 6098 | }, |
| 6099 | { |
| 6100 | "sha": "f50e34259ab202685f2e0513c8cb3acb422e70b3", |
| 6101 | "date": "2026-09-24", |
| 6102 | "subject": "AGENTS.md: amadan is the source of truth; squash before landing", |
| 6103 | "branch": |