spec: host lifecycle claim rev 6.7, the moves session's notes on writer epochs
closed.json consumed by version at open (failure means cold recovery); the first wake after create or adoption is cold; the warm DB is the baseline only when its lineage names the old generation, it passes its integrity check, and this box was that generation's active writer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+34
−3
docs/superpowers/specs/2026-10-02-host-lifecycle-claim-design.md+34 −3
CI passed — run details
diff --git a/docs/superpowers/specs/2026-10-02-host-lifecycle-claim-design.md b/docs/superpowers/specs/2026-10-02-host-lifecycle-claim-design.md| index e6d81f41b..722a354e1 100644 |
| --- a/docs/superpowers/specs/2026-10-02-host-lifecycle-claim-design.md |
| +++ b/docs/superpowers/specs/2026-10-02-host-lifecycle-claim-design.md |
| @@ -1,7 +1,9 @@ |
| # The host lifecycle claim |
| -Design, 2026-10-04, **rev 6.6**. Joint rounds 6 and 7 judged the claim ready for primitive planning. Rev |
| -6.5 added the R6-4 rule. Rev 6.6 adds writer epochs (R7-1, amadan #225). A small primitive cited by: |
| +Design, 2026-10-04, **rev 6.7**. Joint rounds 6 and 7 judged the claim ready for primitive planning. Rev |
| +6.5 added the R6-4 rule. Rev 6.6 added writer epochs (R7-1, amadan #225). |
| +Rev 6.7 answers the moves session's three notes on §6.4a: consuming the |
| +marker, the first wake, and the warm baseline. A small primitive cited by: |
| - **#199**, deleting an instance and parking its data: |
| `2026-10-02-replica-ownership-design.md`, which this spec supersedes |
| @@ -853,6 +855,23 @@ So **two writers whose uploads could overlap never share a generation**. |
| - its `max_txid` equals the generation's remote maximum TXID; |
| - its `stamp` is the box's own `active_stamp`. |
| + **The marker is consumed when a writer opens it.** The admitted writer |
| + deletes `closed.json`, by the exact version it read, before it issues |
| + its first upload. If that delete fails, the writer does not continue |
| + the generation; it takes the cold-recovery path instead. A writer that |
| + continues after a clean close and then crashes with uploads in flight |
| + therefore leaves no marker, and the next wake recovers cold. The delete |
| + marker this leaves lets the writer's own later clean close write the |
| + key again with `If-None-Match`. |
| + |
| + **The first wake after a create or an adoption is a cold recovery.** No |
| + writer closed the origin generation. Nobody writes a marker it didn't |
| + earn, and an empty generation is not exempted, because a first writer |
| + that crashed with `[1,1]` in flight leaves the same state. A new |
| + instance's first generation snapshots an empty or near-empty |
| + database, so the cost is small. An adoption pays one full snapshot, |
| + once. |
| + |
| Otherwise the previous writer may still have uploads in flight. That |
| covers a crash, an out-of-memory kill, lease expiry or takeover, a |
| shared-pool failover, a lost box, and a missing or unreadable marker. |
| @@ -863,7 +882,18 @@ So **two writers whose uploads could overlap never share a generation**. |
| `holder.generation`. The CAS writes a **new `holder.generation`**, a |
| fresh op id that is never reused, and a **new `holder.stamp`** (the |
| resulting `gen`). It requires `op.exec` to be this box. The box then: |
| - 1. restores from the old generation; |
| + 1. establishes its **baseline**: |
| + - **The warm local database**, if all of these hold: |
| + - its lineage marker (`<dbPath>.gen`) names the old generation; |
| + - it passes its integrity check; |
| + - the box's local stamp record shows **this box was the old |
| + generation's active writer**. |
| + |
| + A crash without disk loss leaves that database holding |
| + acknowledged writes that were never uploaded, so it is a superset |
| + of the remote. |
| + - **Otherwise, a restore from the old generation's remote.** Another |
| + box may have advanced the remote past this box's copy. |
| 2. activates the new stamp locally (§6.4); |
| 3. replicates **only** into the new generation's prefix. |
| @@ -1128,6 +1158,7 @@ the model catches it. |
| | J4-R4-4 | §5.3 step 4 | |
| | J4-Q2 | §5.1 step 5 | |
| | J5-R5-4 | §2 `holder.stamp`, §6.4 initialization, refusal with no record, the two retirements | |
| +| moves 7.8 notes | §6.4a: marker consumed at open, first wake is cold, warm baseline only for the old generation's own writer | |
| | J7-R7-1 | §6.4a writer epochs: clean close, lost replication state, cold recovery as an installing CAS, generation-bound writers | |
| | J6-R6-4 | §2 `holder.stamp` invariant: any CAS that changes `op.exec` writes `holder.stamp` | |
| | moves 7.6 notes | §6.4 stamp captured at selection; only activation and retire-installation move stamps; §6.2a non-incarnation children | |