carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1**Neither spec is ready for planning.** B rev 3 resolves most of the original round-2 findings, but the combined protocol still permits concurrent writers after `declare-lost`, cannot safely exclude delayed staging work, and has several crash paths that cannot finish.
2
3I read AGENTS.md, both complete specs, and all five prior findings documents. Code references below refer to `6e4d3a0e` unless explicitly qualified. **The db-door implementation is absent from this worktree**; I checked it at `653ad4b1`. This was a static, read-only review: no files changed, tests run, or production actions taken. The requested repository-policy Opus cross-check was unavailable; these are my findings.
4
5**1. Moves round-2 dispositions**
6
7“Resolved” means the particular design defect is addressed, not that the implementation exists or the composed protocol is approved.
8
9| R2 finding | Verdict | Reason |
10|---|---|---|
11| R2-1: surviving flat-exec descendants | **Resolved in B** | §5.3 requires strict containment, empty process trees and stray-process checks; A must adopt D3. |
12| R2-2: stop evidence lost with activator memory | **Resolved in design** | Reconstruction now uses observable state, including never-spawned operations, rather than `stopHistory`. |
13| R2-3: dirty source recovery replays installation | **Resolved** | §7.8 has separate source recovery phases and prohibits reinstalling after `probing`. Pre-flip recovery has a different gap below. |
14| R2-4: reconcile retires rollback target | **Resolved** | Both participants remain held until release and cleanup finish. |
15| R2-5: rollback leaves target replica live | **Resolved as a requirement** | Target replica/staging parking is now mandatory before finalization; the park algorithm has new completion failures below. |
16| R2-6: premature installation markers | **Resolved** | Bucket park/copy/publication are separated; `.files-gen` follows durable env, timer and registry installation. |
17| R2-7: mirror deletes adjacent metadata | **Resolved** | Mirroring is confined to `replica/`; archives, timers and operation metadata are separate. |
18| R2-8: incomplete and unpinned launch environment | **Partly** | Composition and input versions are covered, but checking at admission/configuration does not exclude delayed config/adoption work or changed inherited environment at the actual spawn. |
19| R2-9: missing markers and restore verdict | **Resolved as inventory** | Markers are classified and excluded from content digests; verdict invalidation is specified. |
20| R2-10: incomplete cut budget | **Partly** | T11 includes the missing stages, but budgets one probe attempt while §7.7 permits three; no unambiguous end-to-end deadline constrains landing retries. |
21
22The carried-forward timer finding also remains **partly resolved**: draining delivery and freezing the converger do not cover the runner’s separate pruning path.
23
24**2. D1–D8 and I-7**
25
26**D1 — B is right: admission must identify the box and phase.**
27
28A region alone is insufficient. Wake currently refreshes a local row at [activator.go:1071](/home/paulca/amadan.net/carlos/platform-moves-design/internal/activator/activator.go:1071); ordinary reconcile mints it `ready` at [reconcile.go:364](/home/paulca/amadan.net/carlos/platform-moves-design/internal/provision/reconcile.go:364). Neither expresses the transfer of execution authority.
29
30Exact text:
31
32- **A §§4, 8:** “For move operations, admission requires the holder incarnation, execution holder, participant identity and phase-specific permission defined by the moves spec. Region equality alone never grants admission. Ordinary wake and recovery probe are distinct permissions.”
33- **B §19.1/K1:** “The admission table governs every spawn, including Seed, probe retries and recovery. The table, current holder incarnation and `exec` must all authorize the exact box. Check authorization before restore or other local mutation as well as before spawn.”
34
35**D2 — A is right; B has correctly withdrawn the disagreement.**
36
37Claim revision and installed generation serve different purposes. The existing creation identity is explicitly continuity metadata, not a database generation: [types.go:60](/home/paulca/amadan.net/carlos/platform-moves-design/internal/maintenanceguard/types.go:60).
38
39Exact text:
40
41- **A §2:** “`gen` is the revision of the whole claim and increases on every successful claim write. It is not an installed-data generation.”
42- **B §5.1:** “Installed generations are identified by operation id and incarnation. Claim `gen` is used only for claim concurrency and observations; it is never an installed-generation marker.”
43
44**D3 — B is right, with a required restart-recovery API distinction.**
45
46Best-effort placement can leave descendants outside the host cgroup: [cgroup.go:230](/home/paulca/amadan.net/carlos/platform-moves-design/internal/cgroup/cgroup.go:230). Also, `PrepareStrict` rejects a populated group, so it cannot itself reopen and kill a surviving group after restart: [strict_linux.go:206](/home/paulca/amadan.net/carlos/platform-moves-design/internal/cgroup/strict_linux.go:206).
47
48Exact text:
49
50- **A §6:** “All lifecycle-controlled spawns require strict containment. Stop evidence requires a closed admission fence, drained spawn attempts, an empty complete process tree, closed replicators and no remaining database/WAL/SHM holders. An absent host cgroup is insufficient where an earlier spawn could escape containment.”
51- **B §5.3:** “Reconstruction uses a cleanup-only operation that can reopen, identify, kill and drain an existing populated cgroup without granting spawn authority. `PrepareStrict` remains the empty-group spawn API. A pre-move best-effort child is not certified stopped by ordinary parent exit.”
52
53Apply this to delete/park as well as moves.
54
55**D4 — B is right about IAM; its proposed exception is unsafe. Neither exclusion rule works as written.**
56
57The grants are precise:
58
59| Principal | Own data bucket | Sibling `moves/*` | Sibling `instances/*` |
60|---|---|---|---|
61| Region host | Get, Put, Delete; List | Put, Delete; prefix-conditioned List | No grant through sibling staging |
62
63See [main.tf:166](/home/paulca/amadan.net/carlos/platform-moves-design/infra/modules/region-host/main.tf:166) and [main.tf:217](/home/paulca/amadan.net/carlos/platform-moves-design/infra/modules/region-host/main.tf:217). A source cannot read the destination lock. But two workers for the **same operation** share its prefix, and `MirrorPrefix` deletes destination-only keys: [mirror.go:222](/home/paulca/amadan.net/carlos/platform-moves-design/internal/lease/mirror.go:222).
64
65Exact text:
66
67- **A C3:** “Cross-region staging uses a shared staging-work lease in the deployment bucket, keyed by destination region and host, accessible to both participants. Every staging writer, seal, park and abort obeys this lease. Actors acquire it before revalidating operation and phase. Per-operation naming alone is not exclusion.”
68- **B §19.3 D4:** “Retain M17’s push-only sibling grant. Replace the lease exception with the shared staging-work lease. Before sealing or parking staging, drain earlier rounds and their outstanding I/O. Landing consumes a sealed manifest of exact object identities, using conditional copies; no earlier round may mutate the sealed input.”
69
70The deployment-bucket grant already permits this coordination. The late-I/O requirement still needs the correction in N1 below.
71
72**D5 — B is right about separating move retirement from incarnation deletion, but operation id alone is insufficient.**
73
74The target can park an earlier stay during installation and later park this move’s failed landing during rollback. Both currently use `superseded/<move id>/<host>/`. Those are different datasets within **one** operation. A unique operation id does not separate them.
75
76The source/staging coordinates are independently derived in [movespass.go:364](/home/paulca/amadan.net/carlos/platform-moves-design/internal/host/movespass.go:364); copying supports a destination key, so the distinction can be preserved: [mirror.go:467](/home/paulca/amadan.net/carlos/platform-moves-design/internal/lease/mirror.go:467).
77
78Exact text:
79
80- **A §§2, 5:** “A `park-superseded` obligation identifies operation, retirement event, location, retired generation and artifact class. Its immutable manifest belongs to that exact retirement event, not merely to the incarnation or operation.”
81- **B §§6.4, 7.6, 7.8, 7.9:** “Use distinct destinations beneath `superseded/<op>/<host>/<retirement-id>/`, retaining separate `instances/` and `moves/` subtrees. Initial target retirement, failed-target retirement, source retirement and staging retirement never share a manifest.”
82
83**D6 — B identifies a real omission, but neither spec supplies independent execution fencing.**
84
85Changing `exec` cannot stop a partitioned process. Existing supervision reacts to the **regional replica lease**, not a globally enforced execution grant: [activator.go:2266](/home/paulca/amadan.net/carlos/platform-moves-design/internal/activator/activator.go:2266). Source and target leases cover different buckets.
86
87Exact text:
88
89- **A §4:** “Declaring a box lost does not itself establish stop evidence. Before transferring execution, resolve must obtain independently verified execution fencing of the exact box incarnation. Without that proof it retains the hold. Lost-box quarantine survives operation release and prevents readmission until its old state has been retired.”
90- **B §7.10/D6:** “A claim CAS is bookkeeping, not independent fencing. The resolve command must establish verified compute fencing, or an independently enforced execution-lease expiry, before reopening the source. Recover validated durable target data where available, not only an already-published return. Retain M16’s precommit restriction, exact-participant check, source refusal and explicit loss confirmation.”
91
92The command must perform this through platform interfaces; it cannot require a follow-up box command.
93
94**D7 — B is right.**
95
96The existing `MoveComplete` combines region change and clearing the old move, [provision.go:1053](/home/paulca/amadan.net/carlos/platform-moves-design/internal/provision/provision.go:1053); it cannot be reused unchanged for the proposed multi-stage protocol.
97
98Exact text for **both operation tables**:
99
100> “Legal move-kind transitions are `serving → moving`; `moving → landing` or `reverting`; `landing → restoring` or, after committed finalization, `serving`; `reverting/restoring → serving` only after their recovery and cleanup conditions hold. Kind transitions do not independently transfer execution authority.”
101
102Also reconcile K4’s “by that participant” with §7.5’s source completing the target handoff after a crash. Name one authorized writer for each transition and its recovery.
103
104**D8 — Both rules are compatible; retain B’s stronger operation-specific completion condition.**
105
106Existing `MoveAbortComplete` simply clears the record, [provision.go:1043](/home/paulca/amadan.net/carlos/platform-moves-design/internal/provision/provision.go:1043), so builders must not mistake that helper for the new completion contract.
107
108Exact text:
109
110- **A §2:** “All obligations block `free`. Each operation additionally defines which obligations block its release to `serving`; release preserves obligations owned by any other durable lifecycle work.”
111- **B K8:** “A move releases to `serving` only after every obligation it created has a durable completion acknowledgement. Record cleanup and claim release follow the crash-recoverable finalization protocol, including abort.”
112
113**I-7 — B’s explicit flat-file inventory is necessary.**
114
115Flat env files are siblings of the database, not entries in the flat files directory: [paths.go:50](/home/paulca/amadan.net/carlos/platform-moves-design/internal/activator/paths.go:50). `EnsureAdminToken` deliberately preserves an existing token: [admintoken.go:104](/home/paulca/amadan.net/carlos/platform-moves-design/internal/activator/admintoken.go:104).
116
117Exact text:
118
119- **A §5.4:** “Local retirement covers both layouts. For flat hosts it includes `<DataDir>/<host>/`, the database and companion artifacts, `<host>.env`, `<host>.config.env`, `<host>-sidecar.env`, generation/lineage markers and host-bound operational state. Nested inventory uses the resolved instance directory. Persist this inventory independently of the replaceable operation journal.”
120- **B §17 I-7:** “Agreed: A’s local retirement inventory covers flat files and sibling env files as well as nested state. A host cannot become free until every recorded location acknowledges completion, including an empty retirement.”
121
122**3. New findings**
123
124The following are additional failure traces or failures in the proposed remedies, rather than missing implementation being reported as a defect.
125
126**N1 — P1: client cancellation does not establish the storage exclusion assumed by the simulation.**
127**A §3.1/C3; B §19.4.**
128
129A destructive request is issued before `SafeUntil`; the client times out, the lease expires, and a successor installs new data. The old server-side request can still complete against the reused key. Checking the deadline before submission and cancelling the client does not supply a server-side ownership condition.
130
131The current delete has no condition at all: [mirror.go:493](/home/paulca/amadan.net/carlos/platform-moves-design/internal/lease/mirror.go:493). The lease deadline contract itself warns that notification is not proof: [lease.go:182](/home/paulca/amadan.net/carlos/platform-moves-design/internal/lease/lease.go:182).
132
133**Fix:** specify conditional/version-bound destructive operations or non-reused physical object identities that make late completion harmless. Keep clock/pause assumptions separate from server-side completion. Model “request submitted, client cancelled, server completes later”; an atomic bucket-call model cannot catch this.
134
135**N2 — P1: the D4 exception permits a delayed round to corrupt sealed staging.**
136**B §§7.3–7.6, 19 K5/D4; A C3.**
137
138Worker W reads the permitted phase, then pauses. Another worker finishes the final round and flips. W resumes its same-operation mirror and overwrites or deletes keys while the target copies them. Operation id and incarnation still match.
139
140The existing pass mutex is process-local, [movespass.go:238](/home/paulca/amadan.net/carlos/platform-moves-design/internal/host/movespass.go:238); destination mutation occurs later in [mirror.go:198](/home/paulca/amadan.net/carlos/platform-moves-design/internal/lease/mirror.go:198) and `:228`.
141
142**Fix:** adopt D4’s shared staging lease, validation under that lease, explicit round draining and sealed object identities. Exercise two workers for the same operation, not just competing move ids.
143
144**N3 — P1: `declare-lost` can start a second writer immediately.**
145**A §4; B §7.10, K6/K11.**
146
147The target probe remains alive while partitioned from the control bucket. Resolve changes `exec` to `none`, then the source recovers. The target has not read the new claim and continues background writes. A future kill “when it returns” does not repair the interval with two writers.
148
149Regional replication supervision at [activator.go:2266](/home/paulca/amadan.net/carlos/platform-moves-design/internal/activator/activator.go:2266) does not fence a process merely because another bucket’s claim changed.
150
151**Fix:** D6’s independent fence before source admission. Test a live target partitioned only from control-plane access, including one still able to reach its regional bucket and external systems.
152
153**N4 — P1: the claim and record have unjournaled transaction gaps.**
154**A C2/§5; B §§7.1, 7.5, 7.8–7.11.**
155
156Concrete crash points:
157
158- Create claims `serving`, then crashes before `CreateRecord`.
159- Move claims `moving`, then crashes before publishing `record.move`.
160- Delete removes the record, then crashes before creating park obligations.
161- Abort clears `move`, then crashes before releasing the claim.
162
163The current worker discovers work through records and skips `Move == nil`: [movespass.go:242](/home/paulca/amadan.net/carlos/platform-moves-design/internal/host/movespass.go:242). Neither spec defines a complete recovery owner and replay decision for all these states. “Console: stateless” is false for a claim-only accepted request without durable reconstruction inputs.
164
165**Fix:** persist operation intent and reconstruction inputs before the first cross-object side effect; define discovery and reconciliation of incomplete claims without relying on an existing record. Specify every ambiguous-write recovery and terminal ordering. A stale finalizer must never clear a newer operation.
166
167**N5 — P1: lazy legacy adoption does not establish a complete `touched` inventory.**
168**A §§7, 9; B §§0.4, 7.12.**
169
170Before rollout, H moved from UK to US. The old move left the UK replica; current code purges local artifacts and flips the record, [movespass.go:492](/home/paulca/amadan.net/carlos/platform-moves-design/internal/host/movespass.go:492), without retiring that source replica.
171
172A door adopts H with only US in `touched`. Delete parks US and frees the claim. Recreate H in UK; the old replica remains eligible for host-keyed restore, [backend_exec.go:300](/home/paulca/amadan.net/carlos/platform-moves-design/internal/activator/backend_exec.go:300). It has no move-generation marker, so origin-marker absence does not distinguish it from legitimate origin data.
173
174**Fix:** complete legacy location discovery and retirement acknowledgement before allowing reuse. Unknown historical coverage must block reuse. A first door cannot certify global cleanliness from the current record region or the console’s own bucket.
175
176**N6 — P1: parking an active coordination lock makes ordinary retries conflict permanently.**
177**A §5.4.3; B §17 I-8.**
178
179The park acquires a lease and copies every key, including `lock.json`, into its immutable manifest. Renewal changes the source lock ETag. A retry acquires another lock body. The manifest comparison now fails against the worker’s own coordination state, leaving the obligation outstanding.
180
181Renewal updates the lease identity at [health.go:129](/home/paulca/amadan.net/carlos/platform-moves-design/internal/lease/health.go:129). Existing mirroring explicitly excludes `lock.json` for this reason: [mirror.go:174](/home/paulca/amadan.net/carlos/platform-moves-design/internal/lease/mirror.go:174).
182
183**Fix:** exclude live coordination locks from copied data and manifest completeness checks. Release only the current lease handle, conditionally, after durable completion. A historical lock observation may be recorded as evidence, but cannot be a replayable data entry.
184
185**N7 — P1: one move can reuse its own immutable park manifest for different data.**
186**B §§6.4, 7.6, 7.8, 7.9; A’s borrowed park helper.**
187
188A returning host already has residue on the target. Landing parks that residue into `superseded/<move>/<host>/` and installs new data. Its probe writes, then fails. Rollback cleaning parks the new target replica into the same destination.
189
190With A’s immutable-manifest rule, cleaning encounters unlisted or changed keys and cannot finish. Overwriting the manifest instead destroys the earlier retirement record. Replica and staging retirement also need distinct mappings.
191
192**Fix:** use D5’s retirement-event ids and separate artifact subtrees. Test a move back to a previously used region followed by dirty rollback. Unique move ids alone do not cover this case.
193
194**N8 — P1: status filters do not drain config, adoption or placement work already in flight.**
195**A C3/§8; B §§7.3–7.6, 9.1–9.2, K9.**
196
197A config pass selects A’s ready row and renders its secrets. It stalls. A is deleted and parked; B is created at the same host. The old pass resumes and writes A’s `<host>.config.env`. B can then launch with A’s credentials.
198
199The write uses the captured route at [syncexec.go:1091](/home/paulca/amadan.net/carlos/platform-moves-design/internal/appconfig/syncexec.go:1091), culminating in the rename at `:1180`. Release adoption similarly changes a host-keyed live symlink at [adopt.go:1045](/home/paulca/amadan.net/carlos/platform-moves-design/internal/release/adopt.go:1045). Its earlier `ready` filter does not protect that later mutation.
200
201There is also a separate placement writer: [fleets.go:616](/home/paulca/amadan.net/carlos/platform-moves-design/internal/console/fleets.go:616) changes registry placement before [provision.go:853](/home/paulca/amadan.net/carlos/platform-moves-design/internal/provision/provision.go:853) changes the record.
202
203**Fix:** make these actors participate in lifecycle exclusion, including draining already-admitted work. Bind host-specific writes to incarnation and operation under the same local mutation guard. Guard placement before **any** app, registry or record mutation. At actual probe spawn, revalidate the complete composed environment and pinned executable, including inherited agent variables after restart.
204
205**N9 — P1: app purge can destroy the move’s store before encountering the host claim.**
206**A §5; B §7.12/K7.**
207
208The proposed refusal is inside `PurgeApp`/record retirement. The console destroys app stores **before** calling that function: [ownership.go:404](/home/paulca/amadan.net/carlos/platform-moves-design/internal/console/ownership.go:404), followed by `PurgeApp` at `:442`.
209
210An app with a moving instance can therefore lose its store and credentials before purge reports that the move prevents deletion. Phase 1 permits shared app stores; deferring store migration does not make their destruction safe.
211
212**Fix:** acquire a durable app-purge reservation and the necessary host lifecycle exclusions before store/email teardown or prefix deletion. Concurrent creation must also be excluded. A read-only “no move currently exists” preflight is insufficient.
213
214**N10 — P1: waiting out the db-door cache does not drain authorized reads.**
215**A §§5.1, 8; B §19.1.**
216
217Console A authorizes an old-incarnation GET, then stalls before opening the object. Console B begins deletion and waits one cache lifetime. It parks, frees and recreates the host. A resumes and opens the reused LTX coordinate.
218
219At **`653ad4b1:internal/console/apidb.go:287`**, authorization precedes **`:312`**, the actual `OpenLTXFile`. Cache expiry does not revoke that admitted request or prove that it finished.
220
221**Fix:** bind reads to immutable object versions/identities, or use distributed read reservations whose completion/expiry is part of retirement. Stop accepting reads and drain them on every console before namespace reuse. Model a stalled handler between authorization and object open, not only an already-streaming response.
222
223**N11 — P1: pre-flip recovery can reject its own newly acknowledged writes after a crash.**
224**B §7.4 `reverting`; contrast §7.8’s corrected recovery journal.**
225
226A final staging/archive step fails. The source verifies its stopped digests and starts the recovery probe. That probe changes files and acknowledges background work. The agent crashes before opening and recording `aborting`.
227
228Recovery re-enters §7.4 and compares the changed files against the original stopped digest. It now declares a mismatch and remains stuck. Reinstalling the baseline would lose the probe’s writes.
229
230The probe runs the real writable application, through [backend_exec.go:912](/home/paulca/amadan.net/carlos/platform-moves-design/internal/activator/backend_exec.go:912).
231
232**Fix:** give pre-flip recovery durable `verified → probing → recovered → opened` phases too. After entering `probing`, never reapply the old baseline check as an admission requirement or restore over recovery writes.
233
234**N12 — P1: the version floor omits an automatic path back to an old executable.**
235**A §9; B §§11, 14.3, 15.**
236
237B names `system apply` and explicit rollback. Boot recovery independently restores `carlos.prev`: [systemapply.go:901](/home/paulca/amadan.net/carlos/platform-moves-design/internal/host/systemapply.go:901), calling the shared restore path that copies the old binary at [systemapply.go:817](/home/paulca/amadan.net/carlos/platform-moves-design/internal/host/systemapply.go:817).
238
239A leftover apply journal can therefore restore a pre-floor executable while a host is landing or restoring unless the floor is enforced in this path too. Old reconcile then knows only the ordinary `ready` mint.
240
241Additionally, B §15 puts flagship rehearsals before floor publication, while §11 requires publication before the first production move.
242
243**Fix:** enforce the floor in every executable restoration path, including automatic recovery and boot. Validate `.prev` and outstanding update journals before activation. Publish the floor before protected production rehearsals. Define authoritative enrollment of all relevant boxes/consoles and exclusion of old writers; a version report cannot constrain an old executable that ignores the claim.
244
245**N13 — P2: abort assigns remote parking to an actor without the necessary permission.**
246**B §7.11; A C3.**
247
248The source is told to park target staging into `superseded/`. Under M17 it cannot read target staging and cannot write target `superseded/`; it has only sibling `moves/*` Put/Delete/List. The existing abort only deletes remote staging, [movespass.go:396](/home/paulca/amadan.net/carlos/platform-moves-design/internal/host/movespass.go:396), which explains why its existing authority was sufficient.
249
250**Fix:** make target staging retirement a durable obligation executed by the target-region actor. The source parks its own snapshots. Abort retains its claim until both acknowledge completion. Do not broaden M17 to cross-region data reads.
251
252**N14 — P2: a second timer-pruning actor bypasses the freeze.**
253**B §9.4/K9.**
254
255The runner performs its own daily prune at [runner.go:260](/home/paulca/amadan.net/carlos/platform-moves-design/internal/schedule/runner.go:260). `PruneTimers` removes aged completed once-timers even for an alive host: [timers.go:188](/home/paulca/amadan.net/carlos/platform-moves-design/internal/registry/timers.go:188).
256
257A held source can therefore change its timer snapshot after `stopped`, causing clean recovery’s digest comparison to fail despite no application write. Freezing only declaration convergence and delivery misses this actor.
258
259**Fix:** make both prune callers respect the operation’s timer freeze, or define a canonical snapshot that explicitly excludes disposable history. Exercise the daily runner sweep during landing and rollback.
260
261**N15 — P2: the promised cut window still lacks one enforceable budget.**
262**B §§7.3 T11, 7.4, 7.6–7.7.**
263
264T11 reserves one 30-second probe plus 20-second settle, while §7.7 allows three attempts and landing has a separate ten-minute deadline. Those rules permit a successful move substantially beyond an admitted 120-second window.
265
266The existing health timeout is a per-start bound, [backend_exec.go:36](/home/paulca/amadan.net/carlos/platform-moves-design/internal/activator/backend_exec.go:36), not an end-to-end move deadline.
267
268**Fix:** persist an absolute cut deadline, allocate remaining time across installation and probe attempts, and begin recovery when it is exhausted. Keep recovery’s deadline separate. State whether the estimate promises one-attempt success or includes permitted retries.
269
270There are no additional material P3 findings.
271
272**4. Verdicts**
273
274| Spec | Verdict | Planning blockers |
275|---|---|---|
276| **A: host lifecycle claim** | **Not ready** | Incomplete legacy location adoption; missing cross-object recovery; lock-bearing park manifests; stale background writers and db reads; insufficient execution/storage fencing. |
277| **B: move-any-app rev 3, Phase 1** | **Not ready** | Unsafe D4/D6 implementations; colliding park transactions; unjournaled pre-flip recovery; abort IAM mismatch; incomplete integration with purge, background passes and automatic executable recovery. |
278
279A also fails to carry forward the prior **R3-12 fresh-incarnation requirement** explicitly. Both creation helpers still accept caller-provided timestamps—[CreateRecord](/home/paulca/amadan.net/carlos/platform-moves-design/internal/provision/provision.go:820) and [CreateSidecarRecord](/home/paulca/amadan.net/carlos/platform-moves-design/internal/provision/sidecar.go:322)—while A clears the holder on `free` and retains incarnation-keyed immutable park manifests. Reusing the old creation identity must be prohibited. This is an unresolved prior finding, not counted among the new findings.
280
281The joint simulation should use the real permission split and include late server-side completion, claim-only operations, legacy residue discovery, delayed config/adoption writes, purge teardown, distributed read reservations, automatic boot recovery, and multiple retirement events within one operation. Randomizing only the named move phases will miss these failures.
282
283M1–M18 and the reduced follow-on scope can remain unchanged.
284
285---
286
287**FIRST PROMPT:**
288Joint read-only review of the host-lifecycle claim and move-any-app specs against this worktree.
289
290**WHAT:**
291Check prior fixes, settle the interfaces, and find composition failures.
292
293**STATUS:**
294Review complete. Neither spec is ready for planning. Workspace unchanged.
295
296**NEEDED:**
297Nothing for this review.
298
299**RECOMMENDED:**
300Revise the shared exclusion and recovery contracts, then run the expanded joint simulation before implementation planning.
301
302**SESSION:**
303Safe to close. Nothing is running; no handoff file was written because the review is read-only.