carlos / platform Public

rootfs apps: Astra plan review round 1 (reject, 14 findings), copy deck, R8 owners only

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 3dff221498fb372c32408998f21f76afe6e5caf7 parent 9c3d772
3 files changed, +564 −5
  • docs/superpowers/plans/2026-10-24-rootfs-apps-0-index.md +3 −5
  • docs/superpowers/plans/2026-10-24-rootfs-apps-copy.md +502 −0
  • docs/superpowers/plans/CODEX-FINDINGS-ROOTFS-PLANS-R1.md +59 −0

CI passed — run details

CI log
=== gate ===
.amadan/test-gate.sh
=== launchctx (0 s)
ok  	amadan.net/carlos/platform.git/launchctx	0.013s
?   	amadan.net/carlos/platform.git/launchctx/controlname	[no test files]
?   	amadan.net/carlos/platform.git/launchctx/wireid	[no test files]
=== vet (1 s)
=== gofmt (0 s)
gofmt -l .: clean
=== rest (149 s)
?   	github.com/carlosframework/platform/cmd/changelog	[no test files]
ok  	github.com/carlosframework/platform/cmd/console	3.777s
ok  	github.com/carlosframework/platform/cmd/moveprobe	11.951s
ok  	github.com/carlosframework/platform/cmd/zddprobe	0.743s
ok  	github.com/carlosframework/platform/internal/activator	60.252s
ok  	github.com/carlosframework/platform/internal/agentsock	0.020s
ok  	github.com/carlosframework/platform/internal/alerting	0.006s
ok  	github.com/carlosframework/platform/internal/analytics	0.026s
ok  	github.com/carlosframework/platform/internal/appconfig	3.159s
ok  	github.com/carlosframework/platform/internal/apperr	0.128s
ok  	github.com/carlosframework/platform/internal/applog	0.207s
ok  	github.com/carlosframework/platform/internal/awsinv	0.004s
ok  	github.com/carlosframework/platform/internal/boxchoice	0.007s
ok  	github.com/carlosframework/platform/internal/boxid	0.832s
?   	github.com/carlosframework/platform/internal/boxid/boxidtest	[no test files]
?   	github.com/carlosframework/platform/internal/boxid/internal/signtest	[no test files]
ok  	github.com/carlosframework/platform/internal/boxvolumes	0.009s
ok  	github.com/carlosframework/platform/internal/caps	0.016s
ok  	github.com/carlosframework/platform/internal/certwarm	0.002s
ok  	github.com/carlosframework/platform/internal/cgroup	0.820s
ok  	github.com/carlosframework/platform/internal/changelog	0.633s
ok  	github.com/carlosframework/platform/internal/claimactivation	1.324s
ok  	github.com/carlosframework/platform/internal/clamd	0.058s
?   	github.com/carlosframework/platform/internal/cliflag	[no test files]
?   	github.com/carlosframework/platform/internal/controlname	[no test files]
?   	github.com/carlosframework/platform/internal/controlsock	[no test files]
ok  	github.com/carlosframework/platform/internal/dbdoor	7.707s
ok  	github.com/carlosframework/platform/internal/dbdoor/dbdoortest	0.010s
ok  	github.com/carlosframework/platform/internal/dbquery	0.006s
ok  	github.com/carlosframework/platform/internal/dbreads	2.189s
?   	github.com/carlosframework/platform/internal/dbreads/dbreadstest	[no test files]
ok  	github.com/carlosframework/platform/internal/dbverify	0.004s
ok  	github.com/carlosframework/platform/internal/dnsrec	0.003s
ok  	github.com/carlosframework/platform/internal/docsite	0.014s
ok  	github.com/carlosframework/platform/internal/domains	2.902s
ok  	github.com/carlosframework/platform/internal/doorkey	0.007s
ok  	github.com/carlosframework/platform/internal/economics	0.006s
ok  	github.com/carlosframework/platform/internal/edge	45.605s
?   	github.com/carlosframework/platform/internal/edgeproof	[no test files]
ok  	github.com/carlosframework/platform/internal/edgesfile	0.009s
ok  	github.com/carlosframework/platform/internal/fleetapi	0.199s
ok  	github.com/carlosframework/platform/internal/gate	1.867s
ok  	github.com/carlosframework/platform/internal/genselect	0.027s
ok  	github.com/carlosframework/platform/internal/geo	0.018s
ok  	github.com/carlosframework/platform/internal/geoip	0.060s
ok  	github.com/carlosframework/platform/internal/historyreadback	0.337s
ok  	github.com/carlosframework/platform/internal/host	144.612s
ok  	github.com/carlosframework/platform/internal/hostactors	6.304s
ok  	github.com/carlosframework/platform/internal/hostactors/awsmembership	0.006s
ok  	github.com/carlosframework/platform/internal/hostbox	3.158s
ok  	github.com/carlosframework/platform/internal/hostclaim	0.809s
ok  	github.com/carlosframework/platform/internal/hostenv	0.011s
ok  	github.com/carlosframework/platform/internal/hostevidence	0.012s
ok  	github.com/carlosframework/platform/internal/hostexec	5.330s
ok  	github.com/carlosframework/platform/internal/hostfence	0.049s
ok  	github.com/carlosframework/platform/internal/hostfiles	10.249s
ok  	github.com/carlosframework/platform/internal/hostfloor	0.020s
ok  	github.com/carlosframework/platform/internal/hostguard	1.096s
ok  	github.com/carlosframework/platform/internal/hostops	2.158s
?   	github.com/carlosframework/platform/internal/hostops/fencerelease	[no test files]
ok  	github.com/carlosframework/platform/internal/hostops/internal/fencerelease	0.002s
ok  	github.com/carlosframework/platform/internal/hostquarantine	0.003s
ok  	github.com/carlosframework/platform/internal/hostrelocate	0.705s
ok  	github.com/carlosframework/platform/internal/hostresolve	0.266s
ok  	github.com/carlosframework/platform/internal/hostwrite	0.003s
ok  	github.com/carlosframework/platform/internal/infraview	0.005s
ok  	github.com/carlosframework/platform/internal/instancectl	5.235s
ok  	github.com/carlosframework/platform/internal/instanceexec	2.784s
ok  	github.com/carlosframework/platform/internal/instancefs	0.008s
ok  	github.com/carlosframework/platform/internal/instancekey	0.003s
ok  	github.com/carlosframework/platform/internal/instanceupdates	0.015s
ok  	github.com/carlosframework/platform/internal/layout	1.849s
ok  	github.com/carlosframework/platform/internal/lbhealth	0.005s
ok  	github.com/carlosframework/platform/internal/lease	10.315s
ok  	github.com/carlosframework/platform/internal/lease/leasetest	0.649s
ok  	github.com/carlosframework/platform/internal/ledger	0.023s
ok  	github.com/carlosframework/platform/internal/mail	0.306s
ok  	github.com/carlosframework/platform/internal/maintenance	0.088s
ok  	github.com/carlosframework/platform/internal/maintenanceexec	5.622s
ok  	github.com/carlosframework/platform/internal/maintenanceguard	0.084s
ok  	github.com/carlosframework/platform/internal/metrics	0.006s
ok  	github.com/carlosframework/platform/internal/moves	22.892s
ok  	github.com/carlosframework/platform/internal/moves/archive	1.123s
ok  	github.com/carlosframework/platform/internal/objstore	0.273s
ok  	github.com/carlosframework/platform/internal/ops	0.185s
ok  	github.com/carlosframework/platform/internal/park	0.307s
ok  	github.com/carlosframework/platform/internal/plans	0.005s
ok  	github.com/carlosframework/platform/internal/privatefile	0.006s
ok  	github.com/carlosframework/platform/internal/provision	24.892s
ok  	github.com/carlosframework/platform/internal/publicrelease	0.009s
?   	github.com/carlosframework/platform/internal/regionname	[no test files]
ok  	github.com/carlosframework/platform/internal/registry	5.697s
ok  	github.com/carlosframework/platform/internal/relay	7.241s
ok  	github.com/carlosframework/platform/internal/release	27.279s
ok  	github.com/carlosframework/platform/internal/rollout	3.720s
ok  	github.com/carlosframework/platform/internal/rolloutwords	0.006s
ok  	github.com/carlosframework/platform/internal/rootaws	0.010s
ok  	github.com/carlosframework/platform/internal/rootparticipation	0.068s
ok  	github.com/carlosframework/platform/internal/rootstate	0.029s
ok  	github.com/carlosframework/platform/internal/runs	0.511s
ok  	github.com/carlosframework/platform/internal/s3compat	0.008s
ok  	github.com/carlosframework/platform/internal/safefile	0.004s
ok  	github.com/carlosframework/platform/internal/schedule	2.703s
ok  	github.com/carlosframework/platform/internal/seeds	0.011s
ok  	github.com/carlosframework/platform/internal/sim/engines	2.551s
ok  	github.com/carlosframework/platform/internal/sim/hostlife	11.450s
ok  	github.com/carlosframework/platform/internal/sim/litestreamfacts	4.163s
ok  	github.com/carlosframework/platform/internal/status	0.101s
ok  	github.com/carlosframework/platform/internal/steering	0.007s
ok  	github.com/carlosframework/platform/internal/stopevidence	0.321s
ok  	github.com/carlosframework/platform/internal/svcrole	0.002s
ok  	github.com/carlosframework/platform/internal/telemetry	0.008s
ok  	github.com/carlosframework/platform/internal/termfence	0.007s
ok  	github.com/carlosframework/platform/internal/tunnelclient	0.005s
ok  	github.com/carlosframework/platform/internal/unixdial	0.003s
ok  	github.com/carlosframework/platform/internal/updatewords	0.009s
ok  	github.com/carlosframework/platform/internal/usage	0.008s
ok  	github.com/carlosframework/platform/internal/version	0.003s
ok  	github.com/carlosframework/platform/internal/vet	1.695s
=== internal_console@0 (81 s)
ok  	github.com/carlosframework/platform/internal/console	78.625s
=== internal_console@1 (46 s)
ok  	github.com/carlosframework/platform/internal/console	43.500s
=== internal_console@2 (43 s)
ok  	github.com/carlosframework/platform/internal/console	40.665s
=== internal_console@3 (42 s)
ok  	github.com/carlosframework/platform/internal/console	39.927s
=== internal_console@4 (45 s)
ok  	github.com/carlosframework/platform/internal/console	43.128s
=== internal_console@5 (43 s)
ok  	github.com/carlosframework/platform/internal/console	41.083s
=== internal_console@6 (40 s)
ok  	github.com/carlosframework/platform/internal/console	37.481s
=== internal_console@7 (48 s)
ok  	github.com/carlosframework/platform/internal/console	45.408s
=== root@0 (111 s)
ok  	github.com/carlosframework/platform	109.298s
=== root@1 (85 s)
ok  	github.com/carlosframework/platform	83.761s
=== root@2 (94 s)
ok  	github.com/carlosframework/platform	92.308s
=== cross ===
--- shard 0 of 5 ---
cross-compiling darwin/arm64
--- shard 1 of 5 ---
cross-compiling darwin/amd64
--- shard 2 of 5 ---
cross-compiling linux/arm64
linux/arm64 carlos binary: 50528418 bytes (ceiling 52000000)
--- shard 3 of 5 ---
cross-compiling windows/amd64
--- shard 4 of 5 ---
cross-compiling windows/arm64
=== minio-contract ===
minio contract: arm64, minio RELEASE.2025-09-07T16-13-09Z, mc RELEASE.2025-08-13T08-35-41Z
  minio: downloading https://github.com/minio/minio/releases/download/RELEASE.2025-09-07T16-13-09Z/minio.linux-arm64.RELEASE.2025-09-07T16-13-09Z
  minio: downloaded, digest verified
  mc: downloading https://github.com/minio/mc/releases/download/RELEASE.2025-08-13T08-35-41Z/mc.linux-arm64.RELEASE.2025-08-13T08-35-41Z
  mc: downloaded, digest verified
  minio healthy on 127.0.0.1:20999
Added `local` successfully.
Bucket created successfully `local/contract-bucket`.
Bucket created successfully `local/denied-bucket`.
Created policy `contract-only` successfully.
Added user `scopeduser` successfully.
Attached Policies: [contract-only]
To User: scopeduser
  buckets and scoped user ready
=== RUN   TestDeliveredContractMinio
=== RUN   TestDeliveredContractMinio/put
=== RUN   TestDeliveredContractMinio/get_round-trips_the_body
=== RUN   TestDeliveredContractMinio/list_shows_the_key
=== RUN   TestDeliveredContractMinio/head_and_list_agree_on_the_version
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed
=== RUN   TestDeliveredContractMinio/delete_removes_it
=== RUN   TestDeliveredContractMinio/cross-bucket_denial
--- PASS: TestDeliveredContractMinio (0.02s)
    --- PASS: TestDeliveredContractMinio/put (0.00s)
    --- PASS: TestDeliveredContractMinio/get_round-trips_the_body (0.00s)
    --- PASS: TestDeliveredContractMinio/list_shows_the_key (0.00s)
    --- PASS: TestDeliveredContractMinio/head_and_list_agree_on_the_version (0.00s)
    --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload (0.00s)
    --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route (0.01s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed (0.00s)
    --- PASS: TestDeliveredContractMinio/delete_removes_it (0.00s)
    --- PASS: TestDeliveredContractMinio/cross-bucket_denial (0.00s)
PASS
ok  	github.com/carlosframework/platform/internal/objstore	0.025s
=== RUN   TestT4StorageProbeMinio
2026/10/24 17:55:37 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18E188CC4D741EB4, HostID: 7c420053e0fbcd7f41653fdd92ffa2802c903d05303b1aa15adc2e8bb65d183f, api error SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
--- PASS: TestT4StorageProbeMinio (0.01s)
PASS
ok  	github.com/carlosframework/platform/internal/host	0.022s
=== RUN   TestS3StoreMinioContract
=== RUN   TestS3StoreMinioContract/conditional_get_and_etag_listing
=== RUN   TestS3StoreMinioContract/bump_through_every_mutation_path
--- PASS: TestS3StoreMinioContract (0.03s)
    --- PASS: TestS3StoreMinioContract/conditional_get_and_etag_listing (0.01s)
    --- PASS: TestS3StoreMinioContract/bump_through_every_mutation_path (0.02s)
PASS
ok  	github.com/carlosframework/platform/internal/release	0.031s
Bucket created successfully `local/dbf-deploy`.
Bucket created successfully `local/dbf-data-ie`.
Bucket created successfully `local/dbf-data-uk`.
local/dbf-deploy versioning is enabled
Created policy `dbf-console` successfully.
Created policy `dbf-ukbox` successfully.
Added user `dbfconsole` successfully.
Added user `dbfukbox` successfully.
Attached Policies: [dbf-console]
To User: dbfconsole
Attached Policies: [dbf-ukbox]
To User: dbfukbox
=== RUN   TestDBForwardMinio
2026/10/24 17:55:40 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000000 txid.db=0000000000000001
2026/10/24 17:55:40 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000001 maxTXID=0000000000000001 size=720
2026/10/24 17:55:40 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000001
2026/10/24 17:55:40 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000002
2026/10/24 17:55:40 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000002 maxTXID=0000000000000002 size=370
2026/10/24 17:55:40 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000002 txid.db=0000000000000002
2026/10/24 17:55:40 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000002 txid.db=0000000000000003
2026/10/24 17:55:40 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000003 maxTXID=0000000000000003 size=454
2026/10/24 17:55:40 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000003 txid.db=0000000000000003
2026/10/24 17:55:40 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000000 txid.db=0000000000000001
2026/10/24 17:55:40 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000001 maxTXID=0000000000000001 size=720
2026/10/24 17:55:40 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000001
2026/10/24 17:55:40 console: CARLOS_SECRETS_PUBKEY is unset, so no region outside the home can be chosen automatically
2026/10/24 17:55:40 console: could not notify member@example.com of a CLI token issue: keymail: lookup member@example.com: keymail: GET /api/federation/lookup?addr=member%40example.com&from=console%40127.0.0.1%3A44357: could not determine target mailbox
    agent.go:135: dbreads: dbr_2bq6uspzua6qsezmdrm4kgojma: planned 3 files (1544 bytes) and restored to 3 in 10ms
    agent.go:135: dbreads: dbr_2bq6uspzua6qsezmdrm4kgojma: output 5 bytes in 1 confirmed chunks in 1ms
2026/10/24 17:55:41 console: db read dbr_2bq6uspzua6qsezmdrm4kgojma: relayed 1 chunks (102 bytes) in 1.004s, ended done
    agent.go:135: dbreads: dbr_y2mqvkc7ab6lvfbtkoguzhksaq: planned 1 files (720 bytes) and restored to 1 in 8ms
    agent.go:135: dbreads: dbr_y2mqvkc7ab6lvfbtkoguzhksaq: output 5 bytes in 1 confirmed chunks in 1ms
2026/10/24 17:55:42 console: db read dbr_y2mqvkc7ab6lvfbtkoguzhksaq: relayed 1 chunks (102 bytes) in 1.003s, ended done
    agent.go:135: dbreads: dbr_fwjznglbbdtxvhxozuxpck67my: planned 3 files (1544 bytes) and held through 3 in 9ms
    agent.go:135: dbreads: dbr_fwjznglbbdtxvhxozuxpck67my: output 1544 bytes in 1 confirmed chunks in 1ms
2026/10/24 17:55:43 console: db read dbr_fwjznglbbdtxvhxozuxpck67my: relayed 1 chunks (1641 bytes) in 1.004s, ended done
=== RUN   TestDBForwardMinio/by_disconnect
=== NAME  TestDBForwardMinio
    agent.go:135: dbreads: dbr_kmxnwgmv52xdt65wbfy2djhs4q: planned 3 files (1544 bytes) and restored to 3 in 10ms
2026/10/24 17:55:43 console: db read dbr_kmxnwgmv52xdt65wbfy2djhs4q: relayed 0 chunks (0 bytes) in 24ms, ended client gone
    agent.go:135: dbreads: dbr_kmxnwgmv52xdt65wbfy2djhs4q: output 5 bytes in 1 confirmed chunks in 104ms
=== RUN   TestDBForwardMinio/by_timeout
=== NAME  TestDBForwardMinio
    agent.go:135: dbreads: dbr_2a4lfmif5ld563ft4vuuvdsppa: planned 3 files (1544 bytes) and restored to 3 in 10ms
2026/10/24 17:56:03 console: db read dbr_2a4lfmif5ld563ft4vuuvdsppa: relayed 0 chunks (0 bytes) in 19.546s, ended no-result
    agent.go:135: dbreads: dbr_2a4lfmif5ld563ft4vuuvdsppa: output 5 bytes in 1 confirmed chunks in 19.521s
--- PASS: TestDBForwardMinio (22.98s)
    --- PASS: TestDBForwardMinio/by_disconnect (0.23s)
    --- PASS: TestDBForwardMinio/by_timeout (19.66s)
PASS
ok  	github.com/carlosframework/platform/internal/console	22.994s
minio contract: PASS

Intent

Human

Owners only seems reasonable

Human

<task-notification> <task-id>aea14a59caf961bd2</task-id> <tool-use-id>toolu_01JCbxeAi7iHcMKSSbSjCLGq</tool-use-id> <output-file>/home/paulca/.cache/tmp/claude-1001/-home-paulca-amadan-net-carlos-platform/622e3b2d-1bba-40c2-bd40-b65d02622c4c/tasks/aea14a59caf961bd2.output</output-file> <status>completed</status> <summary>Agent "Assemble the copy deck" finished</summary> <note>A task-notification fires each time this agent stops with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.</note> <result>The deck is written at `/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-copy.md`. It's the only file I created; nothing was committed. **Counts** | Plan | Live | Struck | Rows | |---|---|---|---| | 1 | 78 | 1 | 79 | | 2 | 12 | 0 | 12 | | 3 | 27 | 1 | 28 | | 4 | 135 | 0 | 135 | | 5 | 43 | 0 | 43 | | 6 | 64 | 0 | 64 | | Total | 359 | 2 | 361 | **Struck rows.** Neither plan's own table marks these; the index and the later plans do. They carry status `struck`, with the striking plan in the file cell. - RFS-1-C15 is struck by Plan 5 Task 2a and replaced by RFS-5-C43. - RFS-3-C28 is struck by Plan 6 Task 16 and replaced by RFS-6-C62. **Conflicts** - No ID is listed by two plans, and none repeats inside a plan. - RFS-2-C08 differs between table and task step. - Table: `&lt;process&gt; is not a process this release declares`. - Plan 2 Task 5 test: `is not a process the release declares`. - Not a conflict, but noted in the deck: Plan 1 renders `&lt;name&gt;`, `&lt;var&gt;` and `&lt;dir&gt;` with `%q` in C02, C03, C06 and C08. **Referenced but not in a table.** No real string is missing. These IDs appear in the plans but aren't in the deck: - `RFS-0-C01`, `RFS-1-C1`, `RFS-1-C001`, `RFS-7-C01` and `RFS-6-C99` are the id-pattern test examples in Plan 1 Task 1. - `RFS-2-C03a` is the index's note that Plan 2's first-draft id became C12. **Format choices to know about** - I kept the model's four columns (id, file, text, status) so the existing parser still reads it. The plan's context note, such as "(fact)" or Plan 5 C01's prefix note, goes in the file cell in parentheses. - Plan 4's two-column tables have no file column. I took the file from each sub-heading, and kept the sub-headings. - I stripped the backticks where a plan wrapped a whole cell as one code span (plans 4, 5 and 6, and some file cells). Cells with several spans are verbatim: Plan 5 C04, C36 and C41, and Plan 6 C41's `\|`. Every row's text was checked against its plan row. - Rows are in ID order. Plan 2 had C12 out of place, and Plan 5 listed C42, C43, C41. **For the gate.** - The current `parseCopyTable` accepts only `pending` or `approved`, so it will reject the two `struck` rows. Plan 1's struck-row rule needs to learn that status, or those rows need deleting before the gate runs. - Most Plan 2, 3, 5 and 6 file cells aren't bare paths, so `Path()` won't resolve them for the applied-text check.</result> <usage><subagent_tokens>154094</subagent_tokens><tool_uses>30</tool_uses><duration_ms>352757</duration_ms></usage> </task-notification>

Human

<task-notification> <task-id>b38sopgj2</task-id> <tool-use-id>toolu_01CY85AMVnu1ZMdDatRyAmMV</tool-use-id> <output-file>/home/paulca/.cache/tmp/claude-1001/-home-paulca-amadan-net-carlos-platform/622e3b2d-1bba-40c2-bd40-b65d02622c4c/tasks/b38sopgj2.output</output-file> <status>completed</status> <summary>Background command "Wait for Astra findings by process name" completed (exit code 0)</summary> </task-notification>

Attributed to this commit: 20.6 g CO₂e (2503003 tokens). This is an attribution, not a measurement — usage counted from this commit's own marker forward to the next one on design-rootfs-apps, never backward from it. A turn that produced more than one commit books all of its tokens to the last one, and a concurrent session on this branch can add to the same figure. Some of it was priced using the shared default rate, because no model-specific factor row exists yet for at least one model involved. The Carbon view has the repo total, which is never derived from this attribution.

diff --git a/docs/superpowers/plans/2026-10-24-rootfs-apps-0-index.md b/docs/superpowers/plans/2026-10-24-rootfs-apps-0-index.md
index 0902fe0c0..ed44cb0e7 100644
--- a/docs/superpowers/plans/2026-10-24-rootfs-apps-0-index.md
+++ b/docs/superpowers/plans/2026-10-24-rootfs-apps-0-index.md
@@ -216,7 +216,7 @@ code stops and records the problem at the top of its own file under
## Paul's rulings after the spec (2026-10-24; do not reopen)
- **R7. `carlos run` on fleet boxes is carried over Plan 6's box-dials-the-console door.** The box dials the console per run on a signed grant, and the console makes the record and `runs/` writes the store door refuses a fleet box (Plan 6 Task 16, which also removes the fleet arm of `runClassRefusal`). Until it lands, Plan 3 keeps `carlos run` refused on fleet boxes, with today's sentence. Plan 4's sample and dev-fleet checklist never depend on `carlos run` on a fleet box for spec §6 step 1.
-- **R8. Who grants egress.** The account that owns a fleet grants egress for its own apps on its own fleet boxes; on a single-tenant deployment the platform operator grants (Plan 5 F3, Task 8). The box's `OwnBoxAllowed` is unchanged and still decides where a grant may open anything.
+- **R8. Who grants egress.** The account that owns a fleet grants egress for its own apps on its own fleet boxes, and within that account **owners only** (Paul, 2026-10-24; members cannot grant or widen a grant); on a single-tenant deployment the platform operator grants (Plan 5 F3, Task 8). The box's `OwnBoxAllowed` is unchanged and still decides where a grant may open anything.
- **R9. Rootfs instances default to the 1 GB tier** (`cgroup.TierChildren`), not 512 MB. Plan 2 owns the tier selection (`rootfsTier`, `GenTier`); Plan 1's `--check` limits memory to it; Plan 4's docs say 1 GB.
- **R10. The dev e2e box.** A new `t4g.small` (arm64) in the dev account (AWS profile `kass`, eu-west-1), as a fleet box, plus its fleet token and a `carlos store` bucket and IAM user, deleted after the checks. Approved by Paul 2026-10-24 for Plan 2 Task 10 and Plan 4 Task 11, which cite it. Any change in account, region, resource type, cost or duration needs a fresh approval; Plans 5 and 6's dev checks are not covered by it.
@@ -371,7 +371,5 @@ plan's reader finds them here.
(spec §5.7 last bullet) has no owning task. The warning is box-side and
exists for every box today, so nothing should need to change; Plan 4's
self-review now says so. Confirm, or name a plan to check it.
-- **Egress grant authority on a shared deployment** (R8): Plan 5 reads "the
- account" as any person who is a member of the app's account (the
- authority the fleet doors use today), not owners only. Say if it should
- be owners only.
+- ~~Egress grant authority~~ answered: owners only (R8). Plan 5's grant
+ door, CLI, copy and tests change in the review-fix round.
diff --git a/docs/superpowers/plans/2026-10-24-rootfs-apps-copy.md b/docs/superpowers/plans/2026-10-24-rootfs-apps-copy.md
new file mode 100644
index 000000000..c00b54f9e
--- /dev/null
+++ b/docs/superpowers/plans/2026-10-24-rootfs-apps-copy.md
@@ -0,0 +1,502 @@
+# Rootfs apps: copy deck (pending Paul's review)
+
+Every user-facing string of the rootfs apps series (#366), assembled verbatim
+from the string tables of plans 1 to 6 (`2026-10-24-rootfs-apps-[1-6]-*.md`).
+Paul reviews it with the `copy-review` skill before any task writes a string:
+Plan 1 Task 1 stops for that review. The gate is `approved_rootfs_copy_test.go`
+(Plan 1 Task 1), which reads the run deck's format: columns id, file, text,
+status.
+
+The rules:
+
+- A row is `pending` until Paul approves it in the copy review. His edits are
+ applied to the text here verbatim and the row becomes `approved`.
+- A row marked `struck` was superseded by a later plan. It is kept here for
+ history and is not reviewed.
+- The file cell is the plan's "where it appears" cell. A note in parentheses
+ after it is the context note the plan gives (or, on a struck row, the plan
+ that strikes it). Plan 4's tables that have no file column take the file from
+ their sub-heading.
+- Rows are in id order within each plan. The text cell is the plan's text,
+ unedited. Where a plan wrote a whole cell as one code span, the surrounding
+ backticks are dropped. A `\n` in a text is a line break inside one literal.
+- Placeholders are as each plan writes them: `<name>` (Plans 1, 2 and 4) or the
+ Go verb the code formats, `%s`, `%d`, `%q` (Plans 3, 5 and 6). Each plan's own
+ key is quoted above its table.
+- No em dashes.
+
+## Plan 1: ship (`2026-10-24-rootfs-apps-1-ship.md`)
+
+From the plan: Placeholders: `<app>` an app name; `<name>` a process name; `<var>` an environment variable name; `<n>`, `<max>`, `<code>`, `<status>` numbers; `<kind>` `binary` or `static`; `<version>` a release version; `<dir>`, `<path>`, `<target>` paths; `<file>` a file path; `<flag>` a flag name without dashes; `<command>` a command as typed; `<framework>` Rails, Laravel or Django; `<size>`, `<memory>` a size such as `612.4MB`; `<platform>` such as `linux/amd64`; `<platforms>` a comma-separated list; `<type>` file or symlink; `<source>` what the person passed to `--rootfs`; `<image>` an image name; `<runtime>` docker or podman; `<reason>` the underlying error; `<duration>` such as `3.2s`; `<seconds>` a whole number; `<ports>` port numbers, comma-separated; `<arch>` such as `amd64`. A row's `\n` is a line break inside one literal.
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-1-C01 | internal/release/rootfs.go | the processes declare no web process. A rootfs release needs exactly one, named web. | pending |
+| RFS-1-C02 | internal/release/rootfs.go | <name> is not a process name. Use web, release, console, or a worker name: lower-case letters, digits and hyphens, up to 16 characters, starting with a letter. | pending |
+| RFS-1-C03 | internal/release/rootfs.go | <name> is reserved, so no process can use that name. | pending |
+| RFS-1-C04 | internal/release/rootfs.go | a rootfs release can declare at most 4 worker processes, and this one declares <n>. | pending |
+| RFS-1-C05 | internal/release/rootfs.go | the <name> process needs a command: a list of words whose first word is not empty. | pending |
+| RFS-1-C06 | internal/release/rootfs.go | the <name> process sets <var> in env, which is not a variable name. | pending |
+| RFS-1-C07 | internal/release/rootfs.go | the <name> process sets <var> in env. Names that start with CARLOS_ belong to the platform. | pending |
+| RFS-1-C08 | internal/release/rootfs.go | the <name> process's working_dir must be an absolute path, and <dir> is not. | pending |
+| RFS-1-C09 | internal/release/rootfs.go | only the release process takes timeout_sec. | pending |
+| RFS-1-C10 | internal/release/rootfs.go | the release process's timeout_sec must be between 1 and <max> seconds. | pending |
+| RFS-1-C11 | internal/release/rootfs.go | the <name> process contains a NUL byte, which no command or variable can hold. | pending |
+| RFS-1-C12 | internal/release/rootfs.go | the processes are <n> bytes, over the limit of <max>. | pending |
+| RFS-1-C13 | internal/release/rootfs.go | processes and hibernate belong to rootfs releases only. | pending |
+| RFS-1-C14 | internal/release/rootfs.go | a rootfs release carries one artifact, rootfs-linux-arm64, and nothing else. | pending |
+| RFS-1-C15 | internal/release/rootfs.go (struck by Plan 5 Task 2a, replaced by RFS-5-C43) | a rootfs release cannot declare capabilities. | struck |
+| RFS-1-C16 | internal/release/rootfs.go | malformed processes block. Want the processes object: web, any workers, release and console. | pending |
+| RFS-1-C17 | internal/release/rootfs.go | processes: null. A rootfs release needs its processes, starting with web. | pending |
+| RFS-1-C18 | internal/release/rootfs_ship.go | <app> ships <kind> releases (<version> is one), so it cannot take a rootfs release. Ship rootfs releases to an app of their own, made with carlos apps create. | pending |
+| RFS-1-C19 | internal/release/rootfs_ship.go | <app> ships rootfs releases (<version> is one), so it cannot take a <kind> release. Ship that release to another app. | pending |
+| RFS-1-C20 | internal/release/rootfs_ship.go | <app>'s rootfs releases are always on (<version> is one), so this release cannot opt into hibernation. Ship it without --hibernate, or use a new app. | pending |
+| RFS-1-C21 | internal/release/rootfs_ship.go | <app>'s rootfs releases hibernate (<version> is one), so this release must too. Ship it with --hibernate, or use a new app. | pending |
+| RFS-1-C22 | internal/console/apicli.go | invalid kind (want "binary", "static" or "rootfs") | pending |
+| RFS-1-C23 | internal/console/apicli.go (a fragment of the temporary-app refusal) | ship a rootfs release to it | pending |
+| RFS-1-C24 | internal/console/apiship_rootfs.go | <app> is a control-plane app, so its releases are binaries only. | pending |
+| RFS-1-C25 | internal/console/apiship_rootfs.go | the request does not say how large the rootfs image is, so nothing was read. Update carlos and ship again. | pending |
+| RFS-1-C26 | internal/console/apiship_rootfs.go | the rootfs image is over 2 GiB, the most one release can carry. Make the image smaller and ship again. | pending |
+| RFS-1-C27 | internal/console/apiship_rootfs.go | a rootfs release ships exactly one file part, named "rootfs-linux-arm64" | pending |
+| RFS-1-C28 | internal/console/apiship_rootfs.go | the rootfs part does not match the size the request declared, so nothing was shipped. | pending |
+| RFS-1-C29 | internal/console/apiship_rootfs.go | version <version> was already shipped with different processes or hibernation. Versions are immutable, so ship under a new version. | pending |
+| RFS-1-C30 | cli.go | an OCI image (a layout directory, a docker save archive or a local image name) or a directory, shipped as a rootfs release | pending |
+| RFS-1-C31 | cli.go | JSON file holding the rootfs release's processes: web, any workers, release and console | pending |
+| RFS-1-C32 | cli.go | let this rootfs app hibernate when idle. Rootfs apps are always on unless their first release opts in | pending |
+| RFS-1-C33 | cli.go | run the rootfs image here with Docker or Podman, the way a box would, and ship nothing | pending |
+| RFS-1-C34 | ship_rootfs.go | usage: carlos ship --app <a> --rootfs <image-or-dir> --processes <file.json> [--hibernate] [--version <sha>] [--label <one line>] [--notes <text> \| --notes-file <file>] [--swap hold] [--account <sqid-or-name>] [--account-id <sqid>] [--console <origin>]\n carlos ship --rootfs <image-or-dir> --processes <file.json> [--hibernate] --check | pending |
+| RFS-1-C35 | ship_rootfs.go | --rootfs cannot be combined with --<flag>. | pending |
+| RFS-1-C36 | ship_rootfs.go | --rootfs takes the image or directory as its value, so leave the other arguments off. | pending |
+| RFS-1-C37 | ship_rootfs.go | --rootfs needs --processes, a JSON file holding the release's processes. | pending |
+| RFS-1-C38 | ship_rootfs.go | --<flag> works only with --rootfs. | pending |
+| RFS-1-C39 | ship_rootfs.go | --processes <file>: <reason> | pending |
+| RFS-1-C40 | ship_rootfs.go | filled in console: <command>, because this looks like a <framework> app. Declare console in --processes to choose another. | pending |
+| RFS-1-C41 | ship_rootfs.go | left out <n> device files, sockets and pipes: a rootfs image cannot carry them. | pending |
+| RFS-1-C42 | ship_rootfs.go | built the rootfs image: <size>, <n> files. | pending |
+| RFS-1-C43 | ship_rootfs.go | the rootfs image is <size>, over the 2 GiB one release can carry. Make the image smaller and ship again. | pending |
+| RFS-1-C44 | apimode_rootfs.go | this console does not take rootfs releases yet. Update the console, then ship again. | pending |
+| RFS-1-C45 | internal/rootfsimage/errors.go | this image is built for <platform>, and boxes run linux/arm64. Rebuild it for linux/arm64, for example with docker buildx build --platform linux/arm64. | pending |
+| RFS-1-C46 | internal/rootfsimage/errors.go | this image has no linux/arm64 variant (it has <platforms>). Rebuild it for linux/arm64, for example with docker buildx build --platform linux/arm64. | pending |
+| RFS-1-C47 | internal/rootfsimage/errors.go | <path> is a program built for <platform>, and boxes run linux/arm64. Build the directory's programs for linux/arm64. | pending |
+| RFS-1-C48 | internal/rootfsimage/errors.go | the <name> process runs <command>, which the image does not have. Commands are looked up in the process's PATH, or from its working_dir when they contain a slash. | pending |
+| RFS-1-C49 | ship_runtime.go | <source> is not a file, a directory or a local image. | pending |
+| RFS-1-C50 | internal/rootfsimage/errors.go | <source> is not an OCI image, a docker save archive or a directory. | pending |
+| RFS-1-C51 | internal/rootfsimage/errors.go | the image has an entry outside its root (<path>), so it was not shipped. | pending |
+| RFS-1-C52 | internal/rootfsimage/errors.go | the image has <path> as a <type>, and boxes mount a directory there. Remove it from the image. | pending |
+| RFS-1-C53 | internal/rootfsimage/errors.go | the image links <path> to <target>, which is not a file in the image. | pending |
+| RFS-1-C54 | internal/rootfsimage/errors.go | the image sets <var> in its environment. Names that start with CARLOS_ belong to the platform, so remove it from the image. | pending |
+| RFS-1-C55 | internal/rootfsimage/errors.go | the archive holds <n> images. Save one image and ship that. | pending |
+| RFS-1-C56 | internal/rootfsimage/dir_other.go | a directory can be shipped as a rootfs only from Linux or macOS, which keep file modes. Ship an OCI image instead. | pending |
+| RFS-1-C57 | ship_runtime.go | --check runs the image with Docker or Podman, and neither is installed here. | pending |
+| RFS-1-C58 | ship_runtime.go | <source> is not a file or a directory, and there is no Docker or Podman here to export it as an image. | pending |
+| RFS-1-C59 | ship_runtime.go | could not export <image> with <runtime>: <reason> | pending |
+| RFS-1-C60 | ship_check.go | checking the image with <runtime>: read-only root, <memory> of memory, <seconds> s for web to answer. | pending |
+| RFS-1-C61 | ship_check.go | this machine is <arch>, so the arm64 image runs under emulation and starts slower than on a box. | pending |
+| RFS-1-C62 | ship_check.go | the arm64 image cannot run here. Install emulation for arm64 (qemu and binfmt), or run the check on an arm64 machine. | pending |
+| RFS-1-C63 | ship_check.go | release finished in <duration>. | pending |
+| RFS-1-C64 | ship_check.go | release exited with status <code>. Its last lines: | pending |
+| RFS-1-C65 | ship_check.go | release did not finish within <duration>. | pending |
+| RFS-1-C66 | ship_check.go | web answered GET / with <status> after <duration>. | pending |
+| RFS-1-C67 | ship_check.go | web did not answer GET / on CARLOS_SOCKET within <duration>. | pending |
+| RFS-1-C68 | ship_check.go | web listens on port <ports> instead of the socket. Serve HTTP on the unix socket at CARLOS_SOCKET. | pending |
+| RFS-1-C69 | ship_check.go | web answered GET / with <status>. Health needs an answer below 500. | pending |
+| RFS-1-C70 | ship_check.go | <name> exited with status <code>. Its last lines: | pending |
+| RFS-1-C71 | ship_check.go | <name> ran out of memory. A rootfs instance's tier allows <memory>. | pending |
+| RFS-1-C72 | ship_check.go | <name> tried to write outside its instance directory. The root is read-only, so write under <dir> or /tmp. | pending |
+| RFS-1-C73 | ship_check.go | <name> is still running after <duration>. | pending |
+| RFS-1-C74 | ship_check.go | the image passed the local check. A box also applies its egress fence and its own limits, so this is a convenience, not a guarantee. | pending |
+| RFS-1-C75 | ship_check.go | the image failed the local check. | pending |
+| RFS-1-C76 | ship_check_probe.go | --check needs a linux build of carlos to probe the socket from inside the container, and this one is a development build. Use a released carlos, or set CARLOS_CHECK_PROBE to a linux carlos binary. | pending |
+| RFS-1-C77 | ship_check_probe.go | could not fetch the linux build of carlos for the check: <reason> | pending |
+| RFS-1-C78 | internal/rootfsimage/errors.go | the image's layer <digest> does not match its digest, so it was not shipped. | pending |
+| RFS-1-C79 | internal/console/apicli.go | could not check this app's releases. Nothing was shipped. Try again. | pending |
+
+From the plan: RFS-1-C78's `<digest>` is a `sha256:<hex>` digest. Kept out of the table on purpose (diagnostics, not human text): the probe's one-line JSON on stdout, `validateManifest`'s existing terse messages, store errors wrapped for logs.
+
+## Plan 2: box isolation (`2026-10-24-rootfs-apps-2-box-isolation.md`)
+
+From the plan: Human-readable text this plan introduces, for the series copy deck. Diagnostics, log fragments, JSON keys and probe check names are not listed (copy review covers human text only).
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-2-C01 | `RootfsPlacementAllowed`, flat or not nested-ready; the activator's flat-row refusal | rootfs instances need nested isolation, and this box does not have it yet | pending |
+| RFS-2-C02 | `RootfsPlacementAllowed`, probe not passed; the control service's 503 | this box has not passed the rootfs isolation probe on this boot (<check>) | pending |
+| RFS-2-C03 | `RootfsPlacementAllowed`, platform box | rootfs instances run only on a customer's own boxes. This box is shared: it is not a fleet box and the deployment is not single-tenant | pending |
+| RFS-2-C04 | `RootfsPlacementAllowed`, fleet owner unknown or unreadable | this fleet box cannot confirm which account owns its fleet, so it will not start a rootfs instance | pending |
+| RFS-2-C05 | `RootfsPlacementAllowed`, another account | this instance belongs to an account that does not own this fleet | pending |
+| RFS-2-C06 | `RootfsPlacementAllowed`, claim armed | rootfs instances are not started under host lifecycle claim control yet, and this box has it armed | pending |
+| RFS-2-C07 | control service, manifest not rootfs; agent form for a binary staged under a rootfs row | the staged release for this instance is a binary, not a rootfs image | pending |
+| RFS-2-C08 | control service, undeclared process | <process> is not a process this release declares | pending |
+| RFS-2-C09 | activator, health bound | the web process did not answer on its socket within 120 s | pending |
+| RFS-2-C10 | control service, mount setup failed | the image has no <path>, which the instance needs; rebuild it with carlos ship | pending |
+| RFS-2-C11 | `RootfsBoxReady`, overlap swaps not configured | rootfs instances need overlap deploys, and this box does not run them: set CARLOS_SWAP=overlap in its host.env | pending |
+| RFS-2-C12 | `RootfsPlacementAllowed`, platform box serving a pool | rootfs instances run only on a customer's own boxes. A dedicated pool (<pool>) does not make this box one customer's | pending |
+
+## Plan 3: lifecycle (`2026-10-24-rootfs-apps-3-lifecycle.md`)
+
+From the plan: Every row goes to the deck in Task 1 and reaches code only once approved. `%s` and `%d` are the placeholders the code formats.
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-3-C01 | `internal/rolloutwords/words.go` (`reasons["release"]`, read after "because") | its release command failed | pending |
+| RFS-3-C02 | `internal/rolloutwords/words.go` (`reasons["release-timeout"]`) | its release command did not finish in time | pending |
+| RFS-3-C03 | `internal/rolloutwords/words.go` (`EventReleaseStarted`) | running the release command of build %s | pending |
+| RFS-3-C04 | `internal/rolloutwords/words.go` (`EventReleaseDone`) | the release command of build %s finished in %s | pending |
+| RFS-3-C05 | `internal/rolloutwords/words.go` (`EventReleaseFailed`; also `ReleaseError.Error`) | the release command of build %s exited with status %d | pending |
+| RFS-3-C06 | `internal/rolloutwords/words.go` (`EventReleaseSignal`; also `ReleaseError.Error`) | the release command of build %s was ended by signal %s | pending |
+| RFS-3-C07 | `internal/rolloutwords/words.go` (`EventReleaseTimedOut`; also `ReleaseError.Error`) | the release command of build %s did not finish within %s, so it was stopped | pending |
+| RFS-3-C08 | `internal/rolloutwords/words.go` (`EventWorkerStarted`) | worker %s started | pending |
+| RFS-3-C09 | `internal/rolloutwords/words.go` (`EventWorkerExited`) | worker %s exited with status %d. starting it again in %s | pending |
+| RFS-3-C10 | `internal/rolloutwords/words.go` (`EventWorkerCrashLoop`) | worker %s keeps exiting. it is started again once a minute | pending |
+| RFS-3-C11 | `internal/rolloutwords/words.go` (`EventResidentExited`) | instance exited. starting it again in %s | pending |
+| RFS-3-C12 | `internal/rolloutwords/words.go` (`EventRootfsRefused`) | this box cannot run the instance: %s | pending |
+| RFS-3-C13 | `internal/rolloutwords/words.go` (`RootfsRefusedClaims`, fills C12) | host claims are armed here | pending |
+| RFS-3-C14 | `internal/rolloutwords/words.go` (`RootfsRefusedUnarmed`, fills C12) | overlap swaps are not armed here | pending |
+| RFS-3-C15 | `internal/activator/rootfs_service.go` (`errRootfsReplicaMissing`, the member's wake reason) | the instance has served before and its database replica is missing, so it was not started with an empty database | pending |
+| RFS-3-C16 | `internal/activator/activator.go` (`serveWakeError`, the 503 body for `errResidentBackoff`) | instance is restarting; retry shortly | pending |
+| RFS-3-C17 | `run.go` (the `--version` flag's help) | a build of the app to run instead of the one the instance serves | pending |
+| RFS-3-C18 | `run.go` (`runUsageRun`, replacing today's approved line at `:28`) | usage: carlos run --app <app> --instance <host> [--file <path>]... [--timeout 30m] [--version <build>] -- <arg>... | pending |
+| RFS-3-C19 | `internal/console/apiruns.go` (400) | %s is not a build name | pending |
+| RFS-3-C20 | `internal/console/apiruns.go` (409) | %s has no build %s | pending |
+| RFS-3-C21 | `run.go` (`runExit`, refused version) | %s: build %s is not on the instance's box, so the run did not start | pending |
+| RFS-3-C22 | `internal/host/runevents.go` (`runRefusedWords`, version) | the build is not on the box | pending |
+| RFS-3-C23 | `internal/console/seedmove.go` (`refuseRootfsMove`, 409) | %s is a rootfs instance, and a rootfs instance does not move. create a new instance where you want it | pending |
+| RFS-3-C24 | `internal/console/seedmove.go` (`rootfsMoveConflict`, `carlos apps place`) | this app's instances are rootfs instances, which do not move. create new instances where you want them | pending |
+| RFS-3-C25 | `internal/host/systemapply.go` (`systemApplyRootfsRefusal`) | %s cannot run rootfs instances, and this box still has: %s. delete those instances before installing it | pending |
+| RFS-3-C26 | `docs/site/cli.md` (`carlos run`, a paragraph) | --version runs another build of the app against the instance, for example the build a deploy is about to bring in. The build must already be on the instance's box. The command still gets the environment the instance serves with. | pending |
+| RFS-3-C27 | `docs/site/cli.md` (`carlos run`, a paragraph) | For a rootfs app the command after -- runs inside the instance's image and is found on the image's PATH. | pending |
+| RFS-3-C28 | `docs/site/cli.md` (`carlos run`, the same paragraph) (struck by Plan 6 Task 16, replaced by RFS-6-C62) | carlos run does not reach instances on a customer fleet yet. | struck |
+
+From the plan: Count: 28. (RFS-3-C28 is struck from the deck by Plan 6 Task 16 when runs reach fleet boxes, R7.)
+
+## Plan 4: console and docs (`2026-10-24-rootfs-apps-4-console-and-docs.md`)
+
+From the plan: Placeholders: `<app>` an app; `<fleet>` a fleet name; `<region>` a region's name; `<n>`, `<done>`, `<total>`, `<running>` numbers; `<host>` an instance host; `<name>` a worker's name; `<time>` a time; `<note>` a text. "fact" marks a row that depends on Plans 1 to 3 (Global Constraints). Status of every row: pending.
+
+### Console refusals (internal/console/rootfs.go)
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-4-C01 | internal/console/rootfs.go | <app> is a rootfs app, and a rootfs app runs only on boxes your account owns. place it on one of your fleets first with carlos apps place. | pending |
+| RFS-4-C02 | internal/console/rootfs.go | <app> is a rootfs app, and a rootfs app does not run in a dedicated pool yet. create the instance without a pool. | pending |
+| RFS-4-C03 | internal/console/rootfs.go | <app> is a rootfs app, so it cannot move to the shared boxes. a rootfs app runs only on boxes your account owns. | pending |
+| RFS-4-C04 | internal/console/rootfs.go | <app> is a rootfs app with instances, and a rootfs app's instances cannot move to other boxes yet. delete its instances first, or create a new app where you want it to run. | pending |
+| RFS-4-C05 | internal/console/rootfs.go | none of fleet <fleet>'s boxes can run a rootfs app yet. a box can once it runs a platform release with rootfs support, on the nested layout, and has passed its rootfs check. | pending |
+| RFS-4-C06 | internal/console/rootfs.go | no box in <region> can run a rootfs app yet. a box can once it runs a platform release with rootfs support, on the nested layout, and has passed its rootfs check. | pending |
+| RFS-4-C07 | internal/console/rootfs.go | could not check which boxes can run a rootfs app. try again. | pending |
+| RFS-4-C08 | internal/console/rootfs.go | could not read this app's releases. try again. | pending |
+| RFS-4-C09 | internal/console/rootfs.go | <app> is a rootfs app, and a new rootfs instance cannot start from a copy of another database yet. create it empty, then load the data from your app. | pending |
+| RFS-4-C10 | internal/console/rootfs.go | <app> is a rootfs app, and a rootfs app has no replicas yet. | pending |
+| RFS-4-C11 | internal/console/rootfs.go | <app> already has <n> instances made before its first release, such as <host>. an app's first release decides its kind, and those instances were made for a binary app. delete them, ship again, then create them again. | pending |
+
+### CLI (instances_rootfs.go, instances_cli.go)
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-4-C12 | instances_rootfs.go, instances_cli.go | RUNTIME | pending |
+| RFS-4-C13 | instances_rootfs.go, instances_cli.go | WORKERS | pending |
+| RFS-4-C14 | instances_rootfs.go, instances_cli.go | binary | pending |
+| RFS-4-C15 | instances_rootfs.go, instances_cli.go | rootfs | pending |
+| RFS-4-C16 | instances_rootfs.go, instances_cli.go | rootfs, hibernates | pending |
+| RFS-4-C17 | instances_rootfs.go, instances_cli.go | <running>/<total>, <name> restarting | pending |
+| RFS-4-C18 | instances_rootfs.go, instances_cli.go | rootfs, always on. it starts as soon as its box picks it up, and does not wait for a request. | pending |
+| RFS-4-C19 | instances_rootfs.go, instances_cli.go | rootfs, hibernates when idle. | pending |
+
+### The sample app (examples/rails-shop)
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-4-C20 | app/views/pages/show.html.erb | Tables in its database: <tables>. Cable messages: <n>. | pending |
+| RFS-4-C21 | `app/views/layouts/application.html.erb`, `app/views/pages/show.html.erb` | shop | pending |
+| RFS-4-C22 | app/views/pages/show.html.erb | Enqueue a job | pending |
+| RFS-4-C23 | app/views/pages/show.html.erb | Jobs done: <done> of <total> | pending |
+| RFS-4-C24 | app/views/pages/show.html.erb | Heartbeats in the last hour: <n> | pending |
+| RFS-4-C25 | app/views/pages/show.html.erb | Upload a file | pending |
+| RFS-4-C26 | app/views/pages/show.html.erb | This page was cached at <time>. | pending |
+| RFS-4-C27 | v2.patch | Latest note: <note> | pending |
+| RFS-4-C28 | README.md | A small Rails 8 app that runs on CARLOS as a rootfs app. The guide Run a Rails app on your own boxes is built from it. | pending |
+| RFS-4-C29 | README.md | Build it with docker buildx for linux/arm64, check it with carlos ship --check, and ship it with carlos ship --rootfs. The guide has every step. | pending |
+
+### docs/site/rootfs.md
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-4-C30 | docs/site/rootfs.md | Rootfs apps | pending |
+| RFS-4-C31 | docs/site/rootfs.md (fact) | A rootfs app is an app shipped as a read-only Linux image instead of a single binary. You build the image on your own machine, from a Dockerfile or anything else that makes an OCI image or a directory, and carlos ship --rootfs uploads it. The platform never builds anything and never pulls from a registry. | pending |
+| RFS-4-C32 | docs/site/rootfs.md | A rootfs app runs only on boxes your account owns: a fleet of yours on a deployment that runs apps for other people, such as Carloku, or any box of a deployment run for one customer. The box must be on the nested layout and must have passed its rootfs check. The console refuses anywhere else, and so does the box. | pending |
+| RFS-4-C33 | docs/site/rootfs.md | What fixes an app's kind | pending |
+| RFS-4-C34 | docs/site/rootfs.md | An app's first release makes it a binary app or a rootfs app, and it stays that kind. A release of the other kind is refused when you ship it. To change kinds, create a new app. | pending |
+| RFS-4-C35 | docs/site/rootfs.md (fact, D4) | Each instance takes its hibernation setting from the release it is created with, and keeps it. A rootfs app is always on unless that release was shipped with carlos ship --hibernate. A later release that asks for the other setting is refused when you ship it. | pending |
+| RFS-4-C36 | docs/site/rootfs.md | Processes | pending |
+| RFS-4-C37 | docs/site/rootfs.md (fact) | The JSON file you pass to carlos ship --processes names the commands the image runs. Each is an argv array, either an absolute path or a name found on the image's PATH, with an optional env of plain values (never secrets) and an optional working_dir. | pending |
+| RFS-4-C38 | docs/site/rootfs.md | web is required, exactly one. It serves HTTP on CARLOS_SOCKET. | pending |
+| RFS-4-C39 | docs/site/rootfs.md (fact) | release is optional, at most one. It runs on every deploy, the first included, before the new web starts. It may run for ten minutes unless it sets timeout_sec. | pending |
+| RFS-4-C40 | docs/site/rootfs.md | console is optional, at most one. It is the command an interactive session starts. The platform never starts it on its own. | pending |
+| RFS-4-C41 | docs/site/rootfs.md | Any other name is a worker, up to four of them. A name is lowercase letters, digits and hyphens, starts with a letter, and is at most 16 characters long. | pending |
+| RFS-4-C42 | docs/site/rootfs.md | Commands are not run through a shell, so a $CARLOS_SOCKET written in a command is passed as it is. Read the variable in your server's config file instead, or run the command with sh -c if your image has a shell. | pending |
+| RFS-4-C43 | docs/site/rootfs.md | What every process gets | pending |
+| RFS-4-C44 | docs/site/rootfs.md (fact) | Every process of the instance gets the same environment: web, the workers, release and carlos run alike. That is the app's config bundle, the instance's own variables and secrets, its store's coordinates, and these: | pending |
+| RFS-4-C45 | docs/site/rootfs.md | CARLOS_SOCKET is the unix socket web serves HTTP on. | pending |
+| RFS-4-C46 | docs/site/rootfs.md | CARLOS_DB is the instance's SQLite database, the one file the platform replicates. An app that keeps its data somewhere else can ignore it. | pending |
+| RFS-4-C47 | docs/site/rootfs.md (fact) | CARLOS_HOST, CARLOS_REGION, CARLOS_CONTROL_SOCKET and CARLOS_PURGE mean what they mean for a binary instance, as [What an instance is started with](/docs/cli#what-an-instance-is-started-with) says. | pending |
+| RFS-4-C48 | docs/site/rootfs.md | Health | pending |
+| RFS-4-C49 | docs/site/rootfs.md | web must answer GET / on CARLOS_SOCKET with a status below 500 within 120 seconds of starting. Until it does, the instance does not serve and its workers do not start. | pending |
+| RFS-4-C50 | docs/site/rootfs.md | What it can write | pending |
+| RFS-4-C51 | docs/site/rootfs.md | The image is the instance's root filesystem, and it is read-only. An instance writes in two places: the directory CARLOS_DB is in, which is kept across restarts and deploys, and /tmp, which is empty at every start. /tmp is held in memory, so what is in it counts against the instance's memory. | pending |
+| RFS-4-C52 | docs/site/rootfs.md | Memory and CPU | pending |
+| RFS-4-C53 | docs/site/rootfs.md (fact, D10) | All of an instance's processes share one memory and CPU limit, the same tiers a binary instance gets, 1 GB by default. A process that goes over it is stopped and started again. | pending |
+| RFS-4-C54 | docs/site/rootfs.md | No JIT | pending |
+| RFS-4-C55 | docs/site/rootfs.md | Memory is never writable and executable at once, so a JIT compiler cannot start: Ruby's YJIT, PHP's opcache JIT, V8 and the JVM's JIT. Ruby, PHP and Python run well without one. Node and Java apps cannot run as rootfs apps yet. | pending |
+| RFS-4-C56 | docs/site/rootfs.md | Network | pending |
+| RFS-4-C57 | docs/site/rootfs.md | An instance can reach public addresses, such as an object store or a managed database's public endpoint. It cannot reach private addresses, the box it runs on, or the cloud's metadata service. | pending |
+| RFS-4-C58 | docs/site/rootfs.md | Deployments run for one customer | pending |
+| RFS-4-C59 | docs/site/rootfs.md | A deployment whose boxes all belong to one customer says so with CARLOS_DEPLOYMENT_SINGLE_TENANT=1, in the console's environment and in every box's host.env. A rootfs app can then run on any of its boxes, not only on a fleet. Leave it unset on a deployment that runs apps for other people. The console does not start if the value is anything but 0 or 1. | pending |
+| RFS-4-C60 | docs/site/rootfs.md | Dedicated pools do not count as a customer's own boxes yet, because nothing ties a pool to one account. On a deployment that runs apps for other people, a rootfs app cannot run in one. | pending |
+| RFS-4-C61 | docs/site/rootfs.md | Not in this version | pending |
+| RFS-4-C62 | docs/site/rootfs.md | More than one copy of an app across boxes, more than one SQLite database per instance, moving a rootfs instance to another fleet or region, and starting a new rootfs instance from a copy of another database. | pending |
+
+### docs/site/rails.md
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-4-C63 | docs/site/rails.md | Run a Rails app on your own boxes | pending |
+| RFS-4-C64 | docs/site/rails.md | This guide takes a Rails 8 app from a Dockerfile to a running instance on boxes your account owns. The app runs from a read-only image you build on your own machine. Its web process and its job worker share one SQLite database, which the platform replicates, and uploads go to the app's own bucket. | pending |
+| RFS-4-C65 | docs/site/rails.md | You need Docker with buildx, the carlos CLI signed in to your console, and a fleet with at least one box. On a deployment that runs apps for other people, such as Carloku, a rootfs app runs only on a fleet your account owns. [carlos fleets](/docs/cli#carlos-fleets) sets one up, and [Rootfs apps](/docs/rootfs) has the full contract. | pending |
+| RFS-4-C66 | docs/site/rails.md | The finished app is in the platform repository under examples/rails-shop. Every file this guide shows is taken from it. | pending |
+| RFS-4-C67 | docs/site/rails.md | The app | pending |
+| RFS-4-C68 | docs/site/rails.md | Start from rails new with SQLite. Rails 8 gives you Solid Queue, Solid Cache and Solid Cable, each with a database of its own. On CARLOS an instance has one database, so all three share it. | pending |
+| RFS-4-C69 | docs/site/rails.md | Puma | pending |
+| RFS-4-C70 | docs/site/rails.md | The platform gives the web process a unix socket to serve on, in CARLOS_SOCKET. Bind Puma to it and to nothing else. A process that listens on a TCP port instead never answers its health check. | pending |
+| RFS-4-C71 | docs/site/rails.md | puma.rb reads the socket from the environment because commands are not run through a shell. Without CARLOS_SOCKET, on your laptop, it listens on port 3000 as usual. | pending |
+| RFS-4-C72 | docs/site/rails.md | One database | pending |
+| RFS-4-C73 | docs/site/rails.md | CARLOS_DB is the path of the instance's database. It is the one file the platform replicates, and it is kept across restarts and deploys. | pending |
+| RFS-4-C74 | docs/site/rails.md | Point Solid Queue, Solid Cache and Solid Cable at the same database. Remove config.solid_queue.connects_to from config/environments/production.rb, remove database: from the production section of config/cache.yml, and remove connects_to from the production section of config/cable.yml. Each then uses the primary connection. | pending |
+| RFS-4-C75 | docs/site/rails.md | Their tables then need migrations of their own. Copy the table definitions from db/queue_schema.rb, db/cache_schema.rb and db/cable_schema.rb into three migrations, and delete the three schema files. | pending |
+| RFS-4-C76 | docs/site/rails.md | SQLite runs in WAL mode, so the web process and the worker can both write to the file. | pending |
+| RFS-4-C77 | docs/site/rails.md | Uploads | pending |
+| RFS-4-C78 | docs/site/rails.md | Keep uploads out of the image and out of the database. carlos store create gives the app a bucket and puts its coordinates in the app's environment. Point Active Storage at them: | pending |
+| RFS-4-C79 | docs/site/rails.md | Then set config.active_storage.service = :carlos in production.rb, and add the aws-sdk-s3 gem. | pending |
+| RFS-4-C80 | docs/site/rails.md | YJIT | pending |
+| RFS-4-C81 | docs/site/rails.md | Instances run with memory that cannot be written and executed at once, so a JIT cannot start. Rails 7.2 and later turn YJIT on by default. Turn it off in production.rb with config.yjit = false. | pending |
+| RFS-4-C82 | docs/site/rails.md | The image | pending |
+| RFS-4-C83 | docs/site/rails.md | Build the image for arm64, which is what the boxes run. buildx does that on any machine, an Intel laptop included. When the image runs, its root filesystem is read-only, and only /tmp and the directory CARLOS_DB is in can be written. | pending |
+| RFS-4-C84 | docs/site/rails.md | tmp is a link to /tmp, because Rails writes pid and cache files there. | pending |
+| RFS-4-C85 | docs/site/rails.md | Bootsnap's cache is built into the image, and BOOTSNAP_READONLY keeps it from writing at run time. | pending |
+| RFS-4-C86 | docs/site/rails.md | Every file is readable by any user, because an instance does not run as root. | pending |
+| RFS-4-C87 | docs/site/rails.md (fact, D4) | There is no ENTRYPOINT or CMD. The platform runs the commands processes.json names, and nothing else. | pending |
+| RFS-4-C88 | docs/site/rails.md | The processes | pending |
+| RFS-4-C89 | docs/site/rails.md (fact, D4) | processes.json, beside the Dockerfile, names the processes. carlos ship --processes reads it when it makes the release: | pending |
+| RFS-4-C90 | docs/site/rails.md | web serves requests. worker runs beside it, from the same image, with the same environment and the same database. | pending |
+| RFS-4-C91 | docs/site/rails.md | release runs on every deploy, before the new web starts. Here it runs the migrations. | pending |
+| RFS-4-C92 | docs/site/rails.md | console is the command an interactive session starts. The platform never starts it on its own. | pending |
+| RFS-4-C93 | docs/site/rails.md (fact, D4) | A rootfs app is always on. To let an instance sleep when nobody uses it, ship the app's first release with carlos ship --hibernate. An instance keeps the setting it was created with. | pending |
+| RFS-4-C94 | docs/site/rails.md | Check it on your machine | pending |
+| RFS-4-C95 | docs/site/rails.md (fact) | carlos ship --check runs the image the way a box would: a read-only root, a private /tmp, a socket, a database, and the default memory limit. It needs Docker or Podman, and says what went wrong, such as a process that listened on a port, a write outside the instance's directory, or an image built for amd64. | pending |
+| RFS-4-C96 | docs/site/rails.md | Ship it | pending |
+| RFS-4-C97 | docs/site/rails.md | Create the app on your fleet, give it instances, a bucket and a secret key base. Then ship the image, promote it, and create the instance. | pending |
+| RFS-4-C98 | docs/site/rails.md | Ship before you create the instance. An app's first release makes it a rootfs app, and an instance takes that, and whether it hibernates, from the release when it is created. | pending |
+| RFS-4-C99 | docs/site/rails.md | The first start runs release, which migrates the empty database, then starts web, then the worker once web answers. carlos instances list shows the instance's runtime and its workers, and carlos logs shows all three processes. | pending |
+| RFS-4-C100 | docs/site/rails.md (fact, D8) | carlos run runs a one-off command in the instance, from its current image. It does not reach instances on a fleet yet. On a deployment run for one customer it works like this: | pending |
+| RFS-4-C101 | docs/site/rails.md | Deploys and migrations | pending |
+| RFS-4-C102 | docs/site/rails.md | A deploy starts the new web beside the old one and moves traffic once the new one answers. release runs first, from the new image, while the old version is still serving. So a migration has to work with the code that is already running: add a column, deploy, use it, and remove the old one in a later deploy. | pending |
+| RFS-4-C103 | docs/site/rails.md | When a migration cannot work that way, ship that release with --swap hold. The old version stops, release runs, and the new version starts. Requests wait for a few seconds while that happens. | pending |
+| RFS-4-C104 | docs/site/rails.md (fact) | If release fails or runs past its time limit, the old version keeps serving and the deploy stops for that instance. carlos instances list says so, and the next deploy tries again. | pending |
+| RFS-4-C105 | docs/site/rails.md | Rolling back a release does not roll back the database. carlos rollback brings the previous image back, and it runs against the schema the newer release left. This is the other reason a migration should work with the code before it. | pending |
+| RFS-4-C106 | docs/site/rails.md | During a deploy the old worker stops once the new web is healthy, and then the new worker starts. Two workers never run at once. | pending |
+| RFS-4-C107 | docs/site/rails.md | When something crashes | pending |
+| RFS-4-C108 | docs/site/rails.md (fact) | The platform starts the app when its box starts, starts web or a worker again when it crashes, and never waits for a visitor to do it. A worker that keeps crashing is started again with a growing delay, and never takes web down with it. | pending |
+| RFS-4-C109 | docs/site/rails.md | Limits | pending |
+| RFS-4-C110 | docs/site/rails.md | [Rootfs apps](/docs/rootfs) lists the limits. The ones a Rails app meets first: one memory limit for all its processes together, 120 seconds for web to answer after it starts, and at most four workers. | pending |
+
+### docs/site/laravel-and-django.md
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-4-C111 | docs/site/laravel-and-django.md | Laravel and Django | pending |
+| RFS-4-C112 | docs/site/laravel-and-django.md | The Rails guide's shape works for any framework that runs on Linux without a JIT. These notes cover what is different for Laravel and for Django. Read [the Rails guide](/docs/rails) first. | pending |
+| RFS-4-C113 | docs/site/laravel-and-django.md | Laravel | pending |
+| RFS-4-C114 | docs/site/laravel-and-django.md | Serve Laravel with FrankenPHP, which is one HTTP server process. php-fpm speaks FastCGI, not HTTP, so it cannot be web on its own. Bind FrankenPHP to the socket in its Caddyfile: | pending |
+| RFS-4-C115 | docs/site/laravel-and-django.md | Point the sqlite connection at the instance's database in config/database.php, and set DB_CONNECTION=sqlite with carlos env set: | pending |
+| RFS-4-C116 | docs/site/laravel-and-django.md | The processes: web runs FrankenPHP, a worker runs the queue, release runs the migrations, and console runs tinker. With the database queue driver the jobs live in the same database. | pending |
+| RFS-4-C117 | docs/site/laravel-and-django.md | Caddy keeps state in its data and config directories. Point them at /tmp with XDG_DATA_HOME and XDG_CONFIG_HOME in web's env, and turn Caddy's admin endpoint off. | pending |
+| RFS-4-C118 | docs/site/laravel-and-django.md | For uploads, Laravel's s3 disk takes the bucket, region and keys from CARLOS_STORE_BUCKET, CARLOS_STORE_REGION, CARLOS_STORE_ACCESS_KEY and CARLOS_STORE_SECRET_KEY in config/filesystems.php. | pending |
+| RFS-4-C119 | docs/site/laravel-and-django.md | Leave the opcache JIT off, as it is by default. opcache itself is fine. | pending |
+| RFS-4-C120 | docs/site/laravel-and-django.md | Django | pending |
+| RFS-4-C121 | docs/site/laravel-and-django.md | Serve Django with Gunicorn, which binds a unix socket itself. Give it the path in gunicorn.conf.py, since commands are not run through a shell: | pending |
+| RFS-4-C122 | docs/site/laravel-and-django.md | In settings.py, use the sqlite3 engine with NAME set to os.environ["CARLOS_DB"]. | pending |
+| RFS-4-C123 | docs/site/laravel-and-django.md | The processes: web runs gunicorn -c gunicorn.conf.py with your WSGI module, release runs python manage.py migrate --noinput, and console runs python manage.py shell. A worker is whatever your task queue runs. Pick one that keeps its jobs in the database, so it shares the instance's database. | pending |
+| RFS-4-C124 | docs/site/laravel-and-django.md | Collect static files when you build the image, and serve them with WhiteNoise. They only need to be read, so the read-only image is fine. | pending |
+| RFS-4-C125 | docs/site/laravel-and-django.md | For uploads, django-storages' S3 backend takes the bucket, region and keys from CARLOS_STORE_BUCKET, CARLOS_STORE_REGION, CARLOS_STORE_ACCESS_KEY and CARLOS_STORE_SECRET_KEY in settings.py. | pending |
+| RFS-4-C126 | docs/site/laravel-and-django.md | Python's own JIT is off unless you build Python with it. Leave it off. | pending |
+
+### docs/site/cli.md and docs/site/nav.json
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-4-C127 | `cli.md` (carlos instances) | For a rootfs app, RUNTIME says rootfs, or rootfs, hibernates for an instance that sleeps when idle. WORKERS counts the instance's running workers out of the ones it declares, and names a worker that keeps crashing. A binary instance shows binary and a dash. | pending |
+| RFS-4-C128 | `cli.md` (carlos apps) | A rootfs app stays on boxes your account owns. On a deployment that runs apps for other people, --target "" is refused for it, and so is moving it to another fleet while it has instances. [Rootfs apps](/docs/rootfs) says why. | pending |
+| RFS-4-C129 | `nav.json` label | Rootfs apps | pending |
+| RFS-4-C130 | `nav.json` blurb | What a rootfs app's image is started with, what it can write, and where it may run. | pending |
+| RFS-4-C131 | `nav.json` label | Run a Rails app | pending |
+| RFS-4-C132 | `nav.json` blurb | Build a Rails 8 app into an image, ship it, and run it with a worker on your own boxes. | pending |
+| RFS-4-C133 | `nav.json` label | Laravel and Django | pending |
+| RFS-4-C134 | `nav.json` blurb | What changes from the Rails guide for a Laravel or a Django app. | pending |
+| RFS-4-C135 | `nav.json` section | Guides | pending |
+
+From the plan: (The WORKERS count `<running>/<total>` alone is a number, not copy, so it has no row. RFS-4-C20, unused in the first draft, is the sample page's database line.)
+
+## Plan 5: egress allow (`2026-10-24-rootfs-apps-5-egress-allow.md`)
+
+From the plan: Human text only. `%s`/`%q`/`%d` are filled by the code. No em dashes. These go into `2026-10-24-rootfs-apps-copy.md` for review before Task 2 writes any of them.
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-5-C01 | ship and grant refusal (the grant door and CLI drop the `capabilities: egress: ` prefix) | capabilities: egress: %q is not an address range or a hostname. use a range such as 10.0.0.0/16, a single address, or a name such as db.example.com | pending |
+| RFS-5-C02 | ship and grant refusal | capabilities: egress: %q has host bits set. write it as %s | pending |
+| RFS-5-C03 | ship and grant refusal | capabilities: egress: %q includes %s, which is %s. egress never opens it | pending |
+| RFS-5-C04 | class names in C03 and show | `this host` · `loopback` · `link-local addresses, where the cloud metadata service lives` · `the cloud metadata service` · `multicast` · `reserved addresses` · `an address translation range` | pending |
+| RFS-5-C05 | ship and grant refusal | capabilities: egress: %q is wider than /%d. grant the database's own subnet, not a whole network | pending |
+| RFS-5-C06 | ship and grant refusal | capabilities: egress: %d destinations, at most %d | pending |
+| RFS-5-C07 | ship and grant refusal | capabilities: egress: %q is listed twice | pending |
+| RFS-5-C08 | ship refusal | capabilities: egress and doc_engine contradict. doc_engine fences a conversion engine away from private networks, and egress opens them. drop one | pending |
+| RFS-5-C09 | grant door 409 | this app already has %d egress destinations. revoke one before you grant another | pending |
+| RFS-5-C10 | grant and revoke door 502 | could not publish the egress grant. try again | pending |
+| RFS-5-C11 | grant and revoke door 500 | could not save the egress grant. try again | pending |
+| RFS-5-C12 | grant door 400 | name at least one destination to grant | pending |
+| RFS-5-C13 | revoke door 400, CLI | name the destinations to revoke, or use --all | pending |
+| RFS-5-C14 | CLI after grant | granted %s to %s/%s. it applies on the app's own boxes within a minute, to destinations its live build also declares | pending |
+| RFS-5-C15 | CLI after revoke | revoked %s from %s/%s. boxes close it within a minute | pending |
+| RFS-5-C16 | CLI, revoke of nothing granted | %s/%s had none of those destinations. nothing to revoke | pending |
+| RFS-5-C17 | CLI show | granted: %s | pending |
+| RFS-5-C18 | CLI show | nothing granted | pending |
+| RFS-5-C19 | CLI show | applied: %s (%d address ranges on this instance) | pending |
+| RFS-5-C20 | CLI show | not applied: %s | pending |
+| RFS-5-C21 | reason `not-own-box`, `box` | egress applies only on the customer's own boxes, and this box is not one | pending |
+| RFS-5-C22 | reason `not-nested` | the instance is not nested on this box | pending |
+| RFS-5-C23 | reason `manifest-unreadable` | the box could not read the live build's manifest | pending |
+| RFS-5-C24 | reason `not-declared` | the live build does not declare egress | pending |
+| RFS-5-C25 | reason `not-granted` | nothing it declares is granted | pending |
+| RFS-5-C26 | reason `record-unreadable` | the box has not read the grant yet | pending |
+| RFS-5-C27 | reason `record-expired` | the grant on this box has expired. the console renews it, so check that the console is running | pending |
+| RFS-5-C28 | reason `local-addrs` | the box could not list its own addresses, so it opened nothing | pending |
+| RFS-5-C29 | reason `forbidden` | a destination named an address egress never opens | pending |
+| RFS-5-C30 | reason `too-many` | more than %d address ranges after resolution | pending |
+| RFS-5-C31 | reason `malformed` | a destination was not a valid range | pending |
+| RFS-5-C32 | reason `systemctl`, `control-unreachable` | the box's instance control service did not apply it. it retries within seconds | pending |
+| RFS-5-C33 | CLI show, per name | %s did not resolve | pending |
+| RFS-5-C34 | CLI show, stale box | this box has not reported since %s | pending |
+| RFS-5-C35 | CLI show, operator | box %s | pending |
+| RFS-5-C36 | CLI usage | `usage: carlos egress grant --app <a> <destination>...` / ` carlos egress revoke --app <a> (<destination>... \| --all)` / ` carlos egress show --app <a>` / flags `--account`, `--account-id`, `--console` as in door-key usage / `A destination is an address range such as 10.0.0.0/16, a single address, or a hostname such as db.example.com.` / `on a deployment that runs apps for other people, anyone in the app's account can grant and revoke, for an app on one of the account's own fleets. on a deployment run for one customer, only its operators can. anyone in the account can run show.` | pending |
+| RFS-5-C37 | CLI usage | An app reaches a destination only when its live build declares it too, and only on the customer's own boxes: a fleet box, or any box of a single-tenant deployment. | pending |
+| RFS-5-C38 | CLI usage | Egress opens addresses, not ports. a granted address is reachable on every port, so keep the database's own firewall in place. | pending |
+| RFS-5-C39 | CLI usage | Hostnames are looked up every few seconds, and an address stays open for ten minutes after the name stops returning it. for endpoints that return a different address on each lookup, grant the subnet instead. | pending |
+| RFS-5-C40 | README, App capabilities | egress lets a nested instance reach private addresses its build names: a database or cache in the customer's own network. The build declares the destinations, as "egress": ["10.0.0.0/16", "db.example.com"], and the account that owns the fleet grants them to the app with carlos egress grant (on a deployment run for one customer, its operator does). A box opens only what both name, only for nested instances, and only on the customer's own boxes. On a box shared with other customers it opens nothing, because there a private range is the platform's own network. Whatever the list says, egress never opens the cloud metadata service, the box's loopback or the box's own addresses. It opens addresses, not ports: a granted address is reachable on every port, so the database's own firewall stays the port fence. | pending |
+| RFS-5-C41 | docs/site/cli.md, `### carlos egress` | `Lets an app's nested instances reach private destinations, such as a managed database in your own network. Your app's build declares the destinations, and your account grants them to the app for its own fleets (on a deployment run for one customer, the deployment's operator grants them). An instance gets only what both name, and only on your own boxes: a fleet box, or any box of a single-tenant deployment.` / C37, C38, C39 as paragraphs / `show lists what is granted and, for each instance, whether its box applied it and why not.` | pending |
+| RFS-5-C42 | grant and revoke door 409 (shared deployment) | %s/%s does not run on a fleet your account owns, so egress cannot be granted to it. place it on one of your fleets first with carlos apps place | pending |
+| RFS-5-C43 | ship refusal (rootfs release), replaces RFS-1-C15 | a rootfs release can declare only the egress capability | pending |
+
+From the plan: String count: **43 IDs** (C04 carries seven class names; C36 and C41 are multi-line blocks).
+
+## Plan 6: interactive (`2026-10-24-rootfs-apps-6-interactive.md`)
+
+From the plan: Every string is human text the plan introduces. Existing approved strings it reuses are not listed: run's not-an-instance, `runClassRefusal`, `runMovingMsg`, `runImportMsg`, `runTooManyMsg`, `runDirectModeMsg`, the argv refusals, and the activator stop reasons.
+
+| id | file | text | status |
+|---|---|---|---|
+| RFS-6-C01 | `run.go` usage | carlos run --app <app> --instance <host> -it -- <arg>... | pending |
+| RFS-6-C02 | `run.go` flag `-it`, `--interactive` | run the command in a terminal session. what you type goes to it, and its screen comes back | pending |
+| RFS-6-C03 | run.go | -it takes no --file. a session reads from your keyboard instead | pending |
+| RFS-6-C04 | run.go | -it takes no --timeout. a session ends after 30 minutes without a keystroke, and after 6 hours at most | pending |
+| RFS-6-C05 | run.go | -it takes no --follow. a session cannot be picked up again once its connection is gone | pending |
+| RFS-6-C06 | interactive_cli.go | carlos run -it needs a terminal. run it from an interactive shell, or leave out -it to run the command without one | pending |
+| RFS-6-C07 | interactive_term_other.go | terminal sessions do not work on Windows yet. use carlos run without -it, or a macOS or Linux terminal | pending |
+| RFS-6-C08 | `interactive_cli.go` usage | usage: carlos console --app <app> --instance <host> | pending |
+| RFS-6-C09 | flag `--app` | the app whose console to open | pending |
+| RFS-6-C10 | flag `--instance` | the instance to open it on | pending |
+| RFS-6-C11 | interactive_cli.go | carlos console takes no command. it opens the console process the app's manifest declares. to run another command: carlos run -it --app <app> --instance <host> -- <command> | pending |
+| RFS-6-C12 | interactive_cli.go | carlos console works only through a signed-in console, and this shell is in direct bucket mode. unset CARLOS_DEPLOYMENT_BUCKET and CARLOS_DEPLOYMENT_DIR, then run carlos auth login --console <url> | pending |
+| RFS-6-C13 | status | %s: waiting for its box to open the session | pending |
+| RFS-6-C14 | status | %s: starting the session. a sleeping instance wakes first | pending |
+| RFS-6-C15 | status | %s: connected. the session ends when the command exits | pending |
+| RFS-6-C16 | interactive_cli.go | could not open a session connection to %s: %v | pending |
+| RFS-6-C17 | interactive_cli.go | lost the connection to %s. the box closes the session within two minutes | pending |
+| RFS-6-C18 | sessionExit | %s: no box opened the session within 60 seconds. its box may be running an older release, or may not reach the console | pending |
+| RFS-6-C19 | sessionExit | %s: the session ended after 30 minutes without a keystroke | pending |
+| RFS-6-C20 | sessionExit | %s: the session ended at its 6 hour limit | pending |
+| RFS-6-C21 | sessionExit | %s: the session was interrupted: %s | pending |
+| RFS-6-C22 | sessionExit | %s: the connection to its box dropped, so the session was closed | pending |
+| RFS-6-C23 | sessionExit | %s: the session was cancelled before it started | pending |
+| RFS-6-C24 | sessionExit | %s: the box is not on the nested layout yet, so it cannot open a session | pending |
+| RFS-6-C25 | sessionExit | %s: the box has host claims armed. it cannot open a session yet | pending |
+| RFS-6-C26 | sessionExit | %s: the instance did not wake. %s | pending |
+| RFS-6-C27 | console door and `sessionExit` | interactive sessions are off for %s. an owner can turn them on with carlos apps set %s --interactive on | pending |
+| RFS-6-C28 | sessionExit | %s was deleted and created again after this session was requested. the session did not start | pending |
+| RFS-6-C29 | sessionExit | %s is an import that is not committed yet. the session did not start | pending |
+| RFS-6-C30 | sessionExit | %s: its box is still closing the last session. try again in a minute | pending |
+| RFS-6-C31 | sessionExit | carlos run: the box did not open the session: %s | pending |
+| RFS-6-C32 | console door | %s already has an interactive session open, started by %s | pending |
+| RFS-6-C33 | console door | %s runs a release that declares no console process. add a console entry to processes in the app's manifest, or name the command: carlos run -it --app %s --instance %s -- <command> | pending |
+| RFS-6-C34 | console door | interactive sessions need this console to hold the release signing key | pending |
+| RFS-6-C35 | console doors, host-claim | interactive sessions are not available on this console yet. they need the host-claim launch protocol | pending |
+| RFS-6-C36 | console door | the session request is malformed | pending |
+| RFS-6-C37 | console door | could not open the session. try again | pending |
+| RFS-6-C38 | setting door | only an owner of the account can turn interactive sessions on | pending |
+| RFS-6-C39 | setting door | say whether interactive sessions are on or off | pending |
+| RFS-6-C40 | setting door audit detail | turned interactive sessions %s for %s (%s) | pending |
+| RFS-6-C41 | `apps_swap.go` usage | --interactive on\|off whether members may open a terminal session on the app's instances, with carlos run -it or carlos console. It is off until an owner turns it on. A session can read and change everything the instance can. | pending |
+| RFS-6-C42 | flag `--interactive` | on or off: whether members may open terminal sessions on the app's instances | pending |
+| RFS-6-C43 | apps_swap.go | apps set: --interactive is on or off, not %q | pending |
+| RFS-6-C44 | apps_swap.go | %s: interactive sessions are on. any member can open a terminal on its instances with carlos run -it | pending |
+| RFS-6-C45 | apps_swap.go | %s: interactive sessions are off | pending |
+| RFS-6-C46 | apps_swap.go | apps set: the change did not stick (the console stored interactive %s). Run it again | pending |
+| RFS-6-C47 | `apps_swap.go:39`, replaces `appsSetNothing` | apps set: nothing to set. Pass --swap, --swap-concurrency, --interactive or one of the update settings | pending |
+| RFS-6-C48 | carlos logs | interactive session %s opened by %s | pending |
+| RFS-6-C49 | carlos logs | interactive session %s ended with exit %d after %s | pending |
+| RFS-6-C50 | carlos logs | interactive session %s ended after %s: %s | pending |
+| RFS-6-C51 | `carlos logs` reason | 30 minutes passed without a keystroke | pending |
+| RFS-6-C52 | `carlos logs` reason | it reached its 6 hour limit | pending |
+| RFS-6-C53 | `carlos logs` reason | the person's connection closed | pending |
+| RFS-6-C54 | `carlos logs` reason | the box lost its connection to the console | pending |
+| RFS-6-C55 | carlos logs | interactive session %s did not start: %s | pending |
+| RFS-6-C56 | `carlos logs` refusal | interactive sessions are off for this app | pending |
+| RFS-6-C57 | `carlos logs` refusal | the box was still closing the last session | pending |
+| RFS-6-C58 | `cli.md`, `### carlos run` | With -it, the command runs in a terminal session instead: what you type goes to it and its screen comes back, so a REPL or a shell works. The app must allow it first, with carlos apps set <app> --interactive on, which only an owner can do. A session ends when the command exits, after 30 minutes without a keystroke, after 6 hours, or soon after your connection drops. A deploy, a restart or a move of the instance ends it too. Ctrl-C and Ctrl-D go to the command. One session at a time per instance, beside any run. Who opened it, where, when it ended and how are in the audit log. What you type and what it prints are not kept. | pending |
+| RFS-6-C59 | `cli.md`, `### carlos console` | Opens the console process your app's manifest declares, in a terminal session, as carlos run -it would. carlos ship fills one in for Rails, Laravel and Django apps when the manifest has none. An app without one is refused, and the message says how to name a command instead. | pending |
+| RFS-6-C60 | `cli.md`, `carlos apps set` | --interactive on lets any member open a terminal session on the app's instances with carlos run -it or carlos console. A session can read and change everything the instance can, so it is off until an owner turns it on. Any member can turn it off. | pending |
+| RFS-6-C61 | `cli.md`, exit codes | A session exits with the command's own status, 124 when it ended for lack of keystrokes or at 6 hours, 125 when it was interrupted or its box's connection dropped, 130 when you cancelled it before it started, 3 when the box refused it or none opened it within 60 seconds, 2 when the console refused it, and 1 when carlos lost its connection to the console. | pending |
+| RFS-6-C62 | `cli.md`, `### carlos run`, replaces RFS-3-C28 | On a customer fleet, the instance's box reaches the console for the run itself, so carlos run works there as it does on any other box. | pending |
+| RFS-6-C63 | `carlos logs` (box, a run grant that did not verify) | run %s was not started on this box: its grant could not be verified | pending |
+| RFS-6-C64 | `carlos logs` (box, the relay dropped mid-run) | run %s lost its connection to the console, so it was stopped | pending |
+
+## Conflicts
+
+No id is listed by two plans, and no id repeats inside a plan. One row's text
+differs from the plan's own task steps.
+
+- RFS-2-C08
+ - table version: `<process> is not a process this release declares`
+ - task-step version: `is not a process the release declares` (Plan 2 Task 5, the control service test's "undeclared process" case)
+
+Not a conflict, noted for the gate: RFS-1-C02, C03, C06 and C08 render their
+`<name>`, `<var>` and `<dir>` with `%q` (quoted), as Plan 1 Task 2 says; the
+other Plan 1 rows use `%s` or `%d`.
+
+## Referenced but not in a table
+
+Checked in every plan and in the index: each full `RFS-<n>-C<nn>` id, and each bare `C<nn>` in the plan's own task steps. Every one is in the deck except these, none of which is a string:
+
+- `RFS-0-C01`, `RFS-1-C1`, `RFS-1-C001`, `RFS-7-C01`: the bad-id examples in Plan 1 Task 1's id-pattern test (they must be refused).
+- `RFS-6-C99`: the good-id example in the same test.
+- `RFS-2-C03a`: the index's note that Plan 2's first-draft id is now `RFS-2-C12`.
+
+## Counts
+
+Live rows are `pending` (or `approved`); struck rows are kept for history.
+
+- Plan 1: 78 live, 1 struck (RFS-1-C15), 79 rows
+- Plan 2: 12 live, 0 struck, 12 rows
+- Plan 3: 27 live, 1 struck (RFS-3-C28), 28 rows
+- Plan 4: 135 live, 0 struck, 135 rows
+- Plan 5: 43 live, 0 struck, 43 rows
+- Plan 6: 64 live, 0 struck, 64 rows
+- Total: 359 live, 2 struck, 361 rows
diff --git a/docs/superpowers/plans/CODEX-FINDINGS-ROOTFS-PLANS-R1.md b/docs/superpowers/plans/CODEX-FINDINGS-ROOTFS-PLANS-R1.md
new file mode 100644
index 000000000..aac4a9933
--- /dev/null
+++ b/docs/superpowers/plans/CODEX-FINDINGS-ROOTFS-PLANS-R1.md
@@ -0,0 +1,59 @@
+Reviewed commit `9c3d772a41acd10f623b5ab7371ac3dc95742e45`. These are plan and source-code findings; no files were changed or implementation tests run.
+
+1. **P1 — Rootfs commands are polled and stopped as binary commands. Plan 2 Task 5; Plan 3 Tasks 10/12.**
+ `CmdRootfs` starts the new unit, but `cmdUnit.Poll`, `StopAndSettle`, and the cgroup-empty check still select the binary command unit. A running migration appears gone; cancellation targets another unit and cannot prove the migration stopped. Plan 3’s scripted `CmdStatus` responses conceal this. Evidence: [Plan 3:638–643](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-3-lifecycle.md:638), [cmd.go:129](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/instancectl/cmd.go:129), [cmdunit.go:256](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/activator/cmdunit.go:256), [backend_exec.go:1656](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/activator/backend_exec.go:1656).
+ **Smallest fix:** make polling, stopping, and termination proof runtime-aware together. Test through the real control handler with a running rootfs command and no binary command.
+
+2. **P1 — A cold-wake release can continue after losing its lease. Plan 3 Tasks 10–11.**
+ `runRelease` monitors its command and timeout, but receives no lease supervision. During a long migration the entry remains `actWaking`, which the existing lease-loss sweep skips. Renewal failure does not cancel the wake context. The migration can therefore continue after another box acquires the instance, violating C7. Evidence: [Plan 3:628–640](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-3-lifecycle.md:628), [activator.go:4563](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/activator/activator.go:4563), [health.go:51](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/lease/health.go:51).
+ **Smallest fix:** gate release execution on current ownership and supervise the held lease throughout execution, stopping and proving termination before its safety deadline. Add a lease-loss-during-migration test.
+
+3. **P1 — Rootfs apps can reach the box’s public and global interface addresses. Plan 2 Tasks 4/7; Plan 5 Task 4.**
+ The rootfs templates inherit a deny list that does not cover the box’s public IPv4 or global IPv6 addresses. Subtracting those addresses from grants does not deny their existing default access. A tenant can reach a host listener through such an address. Plan 5 explicitly defers this despite §5.9’s requirement. Evidence: [Plan 5:61–66](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-5-egress-allow.md:61), [carlos-instance@.service:142](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/host/units/carlos-instance@.service:142).
+ **Smallest fix:** assign installation and refresh of actual local-address denies before rootfs readiness, retaining subtraction from allows. Probe public IPv4 and global IPv6 listeners with and without a containing grant.
+
+4. **P1 — A failed egress revocation can leave access open indefinitely. Plan 5 Tasks 4/7.**
+ After an allow is installed, let the reset fail once. Task 4 deletes the host from its state; the next empty request then equals “absent,” so it skips the reset although systemd still permits access. Independently, Task 7 sends an unchanged empty desired state only once, so a failed empty push need not be retried. Evidence: [Plan 5:530](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-5-egress-allow.md:530), [Plan 5:739](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-5-egress-allow.md:739).
+ **Smallest fix:** retain the last applied state or a pending-reset marker until reset succeeds, and retry failed pushes including empty states. Test an installed allow followed by a failed revoke and an identical retry.
+
+5. **P2 — Starting an overlap generation lowers the shared memory limit prematurely. Plan 2 Task 5.**
+ The specified start path preserves populated slice limits only for workers; run starts set the tier. A generation is a run start, so its launch overwrites the scheduler’s combined incumbent-plus-successor limit with 1 GiB. Two individually valid 700 MiB generations can then cause an OOM during overlap. Evidence: [Plan 2:967](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-2-box-isolation.md:967), [swap.go:517](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/activator/swap.go:517), [gen.go:161](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/instancectl/gen.go:161).
+ **Smallest fix:** preserve populated parent limits for generation starts, following the existing binary generation path. Assert that successor startup does not reset the parent tier.
+
+6. **P2 — The parser rejects the specified rootfs stop/reset requests. Plan 2 Task 5.**
+ `/stop` and `/reset` carry `runtime=rootfs` without an image. The shared parser nevertheless requires `runtime=rootfs` if and only if `image` is present. Following both instructions makes termination requests return 400. Evidence: [Plan 2:959](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-2-box-isolation.md:959), [Plan 2:1281](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-2-box-isolation.md:1281).
+ **Smallest fix:** apply the image/runtime equivalence only to launch verbs. Test each termination client against the actual parser.
+
+7. **P2 — Explicit commands lose the image’s working directory and command-search defaults. Plan 2 Tasks 5/6, consumed by Plans 3/6.**
+ The explicit-argv branch selects no declared process, yet takes `Env` and `WorkingDir` from that process. For an image with `WORKDIR=/rails`, the documented `bin/rails` command consequently resolves as `/bin/rails`; image-specific executable search paths are also lost. Evidence: [Plan 2:973](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-2-box-isolation.md:973), [Plan 2:1324](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-2-box-isolation.md:1324).
+ **Smallest fix:** define explicit commands to inherit environment and working directory from the selected image’s web process while retaining their requested argv. Test relative commands and a custom image `PATH`.
+
+8. **P2 — Apps that ignore `CARLOS_DB` cannot reliably restart. Plan 3 Tasks 4/7.**
+ The spec permits a MySQL-only app and promises a placeholder SQLite database. No task creates it. After that app serves successfully, its next wake finds neither local database nor replica, reports `fresh`, and hits the new `GoodVersion != ""` refusal. Evidence: [Plan 3:415](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-3-lifecycle.md:415), [backend_exec.go:795](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/activator/backend_exec.go:795), [backend_exec.go:876](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/activator/backend_exec.go:876).
+ **Smallest fix:** initialize the placeholder database under the first-wake lease without weakening the served-but-missing-data refusal. Test restart of a healthy app that never opens `CARLOS_DB`.
+
+9. **P2 — Concurrent first ships violate the fixed-kind contract. Plan 1 Tasks 3/8.**
+ Binary and rootfs uploads can both observe no release and pass `CheckShipKind`. Both then publish, and the newest manifest determines `AppKind`, potentially contradicting an instance already minted from the other release. Artifact skipping prevents execution under the wrong template but leaves the app unable to adopt otherwise accepted releases. The plan explicitly accepts this race; it is not an R1–R10 ruling. Evidence: [Plan 1:1305](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-1-ship.md:1305), [server.go:1392](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/console/server.go:1392).
+ **Smallest fix:** make first-kind establishment atomic across ship paths and revalidate at publication. Add a concurrent mixed-kind first-ship test.
+
+10. **P2 — Concurrent interactive admissions can both succeed. Plan 6 Task 10.**
+ A marker counts as live only after its session enters the hub, but admission writes the marker before registering the session. Client B can replace client A’s newly written marker during that gap; both subsequently register and report success. Evidence: [Plan 6:740](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-6-interactive.md:740), [Plan 6:768–769](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-6-interactive.md:768).
+ **Smallest fix:** reserve the session in the hub before admission, cleaning it up on failure, or serialize admission and registration per instance. Pause a test between record publication and registration.
+
+11. **P2 — Fleet-run output chunks exceed the relay frame limit. Plan 6 Task 16.**
+ Task 16 sends one existing output chunk plus a 12-byte header through `Send`. Its payload limit is 65,535 bytes, while the existing chunker produces 262,144-byte chunks. A sufficiently verbose fleet run therefore cannot relay its output. Evidence: [Plan 6:199](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-6-interactive.md:199), [Plan 6:1197](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-6-interactive.md:1197), [runs.go:35](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/runs/runs.go:35).
+ **Smallest fix:** define a bounded run-specific frame size or fragmentation/reassembly. Test a full-sized output chunk.
+
+12. **P2 — Fleet-run pickup consumes a boot identity that the protocol never supplies. Plan 6 Task 16.**
+ The relay refers to identity “from the hello,” but defines no hello or agent boot-ID field. Existing `RunPick` requires that boot ID, and the worker refuses execution unless it matches `w.boot`; record incarnation is a different value. Evidence: [Plan 6:1197–1217](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-6-interactive.md:1197), [run.go:133](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/provision/run.go:133), [runexec.go:327](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/host/runexec.go:327).
+ **Smallest fix:** specify the boot-ID exchange separately from incarnation and acknowledge successful pickup CAS before execution proceeds.
+
+13. **P2 — Failed fleet-owner publication has no working create retry. Plan 4 Task 5a.**
+ Publication failure leaves the fleet row inserted and returns 500. Retrying creation reaches the existing “name is taken” return, so it cannot repair the missing owner record. Rootfs launches remain refused until a console restart successfully backfills it. Evidence: [Plan 4:575](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-4-console-and-docs.md:575), [fleets.go:217](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/console/fleets.go:217).
+ **Smallest fix:** repair publication on an authenticated same-owner retry, or assign persistent retry reconciliation. Test one failed write followed by recovery without restarting the console.
+
+14. **P2 — The slice assertion cannot pass against the required generation templates. Plan 5 Task 4.**
+ The proposed test requires every instance template to contain `Slice=carlos-instances-%i.slice`. Generation templates deliberately omit that line because `%i` contains the generation suffix; the correct host slice comes from a runtime drop-in. Rootfs generation and worker templates follow that arrangement. Evidence: [Plan 5:513–515](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-5-egress-allow.md:513), [gen.go:37–47](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/internal/instancectl/gen.go:37), [Plan 2:670](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-rootfs-apps/docs/superpowers/plans/2026-10-24-rootfs-apps-2-box-isolation.md:670).
+ **Smallest fix:** check literal slice assignments for ordinary templates and generated drop-ins for composite instance names, including the effective slice check before startup.
+
+**Verdict: reject.**
\ No newline at end of file