carlos / platform Public

Sidecar isolation spec: Astra round 1 findings (unedited)

Four P1s (worker start/stop ordering, rollback/recovery for D11, lease
replication for always-on workers in D9, D8's no-local-data test) and five
P2s. Revision 2 should mark each accepted finding and list declined ones.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 2a2517d6e05fe38a895605001a5cd0b9b3f5431a parent 1c029ee
1 file changed, +87 −0
  • docs/superpowers/specs/CODEX-FINDINGS-SIDECAR-ISOLATION.md +87 −0

CI passed — run details

CI log
=== gate ===
.amadan/test-gate.sh
=== launchctx (1 s)
ok  	amadan.net/carlos/platform.git/launchctx	0.015s
?   	amadan.net/carlos/platform.git/launchctx/controlname	[no test files]
?   	amadan.net/carlos/platform.git/launchctx/wireid	[no test files]
=== vet (18 s)
=== gofmt (0 s)
gofmt -l .: clean
=== rest (172 s)
?   	github.com/carlosframework/platform/cmd/changelog	[no test files]
ok  	github.com/carlosframework/platform/cmd/console	3.370s
ok  	github.com/carlosframework/platform/cmd/moveprobe	11.766s
ok  	github.com/carlosframework/platform/cmd/zddprobe	0.737s
ok  	github.com/carlosframework/platform/internal/activator	58.812s
ok  	github.com/carlosframework/platform/internal/agentsock	0.031s
ok  	github.com/carlosframework/platform/internal/alerting	0.008s
ok  	github.com/carlosframework/platform/internal/analytics	0.037s
ok  	github.com/carlosframework/platform/internal/appconfig	2.859s
ok  	github.com/carlosframework/platform/internal/apperr	0.158s
ok  	github.com/carlosframework/platform/internal/applog	0.279s
ok  	github.com/carlosframework/platform/internal/awsinv	0.007s
ok  	github.com/carlosframework/platform/internal/boxchoice	0.007s
ok  	github.com/carlosframework/platform/internal/boxid	1.045s
?   	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.014s
ok  	github.com/carlosframework/platform/internal/caps	0.050s
ok  	github.com/carlosframework/platform/internal/certwarm	0.004s
ok  	github.com/carlosframework/platform/internal/cgroup	0.788s
ok  	github.com/carlosframework/platform/internal/changelog	0.446s
ok  	github.com/carlosframework/platform/internal/claimactivation	1.098s
ok  	github.com/carlosframework/platform/internal/clamd	0.072s
?   	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.743s
ok  	github.com/carlosframework/platform/internal/dbdoor/dbdoortest	0.038s
ok  	github.com/carlosframework/platform/internal/dbquery	0.023s
ok  	github.com/carlosframework/platform/internal/dbreads	2.244s
?   	github.com/carlosframework/platform/internal/dbreads/dbreadstest	[no test files]
ok  	github.com/carlosframework/platform/internal/dbverify	0.010s
ok  	github.com/carlosframework/platform/internal/dnsrec	0.007s
ok  	github.com/carlosframework/platform/internal/docsite	0.024s
ok  	github.com/carlosframework/platform/internal/domains	2.867s
ok  	github.com/carlosframework/platform/internal/doorkey	0.009s
ok  	github.com/carlosframework/platform/internal/economics	0.005s
ok  	github.com/carlosframework/platform/internal/edge	45.769s
?   	github.com/carlosframework/platform/internal/edgeproof	[no test files]
ok  	github.com/carlosframework/platform/internal/edgesfile	0.008s
ok  	github.com/carlosframework/platform/internal/fleetapi	0.196s
ok  	github.com/carlosframework/platform/internal/gate	1.706s
ok  	github.com/carlosframework/platform/internal/genselect	0.016s
ok  	github.com/carlosframework/platform/internal/geo	0.011s
ok  	github.com/carlosframework/platform/internal/geoip	0.041s
ok  	github.com/carlosframework/platform/internal/historyreadback	0.260s
ok  	github.com/carlosframework/platform/internal/host	143.383s
ok  	github.com/carlosframework/platform/internal/hostactors	5.759s
ok  	github.com/carlosframework/platform/internal/hostactors/awsmembership	0.013s
ok  	github.com/carlosframework/platform/internal/hostbox	3.017s
ok  	github.com/carlosframework/platform/internal/hostclaim	0.746s
ok  	github.com/carlosframework/platform/internal/hostenv	0.013s
ok  	github.com/carlosframework/platform/internal/hostevidence	0.013s
ok  	github.com/carlosframework/platform/internal/hostexec	5.192s
ok  	github.com/carlosframework/platform/internal/hostfence	0.053s
ok  	github.com/carlosframework/platform/internal/hostfiles	10.348s
ok  	github.com/carlosframework/platform/internal/hostfloor	0.029s
ok  	github.com/carlosframework/platform/internal/hostguard	1.042s
ok  	github.com/carlosframework/platform/internal/hostops	1.924s
?   	github.com/carlosframework/platform/internal/hostops/fencerelease	[no test files]
ok  	github.com/carlosframework/platform/internal/hostops/internal/fencerelease	0.014s
ok  	github.com/carlosframework/platform/internal/hostquarantine	0.014s
ok  	github.com/carlosframework/platform/internal/hostrelocate	0.583s
ok  	github.com/carlosframework/platform/internal/hostresolve	0.218s
ok  	github.com/carlosframework/platform/internal/hostwrite	0.013s
ok  	github.com/carlosframework/platform/internal/infraview	0.016s
ok  	github.com/carlosframework/platform/internal/instancectl	5.234s
ok  	github.com/carlosframework/platform/internal/instanceexec	2.813s
ok  	github.com/carlosframework/platform/internal/instancefs	0.021s
ok  	github.com/carlosframework/platform/internal/instancekey	0.018s
ok  	github.com/carlosframework/platform/internal/instanceupdates	0.021s
ok  	github.com/carlosframework/platform/internal/layout	1.670s
ok  	github.com/carlosframework/platform/internal/lbhealth	0.018s
ok  	github.com/carlosframework/platform/internal/lease	10.287s
ok  	github.com/carlosframework/platform/internal/lease/leasetest	0.550s
ok  	github.com/carlosframework/platform/internal/ledger	0.017s
ok  	github.com/carlosframework/platform/internal/mail	0.261s
ok  	github.com/carlosframework/platform/internal/maintenance	0.086s
ok  	github.com/carlosframework/platform/internal/maintenanceexec	5.580s
ok  	github.com/carlosframework/platform/internal/maintenanceguard	0.102s
ok  	github.com/carlosframework/platform/internal/metrics	0.009s
ok  	github.com/carlosframework/platform/internal/moves	22.293s
ok  	github.com/carlosframework/platform/internal/moves/archive	0.882s
ok  	github.com/carlosframework/platform/internal/objstore	0.267s
ok  	github.com/carlosframework/platform/internal/ops	0.194s
ok  	github.com/carlosframework/platform/internal/park	0.277s
ok  	github.com/carlosframework/platform/internal/plans	0.005s
ok  	github.com/carlosframework/platform/internal/privatefile	0.004s
ok  	github.com/carlosframework/platform/internal/provision	23.412s
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.573s
ok  	github.com/carlosframework/platform/internal/relay	7.246s
ok  	github.com/carlosframework/platform/internal/release	25.941s
ok  	github.com/carlosframework/platform/internal/rollout	3.764s
ok  	github.com/carlosframework/platform/internal/rolloutwords	0.003s
ok  	github.com/carlosframework/platform/internal/rootaws	0.007s
ok  	github.com/carlosframework/platform/internal/rootparticipation	0.063s
ok  	github.com/carlosframework/platform/internal/rootstate	0.032s
ok  	github.com/carlosframework/platform/internal/runs	0.602s
ok  	github.com/carlosframework/platform/internal/s3compat	0.005s
ok  	github.com/carlosframework/platform/internal/safefile	0.005s
ok  	github.com/carlosframework/platform/internal/schedule	2.684s
ok  	github.com/carlosframework/platform/internal/seeds	0.016s
ok  	github.com/carlosframework/platform/internal/sim/engines	2.564s
ok  	github.com/carlosframework/platform/internal/sim/hostlife	10.368s
ok  	github.com/carlosframework/platform/internal/sim/litestreamfacts	3.703s
ok  	github.com/carlosframework/platform/internal/status	0.085s
ok  	github.com/carlosframework/platform/internal/steering	0.006s
ok  	github.com/carlosframework/platform/internal/stopevidence	0.316s
ok  	github.com/carlosframework/platform/internal/svcrole	0.006s
ok  	github.com/carlosframework/platform/internal/telemetry	0.006s
ok  	github.com/carlosframework/platform/internal/termfence	0.005s
ok  	github.com/carlosframework/platform/internal/tunnelclient	0.007s
ok  	github.com/carlosframework/platform/internal/unixdial	0.005s
ok  	github.com/carlosframework/platform/internal/updatewords	0.005s
ok  	github.com/carlosframework/platform/internal/usage	0.006s
ok  	github.com/carlosframework/platform/internal/version	0.002s
ok  	github.com/carlosframework/platform/internal/vet	1.663s
=== internal_console@0 (80 s)
ok  	github.com/carlosframework/platform/internal/console	78.450s
=== internal_console@1 (43 s)
ok  	github.com/carlosframework/platform/internal/console	41.570s
=== internal_console@2 (41 s)
ok  	github.com/carlosframework/platform/internal/console	40.148s
=== internal_console@3 (41 s)
ok  	github.com/carlosframework/platform/internal/console	39.454s
=== internal_console@4 (41 s)
ok  	github.com/carlosframework/platform/internal/console	39.892s
=== internal_console@5 (41 s)
ok  	github.com/carlosframework/platform/internal/console	39.485s
=== internal_console@6 (37 s)
ok  	github.com/carlosframework/platform/internal/console	35.851s
=== internal_console@7 (46 s)
ok  	github.com/carlosframework/platform/internal/console	44.403s
=== root@0 (109 s)
ok  	github.com/carlosframework/platform	107.475s
=== root@1 (84 s)
ok  	github.com/carlosframework/platform	82.848s
=== root@2 (92 s)
ok  	github.com/carlosframework/platform	90.383s
=== 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.021s
=== RUN   TestT4StorageProbeMinio
2026/10/24 19:15:22 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18E18D2667B185B6, 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.00s)
PASS
ok  	github.com/carlosframework/platform/internal/host	0.020s
=== RUN   TestS3StoreMinioContract
=== RUN   TestS3StoreMinioContract/conditional_get_and_etag_listing
=== RUN   TestS3StoreMinioContract/bump_through_every_mutation_path
--- PASS: TestS3StoreMinioContract (0.02s)
    --- PASS: TestS3StoreMinioContract/conditional_get_and_etag_listing (0.01s)
    --- PASS: TestS3StoreMinioContract/bump_through_every_mutation_path (0.01s)
PASS
ok  	github.com/carlosframework/platform/internal/release	0.029s
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 19:15:24 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000000 txid.db=0000000000000001
2026/10/24 19:15:24 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000001 maxTXID=0000000000000001 size=720
2026/10/24 19:15:24 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000001
2026/10/24 19:15:24 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000002
2026/10/24 19:15:24 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000002 maxTXID=0000000000000002 size=370
2026/10/24 19:15:24 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000002 txid.db=0000000000000002
2026/10/24 19:15:24 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000002 txid.db=0000000000000003
2026/10/24 19:15:24 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000003 maxTXID=0000000000000003 size=454
2026/10/24 19:15:24 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000003 txid.db=0000000000000003
2026/10/24 19:15:24 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000000 txid.db=0000000000000001
2026/10/24 19:15:24 INFO ltx file uploaded system=store db=source.db replica=file level=0 minTXID=0000000000000001 maxTXID=0000000000000001 size=720
2026/10/24 19:15:24 INFO replica sync system=store db=source.db replica=file txid.replica=0000000000000001 txid.db=0000000000000001
2026/10/24 19:15:25 console: CARLOS_SECRETS_PUBKEY is unset, so no region outside the home can be chosen automatically
2026/10/24 19:15:25 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%3A35971: could not determine target mailbox
    agent.go:135: dbreads: dbr_zbe5xqqplhtafyq6thfqj5m6la: planned 3 files (1544 bytes) and restored to 3 in 9ms
    agent.go:135: dbreads: dbr_zbe5xqqplhtafyq6thfqj5m6la: output 5 bytes in 1 confirmed chunks in 1ms
2026/10/24 19:15:26 console: db read dbr_zbe5xqqplhtafyq6thfqj5m6la: relayed 1 chunks (102 bytes) in 1.003s, ended done
    agent.go:135: dbreads: dbr_qlwq2ylxg5jdkn332y3pqcz77m: planned 1 files (720 bytes) and restored to 1 in 7ms
    agent.go:135: dbreads: dbr_qlwq2ylxg5jdkn332y3pqcz77m: output 5 bytes in 1 confirmed chunks in 1ms
2026/10/24 19:15:27 console: db read dbr_qlwq2ylxg5jdkn332y3pqcz77m: relayed 1 chunks (102 bytes) in 1.003s, ended done
    agent.go:135: dbreads: dbr_yqxire4nk2af336ozgmds2h6e4: planned 3 files (1544 bytes) and held through 3 in 8ms
    agent.go:135: dbreads: dbr_yqxire4nk2af336ozgmds2h6e4: output 1544 bytes in 1 confirmed chunks in 1ms
2026/10/24 19:15:28 console: db read dbr_yqxire4nk2af336ozgmds2h6e4: relayed 1 chunks (1641 bytes) in 1.003s, ended done
=== RUN   TestDBForwardMinio/by_disconnect
=== NAME  TestDBForwardMinio
    agent.go:135: dbreads: dbr_eg2rkcfuskltcxfrakeflv6tsm: planned 3 files (1544 bytes) and restored to 3 in 8ms
2026/10/24 19:15:28 console: db read dbr_eg2rkcfuskltcxfrakeflv6tsm: relayed 0 chunks (0 bytes) in 15ms, ended client gone
    agent.go:135: dbreads: dbr_eg2rkcfuskltcxfrakeflv6tsm: output 5 bytes in 1 confirmed chunks in 32ms
=== RUN   TestDBForwardMinio/by_timeout
=== NAME  TestDBForwardMinio
    agent.go:135: dbreads: dbr_ozon5bzt2cxshazq3b4kfcr47i: planned 3 files (1544 bytes) and restored to 3 in 9ms
2026/10/24 19:15:48 console: db read dbr_ozon5bzt2cxshazq3b4kfcr47i: relayed 0 chunks (0 bytes) in 19.792s, ended no-result
    agent.go:135: dbreads: dbr_ozon5bzt2cxshazq3b4kfcr47i: output 5 bytes in 1 confirmed chunks in 19.781s
--- PASS: TestDBForwardMinio (23.15s)
    --- PASS: TestDBForwardMinio/by_disconnect (0.15s)
    --- PASS: TestDBForwardMinio/by_timeout (19.90s)
PASS
ok  	github.com/carlosframework/platform/internal/console	23.164s
minio contract: PASS
diff --git a/docs/superpowers/specs/CODEX-FINDINGS-SIDECAR-ISOLATION.md b/docs/superpowers/specs/CODEX-FINDINGS-SIDECAR-ISOLATION.md
new file mode 100644
index 000000000..6c5939805
--- /dev/null
+++ b/docs/superpowers/specs/CODEX-FINDINGS-SIDECAR-ISOLATION.md
@@ -0,0 +1,87 @@
+Reviewed commit `1c029ee5dab20b3083d4ab5ebba3e1975d6a5ff4` and checked every existing-code citation against the worktree. The code matches the brief’s `fef28dc5` baseline. I found nine substantive issues.
+
+1. **P1 — D1/D5 omit the start/stop ordering needed to prevent two workers holding the same workload.**
+
+ A nested worker’s start request times out while its root handler remains pending. Cleanup observes an empty slice and releases the lease. Another box acquires it; the delayed handler then starts the first worker.
+
+ This is precisely the race documented in [legacystart.go:11](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/instancectl/legacystart.go:11). The root start fence currently applies only to `RoleRun` ([server.go:472](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/instancectl/server.go:472)). Failed wakes release the lease unless the error carries the appropriate uncertainty marker ([activator.go:2543](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/activator/activator.go:2543)); the existing proof also hard-codes `RoleRun` ([backend_exec.go:2606](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/activator/backend_exec.go:2606)).
+
+ **Fix:** explicitly extend ordered start cancellation, joining, and uncertain-start cleanup to workers. Retain the lease until the worker-specific stop proves both that no earlier request can start later and that the unit is empty. Changing `KillHost` to inspect the slice alone is insufficient.
+
+2. **P1 — D11 protects installation, but not rollback or recovery.**
+
+ An upgrade starts the new agent, which migrates workers, and subsequently fails its health gate. The updater restores the previous binary and units. That binary starts nested worker rows through the old flat worker implementation.
+
+ The new edge starts before the health gate ([systemapply.go:600](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/host/systemapply.go:600)). Rollback restores through a separate path, `restoreFiles`, without the proposed worker-layout check ([systemapply.go:1784](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/host/systemapply.go:1784)). More seriously, the recovery unit can execute **the previous binary itself**, so adding a check only to the new binary cannot protect that path ([carlos-system-recover.service:41](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/host/units/carlos-system-recover.service:41)).
+
+ The proposed row-only predicate also misses a migration interrupted before its row CAS. The existing layout guard deliberately includes journals, fenced rows and conflicts ([systemapply.go:1273](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/host/systemapply.go:1273)).
+
+ **Fix:** establish a worker compatibility floor before migration is enabled, enforce it on every binary activation and recovery selection, and include incomplete migrations. Add the recovery unit to §8.3’s root-file census.
+
+3. **P1 — D9 treats always-on workers as exclusively box-wide replicated, but they already use lease replication.**
+
+ Wake an always-on worker: its activator acquires the lease and starts replication. Generate the box-wide configuration: because `Hibernate` is false, that configuration includes the same database. D9 preserves this overlapping ownership and adds another path-keyed lineage during migration.
+
+ Lease replication is unconditional after worker startup ([activator.go:2602](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/activator/activator.go:2602)). Always-on supervision explicitly retains that lease and replication ([activator.go:4599](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/activator/activator.go:4599)). The box-wide exclusion tests only `Hibernate` ([litestream.go:356](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/ops/litestream.go:356)); the same file warns that simultaneous replicators can fight over checkpointing and corrupt replicas ([litestream.go:230](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/ops/litestream.go:230)).
+
+ This is an existing defect that the proposed design would preserve, not a defect first introduced by the proposal.
+
+ **Fix:** assign one replication owner. Keeping native workers under lease replication appears consistent with their current lifecycle: exclude them from the box-wide generator and extend the lease restore-verification census, which also currently selects only hibernating rows ([hibernate_verify.go:45](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/ops/hibernate_verify.go:45)).
+
+4. **P1 — D8’s “nine artifacts absent” condition does not establish that a box has no local data.**
+
+ During the flat transition, a tenant can rename a stopped worker’s database and other fixed artifacts. The proposed exception then permits a row-only migration and restores an older bucket copy, while the newer local database remains under another name.
+
+ Even without malicious activity, the nine fixed artifacts are not the complete data inventory. Existing migration code scans and journals application-created extras specifically because moving only those nine previously lost application state ([extras.go:14](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/layout/extras.go:14), [pass.go:810](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/layout/pass.go:810)). Today, missing the required database stops this operation.
+
+ **Fix:** retain the complete extras inventory and distinguish a never-materialized row from missing local data using evidence a flat tenant cannot manufacture. Otherwise require an explicit recovery decision; filesystem absence alone must not authorize restoring over uncertain local history.
+
+5. **P2 — D8 still strands ordinary standby boxes that have config but no database.**
+
+ Box A runs a sidecar. Box B receives its row and config bundle but has never acquired its lease. B therefore has `<host>.config.env`, but no database. It fails both migration cases: the required database is missing, and the nine artifacts are not all absent. After `refuse` is enabled, failover to B remains blocked.
+
+ Config delivery explicitly includes sidecars regardless of whether they have run ([syncexec.go:879](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/appconfig/syncexec.go:879)), and writes the flat config file ([syncexec.go:1523](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/appconfig/syncexec.go:1523)).
+
+ **Fix:** define a safe migration for never-materialized rows with generated metadata, including relocating or regenerating config while fenced. Test failover between two boxes where only one has held the database.
+
+6. **P2 — D15’s upgrade guard cannot guarantee availability from observed spawn history.**
+
+ A dormant flat or foreign workload never wakes during release N’s observation period. Its box publishes fresh snapshots without a would-be refusal. The upgrade passes, N+1 defaults to `refuse`, and the workload’s first later wake fails. Recorded flat intent is another case: the exception names `CARLOS_LAYOUT_DEFAULT=flat`, rather than every effective flat intent.
+
+ The existing classifier recognizes foreign rows ([layout.go:78](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/activator/layout.go:78)); the proposed D14 status records spawn events rather than an inventory of workloads affected by the new policy.
+
+ There is also a separate default transition: explicitly setting `CARLOS_FLAT_EXEC=report` bypasses this guard but does **not** preserve worker behavior when `CARLOS_NESTED_WORKERS` changes from off to on. An unaudited worker using the old absolute database path can consequently break despite that opt-out.
+
+ **Fix:** assess all registered workloads and effective layout intent, including dormant rows, before changing either default. Treat worker migration readiness separately from permission to retain flat execution.
+
+7. **P2 — D6 turns several real worker failures into successful completion.**
+
+ A hibernating worker exits with status 143, or dies from SIGPIPE. The trampoline preserves the numeric exit or maps the signal to 141. The proposed template marks those statuses successful, so `unitProc.Crashed()` returns false and the activator parks the worker. Without another scheduled wake, it stays down.
+
+ Flat workers classify every unsuccessful process exit as a crash ([backend_exec.go:3329](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/activator/backend_exec.go:3329)). The trampoline’s mapping is explicit ([init_linux.go:135](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/instanceexec/init_linux.go:135)), as is the inherited success list ([carlos-instance-sidecar@.service:41](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/host/units/carlos-instance-sidecar@.service:41)). Crash versus finish determines restart versus parking ([activator.go:4625](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/activator/activator.go:4625)).
+
+ **Fix:** give workers exit semantics matching their existing contract, distinguishing requested stops from unexpected nonzero exits. This requires reopening D1’s four-line-only template constraint.
+
+8. **P2 — D17 checks a different placement set from the reconciler and can approve workers that cannot run.**
+
+ A region contains a fresh, nested-ready box, but it serves the wrong pool or accepts inbound traffic when the worker requires `no-inbound`. The proposed check passes; no box creates a runnable row. Conversely, an irrelevant box with workers off blocks creation in an otherwise suitable pool.
+
+ Creation records the app’s pool ([apisidecars.go:293](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/console/apisidecars.go:293)); reconciliation filters region, pool and placement ([sidecar_reconcile.go:343](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/provision/sidecar_reconcile.go:343)).
+
+ Claim mode presents another false positive: all four proposed `Workers=nested` conditions can hold while the actual launch path unconditionally refuses workers ([workerbuild.go:111](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/activator/workerbuild.go:111)).
+
+ **Fix:** evaluate the actual eligible placement set, require it to be nonempty, and include worker-launch capability in readiness.
+
+9. **P2 — D18 equates an incomplete cgroup observation with proof that no flat child remains.**
+
+ The proposed count excludes processes outside named `carlos-exec@*` groups. Existing supported paths can launch without a manager, and the PID-placement fallback can leave grandchildren in the agent’s group ([cgroup.go:360](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/cgroup/cgroup.go:360), [cgroup.go:392](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/cgroup/cgroup.go:392)). The census also returns an empty result for a missing or unreadable root and skips unreadable groups ([metrics_probes.go:253](/home/paulca/.cache/tmp/claude-1001/sec/design-sidecar-isolation/internal/host/metrics_probes.go:253)).
+
+ A normal edge service restart drains its subtree, but D18 does not require evidence of that drain. Its count alone cannot establish the stated condition.
+
+ **Fix:** require a verified drain when transitioning to refusal, account for ungrouped descendants, and report unavailable or incomplete observations as unknown, which blocks fence removal.
+
+I found no fifth flat tenant spawn path beyond the four identified in §1.4. With your current fence hardening, the direct migration into `supervise` described in §1.6 fails because the destination `cgroup.procs` is no longer writable by `carlos`; the empty exemption list removes the other named destination. That follows the kernel’s destination/common-ancestor permission checks ([https://docs.kernel.org/admin-guide/cgroup-v2.html](https://docs.kernel.org/admin-guide/cgroup-v2.html)) and is consistent with systemd’s delegation ownership behavior ([https://systemd.io/CGROUP_DELEGATION/](https://systemd.io/CGROUP_DELEGATION/)). I have not treated that obsolete escape as a finding.
+
+This was a static review; no live infrastructure tests ran. I could not write `CODEX-FINDINGS-SIDECAR-ISOLATION-R1.md` because this session’s filesystem permissions are read-only.
+
+**Overall verdict: reject.**
\ No newline at end of file