carlos / platform Public

plan: claim Plan 8 rev 5, answers review round 4 (one P2, one P3)

Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
codex agent, operated by paul@keymail.dev pushed by claude agent, operated by paul@keymail.dev 050b331ff84c38dfea5785652fb519923067176d parent a3da699
1 file changed, +206 −11
  • docs/superpowers/plans/2026-10-05-host-lifecycle-claim-8-leases-floor.md +206 −11

CI passed — run details

diff --git a/docs/superpowers/plans/2026-10-05-host-lifecycle-claim-8-leases-floor.md b/docs/superpowers/plans/2026-10-05-host-lifecycle-claim-8-leases-floor.md
index 36bf3e214..f9cc6cd1c 100644
--- a/docs/superpowers/plans/2026-10-05-host-lifecycle-claim-8-leases-floor.md
+++ b/docs/superpowers/plans/2026-10-05-host-lifecycle-claim-8-leases-floor.md
@@ -1,6 +1,6 @@
# Host Lifecycle Claim, Plan 8: inert lease and lost-box contracts
-Rev 4 answers review round 3 (one P1, one P2).
+Rev 5 answers review round 4 (one P2, one P3).
This plan follows claim spec **rev 6.22**, §7.3 D2–D6. These contracts remain **PROPOSED**. Paul has not ruled on P1–P3 in §10.1 and amadan discussion **#236**. Landing these libraries does not authorize activation.
@@ -10,7 +10,7 @@ This plan follows claim spec **rev 6.22**, §7.3 D2–D6. These contracts remain
**Architecture:** reuse `release.Store` conditional writes and `DeleteIfMatch`, with the existing lease package's S3 configuration. Keep the specified two-field execution record separate from the replica lease. `hostexec` owns local controller exclusion and deadlines. `hostclaim` owns conditional journal and loss changes. `hostquarantine` consumes an `ActorDirectory` interface; only a test fake exists here. `awsinv` supplies a read-only exact-instance check, and `hostfence` supplies a challenge signed with the console's existing root key. No new live caller can mutate a claim through the CLI or console routes in this plan.
-**Depends on:** Plans 1 and 3, plus E’s follow-up branch `feat/hostclaim-r713` for the native multiple-declaration API in operative §6.4a item 2. Once r713 is pushed, use a clean implementation checkout:
+**Depends on:** Plans 1 and 3, plus E’s follow-up branch `feat/hostclaim-r713` for the native multiple-declaration API in operative §6.4a item 2. Use the pushed r713 tip `f0127321eb97acae7b529eb993910873a720d14d` in a clean implementation checkout:
```bash
git fetch origin
@@ -25,7 +25,7 @@ Use the repository's reviewed-branch workflow when the implementation is ready.
- `docs/superpowers/specs/2026-10-02-host-lifecycle-claim-design.md`, rev 6.22: §2, C1–C6, §6.1, §6.3, operative §6.4a, §7.1–§7.3 and §10–§10.1. §7.3 supplies the proposed claim contracts; §10.1 records the still-open approval boundaries.
- Plans 2, 3, 4, 7 and 7b in this directory supply the storage, local guard, retirement and consumer conventions. Plan 3's R9 applies to every local lease file and lock. Plan 4 owns immutable parking scopes and the late-completion horizon; this plan preserves those journals and retirement identities.
-- Compile baseline: `feat/hostclaim-boxguard` at `8c40aca61d6b25ea5e936ffab171d237f1b13483`, plus the disjoint `origin/main` changes at `562f3dfcb4934c0dec027f730e34bbff08bbbd15`. The Task 1 patch additionally requires r713’s native `Admission.AdditionalWritesLost []WritesLost` and `AdmissionRecord.AdditionalWritesLost`, its verbatim admission copy and `(box, session)` uniqueness check. The authoring check used the local r713 snapshot described below; the pushed branch was unavailable in this checkout. Existing `hostclaim.Update` clones the observation, checks its ETag and assigns the next claim generation. `CompleteObligation` handles discovery completion using the chore's original operation ID.
+- Compile baseline: `feat/hostclaim-boxguard` at `8c40aca61d6b25ea5e936ffab171d237f1b13483`, plus the disjoint `origin/main` changes at `562f3dfcb4934c0dec027f730e34bbff08bbbd15`. The Task 1 patch additionally requires r713’s native `Admission.AdditionalWritesLost []WritesLost` and `AdmissionRecord.AdditionalWritesLost`, its verbatim admission copy and `(box, session)` uniqueness check. Rev 5 checks the exact patch against the pushed `origin/feat/hostclaim-r713` tip `f0127321eb97acae7b529eb993910873a720d14d`. Existing `hostclaim.Update` clones the observation, checks its ETag and assigns the next claim generation. `CompleteObligation` handles discovery completion using the chore's original operation ID.
- `internal/lease/{lease,health,endpoint}.go`: replica leases use a different object and 15-minute TTL. Reuse their configured S3 client, not their wire encoding or TTL. `internal/release/{store,conditional_delete}.go` supplies create-only PUT, conditional replacement and conditional deletion.
- `internal/awsinv/{clients,ec2}.go` supplies `DescribeInstances`. There is no existing stop/terminate primitive to call. The operator fences compute through their authorized infrastructure workflow; this plan verifies a positive cloud result and never changes compute.
- `main.go`, `apimode.go`, `internal/console/{authcli,server}.go` supply CLI dispatch, person sessions and the console signer. `Store.IsOperator` is the required authority. Tenant ownership, system-roller permission and service credentials are insufficient.
@@ -47,7 +47,7 @@ Each task below includes its implementation and tests. Save each existing-file p
## Task 1: Signed loss records, additive claim state and bound transitions
-**Produces:** root-only envelope helpers; D4 timer/write-loss records and archival checks; D5 `DeclareLost` and matching-revision `Readmit`; the D6 `exec_ack.<box>` journal helper. **Consumes:** existing `release.Store`, `hostclaim.Update`, `CompleteObligation`, r713’s native additional-loss fields and operation-owner validation. Apply this task as a unit: the schema, validator and transition changes refer to one another. No CLI or console mutation caller is added. r713 owns additional-loss representation and copying; this task adds durable declaration binding and archival metadata. Ordinary native additional losses remain accepted without `LossID` and retained until archival. The signed wrapper requires an uncovered cold admission and checks every frozen tuple, including older target sessions, against its own baseline. The r713 trimming fixture uses certified predecessors so it continues to test trimming of loss-free rows.
+**Produces:** root-only envelope helpers; D4 timer/write-loss records and archival checks; D5 `DeclareLost` and matching-revision `Readmit`; the D6 `exec_ack.<box>` journal helper. **Consumes:** existing `release.Store`, `hostclaim.Update`, `CompleteObligation`, r713’s native additional-loss fields and operation-owner validation. Apply this task as a unit: the schema, validator and transition changes refer to one another. No CLI or console mutation caller is added. r713 owns additional-loss representation and copying; this task adds durable declaration binding and archival metadata. Ordinary native additional losses remain accepted without `LossID` and retained until archival. The signed wrapper requires an uncovered cold admission and checks every frozen tuple, including older target sessions, against its own baseline. A `LossRecoveryOwner` must validate the persisted handover from the declaration’s original kind/phase to the current recovery state. Kind and phase may change within the same operation; incarnation, operation ID and frozen loss evidence remain bound. Owner policy receives detached copies and cannot alter the admitted inputs. The r713 trimming fixture uses certified predecessors so it continues to test trimming of loss-free rows.
- [ ] **Apply the exact existing-file changes.**
@@ -122,8 +122,8 @@ Each task below includes its implementation and tests. Save each existing-file p
+ }
+ }
@@ -90,0 +111 @@
-+ LossID: in.LossID,
-@@ -108 +129 @@
++ LossID: in.LossID,
+@@ -112 +133 @@
- for len(h.Admissions) > 8 && h.Admissions[0].Covered {
+ for len(h.Admissions) > 8 && h.Admissions[0].Covered && admissionLossArchived(h.Admissions[0]) {
--- a/internal/hostclaim/delete.go
@@ -812,6 +812,23 @@ import (
"github.com/carlosframework/platform/internal/release"
)
+// Existing fixtures declare directly in the recovery phase. The end-to-end
+// test below supplies a separate owner for landing -> restoring.
+type testLossRecoveryOwner struct{}
+
+func (testLossRecoveryOwner) ValidateLossRecovery(c Claim, loss LossRecord, in Admission) error {
+ if c.Op.Kind != loss.OpKind || c.Op.Phase != loss.OpPhase || c.Op.Exec != in.Box {
+ return ErrWrongState
+ }
+ return nil
+}
+
+type lossRecoveryOwnerFunc func(Claim, LossRecord, Admission) error
+
+func (f lossRecoveryOwnerFunc) ValidateLossRecovery(c Claim, loss LossRecord, in Admission) error {
+ return f(c, loss, in)
+}
+
func validLossRecord(t *testing.T) LossRecord {
t.Helper()
now := time.Date(2026, 10, 5, 12, 0, 0, 0, time.UTC)
@@ -1001,7 +1018,7 @@ func TestLossBearingAdmissionRequiresEveryFrozenTargetAndSourceCut(t *testing.T)
candidate.AdditionalWritesLost = append([]WritesLost(nil), in.AdditionalWritesLost...)
evidence := append([]ValidatedWriteSource(nil), validated...)
mutate(&candidate, &evidence)
- if _, err := AdmitWriterWithLoss(ctx, s, pub, obs, candidate, "loss_1", evidence); !errors.Is(err, ErrLossRecord) {
+ if _, err := AdmitWriterWithLoss(ctx, s, pub, obs, candidate, "loss_1", evidence, testLossRecoveryOwner{}); !errors.Is(err, ErrLossRecord) {
t.Fatalf("invalid declaration admitted: %v", err)
}
fresh, err := Read(ctx, s, obs.Host)
@@ -1010,7 +1027,7 @@ func TestLossBearingAdmissionRequiresEveryFrozenTargetAndSourceCut(t *testing.T)
}
})
}
- admitted, err := AdmitWriterWithLoss(ctx, s, pub, obs, in, "loss_1", validated)
+ admitted, err := AdmitWriterWithLoss(ctx, s, pub, obs, in, "loss_1", validated, testLossRecoveryOwner{})
if err != nil {
t.Fatal(err)
}
@@ -1061,7 +1078,7 @@ func TestTargetOnlyLossAdmissionRequiresColdUncoveredRecovery(t *testing.T) {
t.Run(name, func(t *testing.T) {
in := base
mutate(&in)
- if _, err := AdmitWriterWithLoss(ctx, s, pub, obs, in, "loss_1", validated); !errors.Is(err, ErrLossRecord) {
+ if _, err := AdmitWriterWithLoss(ctx, s, pub, obs, in, "loss_1", validated, testLossRecoveryOwner{}); !errors.Is(err, ErrLossRecord) {
t.Fatalf("unsafe target-loss mode = %v", err)
}
})
@@ -1072,6 +1089,138 @@ func TestTargetOnlyLossAdmissionRequiresColdUncoveredRecovery(t *testing.T) {
}
}
+func TestLossDeclarationHandoverAdmission(t *testing.T) {
+ ctx := context.Background()
+ s := release.NewDirStore(t.TempDir())
+ pub, priv, err := ed25519.GenerateKey(nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ sg := release.RootSigner(priv)
+ obs := servingClaim(t, ctx, s)
+ obs, err = Update(ctx, s, obs, func(c *Claim) error {
+ c.Op = Op{Kind: KindLanding, ID: "move", Phase: "probe", Exec: "target", Participants: []string{"target", "recovery"}}
+ c.Holder.WriterBox, c.Holder.Generation, c.Holder.Session = "target", "g-target", 4
+ return nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ record := validLossRecord(t)
+ record.Host, record.HolderIncarnation = obs.Host, obs.Claim.Holder.Incarnation
+ record.HolderStamp, record.HolderSession = obs.Claim.Holder.Stamp, obs.Claim.Holder.Session
+ record.ExpectedClaimGen, record.ExpectedClaimETag = obs.Claim.Gen, obs.ETag
+ record.OpID, record.OpKind, record.OpPhase, record.Box = "move", KindLanding, "probe", "target"
+ record.WriteSources = []WriteSource{
+ {Reason: "target", Box: "target", Generation: "g-target", Session: 4, Region: "ie", Baseline: "target-snapshot"},
+ {Reason: "source-cut", Box: "source", Generation: "g-source", Session: 2, Region: "ie", Baseline: "source-seal"},
+ }
+ prepared, err := CreateLossRecord(ctx, s, sg, record)
+ if err != nil {
+ t.Fatal(err)
+ }
+ declared, err := DeclareLost(ctx, s, pub, obs, record.ID, testLossOwner{})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if declared.Claim.Op.Kind != KindLanding || declared.Claim.Op.Phase != "probe" || declared.Claim.Op.Exec != "none" ||
+ declared.Claim.Holder.Stamp != record.HolderStamp || declared.Claim.Holder.Session != record.HolderSession {
+ t.Fatalf("declaration changed recovery authority: %+v", declared.Claim)
+ }
+ committed := prepared.Record
+ committed.State, committed.ResultClaimGen = "committed", declared.Claim.Gen
+ if _, err := ReplaceLossRecord(ctx, s, sg, prepared, committed); err != nil {
+ t.Fatal(err)
+ }
+ // The operation owner hands execution to a new installation in the same
+ // operation, preserving the original declaration and writer provenance.
+ recoveryStamp := declared.Claim.Gen + 1
+ handover, err := Update(ctx, s, declared, func(c *Claim) error {
+ if c.Op.Kind != KindLanding || c.Op.Phase != "probe" || c.Op.Exec != "none" || !lossRefPresent(c, record.ID) {
+ return ErrWrongState
+ }
+ c.Op.Kind, c.Op.Phase, c.Op.Exec = KindRestoring, "restore", "recovery"
+ c.Op.Journal["recovery.loss"] = record.ID
+ c.Holder.Stamp = recoveryStamp
+ return nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ source := WritesLost{Box: "source", Generation: "g-source", Session: 2, RemoteMaxTXID: 10}
+ in := Admission{ObservedOpID: "move", ObservedPhase: "restore", ObservedSession: 4, ObservedGeneration: "g-target", Box: "recovery", Mode: "cold", NewGeneration: "g-recovery", Region: "ie", PredecessorRegion: "ie", RemoteMaxTXID: 12, AdditionalWritesLost: []WritesLost{source}}
+ validated := []ValidatedWriteSource{
+ {Reason: "target", Box: "target", Generation: "g-target", Session: 4, Region: "ie", Baseline: "target-snapshot", RemoteMaxTXID: 12},
+ {Reason: "source-cut", Box: "source", Generation: "g-source", Session: 2, Region: "ie", Baseline: "source-seal", RemoteMaxTXID: 10},
+ }
+ owner := lossRecoveryOwnerFunc(func(c Claim, loss LossRecord, a Admission) error {
+ if loss.OpKind != KindLanding || loss.OpPhase != "probe" || c.Op.Kind != KindRestoring || c.Op.Phase != "restore" ||
+ c.Op.Exec != "recovery" || a.Box != c.Op.Exec || c.Holder.Stamp != recoveryStamp ||
+ c.Op.Journal["recovery.loss"] != loss.ID || c.Op.Journal["loss."+loss.ID] != `{"kind":"lost-target"}` {
+ return ErrWrongState
+ }
+ // A policy callback cannot rewrite any input used by the admission.
+ c.Holder.Incarnation = "changed"
+ c.Op.Journal["recovery.loss"] = "changed"
+ loss.WriteSources[0].Baseline = "changed"
+ a.AdditionalWritesLost[0].RemoteMaxTXID = 999
+ return nil
+ })
+ if _, err := AdmitWriterWithLoss(ctx, s, pub, declared, in, record.ID, validated, owner); !errors.Is(err, ErrWrongState) {
+ t.Fatalf("admitted before handover: %v", err)
+ }
+ if _, err := AdmitWriterWithLoss(ctx, s, pub, handover, in, record.ID, validated, nil); !errors.Is(err, ErrLossOwnerRequired) {
+ t.Fatalf("admitted without owner: %v", err)
+ }
+ for name, mutate := range map[string]func(*Claim){
+ "kind": func(c *Claim) { c.Op.Kind = KindReverting },
+ "phase": func(c *Claim) { c.Op.Phase = "unauthorized" },
+ "executor": func(c *Claim) { c.Op.Exec = "other" },
+ "stamp": func(c *Claim) { c.Holder.Stamp++ },
+ "handover": func(c *Claim) { delete(c.Op.Journal, "recovery.loss") },
+ "intent": func(c *Claim) { delete(c.Op.Journal, "loss."+record.ID) },
+ "operation": func(c *Claim) { c.Op.ID = "other" },
+ "incarnation": func(c *Claim) { c.Holder.Incarnation = "other" },
+ "loss ref": func(c *Claim) { c.LossRefs = nil },
+ } {
+ t.Run(name, func(t *testing.T) {
+ candidate := handover
+ candidate.Claim, err = cloneClaim(handover.Claim)
+ if err != nil {
+ t.Fatal(err)
+ }
+ mutate(candidate.Claim)
+ if _, err := AdmitWriterWithLoss(ctx, s, pub, candidate, in, record.ID, validated, owner); err == nil {
+ t.Fatal("admitted with changed binding")
+ }
+ })
+ }
+ stale := in
+ stale.ObservedPhase = "probe"
+ if _, err := AdmitWriterWithLoss(ctx, s, pub, handover, stale, record.ID, validated, owner); !errors.Is(err, ErrWrongState) {
+ t.Fatalf("stale admission phase = %v", err)
+ }
+ fresh, err := Read(ctx, s, obs.Host)
+ if err != nil || fresh.ETag != handover.ETag {
+ t.Fatalf("refusal changed claim: %v", err)
+ }
+ admitted, err := AdmitWriterWithLoss(ctx, s, pub, handover, in, record.ID, validated, owner)
+ if err != nil {
+ t.Fatal(err)
+ }
+ last := admitted.Claim.Holder.Admissions[len(admitted.Claim.Holder.Admissions)-1]
+ if last.LossID != record.ID || last.WritesLost == nil || *last.WritesLost != (WritesLost{Box: "target", Generation: "g-target", Session: 4, RemoteMaxTXID: 12}) ||
+ !reflect.DeepEqual(last.AdditionalWritesLost, []WritesLost{source}) || admitted.Claim.Holder.WriterBox != "recovery" ||
+ admitted.Claim.Op.ID != record.OpID || admitted.Claim.Op.Kind != KindRestoring || admitted.Claim.Op.Phase != "restore" ||
+ admitted.Claim.Holder.Incarnation != record.HolderIncarnation || admitted.Claim.Op.Journal["recovery.loss"] != record.ID {
+ t.Fatalf("recovery admission = %+v", admitted.Claim)
+ }
+ frozen, err := ReadLossRecord(ctx, s, pub, record.ID)
+ if err != nil || !reflect.DeepEqual(frozen.Record, committed) {
+ t.Fatalf("recovery rewrote frozen declaration: %+v, %v", frozen.Record, err)
+ }
+}
+
func TestLegacyLossWithoutDeclarationRetainsEvidence(t *testing.T) {
a := AdmissionRecord{Region: "ie", Session: 3, WritesLost: &WritesLost{Box: "legacy", Session: 0}}
if !validWriteLosses(a.WritesLost, nil) {
@@ -1184,7 +1333,19 @@ type ValidatedWriteSource struct {
RemoteMaxTXID uint64
}
-func AdmitWriterWithLoss(ctx context.Context, s release.Store, pub ed25519.PublicKey, observed Observed, in Admission, lossID string, validated []ValidatedWriteSource) (Observed, error) {
+// LossRecoveryOwner validates the operation's persisted recovery handover
+// against the original declaration and the requested admission. It must check
+// the legal kind/phase transition, recovery intent, executor and installation
+// stamp. The library retains incarnation, operation and frozen-loss bindings;
+// it cannot infer the moves owner's legal recovery path. Inputs are copies.
+type LossRecoveryOwner interface {
+ ValidateLossRecovery(Claim, LossRecord, Admission) error
+}
+
+func AdmitWriterWithLoss(ctx context.Context, s release.Store, pub ed25519.PublicKey, observed Observed, in Admission, lossID string, validated []ValidatedWriteSource, owner LossRecoveryOwner) (Observed, error) {
+ if owner == nil {
+ return Observed{}, ErrLossOwnerRequired
+ }
if observed.Absent || observed.Claim == nil || observed.Claim.Holder == nil || !lossRefPresent(observed.Claim, lossID) {
return Observed{}, ErrLossRecord
}
@@ -1201,7 +1362,7 @@ func AdmitWriterWithLoss(ctx context.Context, s release.Store, pub ed25519.Publi
return Observed{}, err
}
if loss.Record.State != "committed" || loss.Record.Host != observed.Host || loss.Record.HolderIncarnation != observed.Claim.Holder.Incarnation ||
- loss.Record.OpID != observed.Claim.Op.ID || loss.Record.OpKind != observed.Claim.Op.Kind || loss.Record.OpPhase != observed.Claim.Op.Phase {
+ loss.Record.OpID == "" || loss.Record.OpID != observed.Claim.Op.ID {
return Observed{}, ErrLossRecord
}
if in.Mode != "cold" || in.PredecessorCertified || in.Coverage != "" {
@@ -1257,6 +1418,25 @@ func AdmitWriterWithLoss(ctx context.Context, s release.Store, pub ed25519.Publi
return Observed{}, fmt.Errorf("%w: declared remote maximum differs from its validated baseline", ErrLossRecord)
}
}
+ // Owner policy may inspect detached inputs but cannot alter the claim,
+ // frozen declaration or the admission that passed the evidence checks.
+ policy := struct {
+ Claim Claim
+ Loss LossRecord
+ Admission Admission
+ }{*observed.Claim, loss.Record, in}
+ wire, err := json.Marshal(policy)
+ if err != nil {
+ return Observed{}, err
+ }
+ // Clear shared maps, slices and pointers before decoding the copies.
+ policy.Claim, policy.Loss, policy.Admission = Claim{}, LossRecord{}, Admission{}
+ if err := json.Unmarshal(wire, &policy); err != nil {
+ return Observed{}, err
+ }
+ if err := owner.ValidateLossRecovery(policy.Claim, policy.Loss, policy.Admission); err != nil {
+ return Observed{}, err
+ }
in.LossID, in.lossVerified = lossID, true
return Update(ctx, s, observed, AdmitWriter(in))
}
@@ -5507,6 +5687,11 @@ The proposed answers live in **§7.3/§10.1** and **amadan #236**. They are not
## Self-review
+Rev 5 answers review round 4:
+
+- **P2 — recovery after declaration:** `AdmitWriterWithLoss` requires a `LossRecoveryOwner` to validate the legal recovery handover, executor, stamp and persisted intent. It retains the declaration’s host, incarnation, nonempty operation ID and complete frozen-loss bindings without requiring the recovery kind/phase to equal the declaration’s original state. The callback receives detached copies; native admission still checks the current executor, observed phase, session and generation under the claim CAS. `TestLossDeclarationHandoverAdmission` prepares and commits a real loss declaration in `landing/probe`, hands execution to `restoring/restore` in the same operation, and admits the recovery writer with the original target and source-cut losses. It refuses missing owners, unauthorized kind/phase/executor/stamp/intent, missing handover evidence, changed incarnation/operation/reference and stale admission phase; callback mutations cannot change the admission or signed declaration.
+- **P3 — r713 formatting:** the `generation.go` patch is regenerated against pushed r713 `f0127321` from gofmt output, including the inserted `LossID` field’s alignment. The applied result is checked with `gofmt -l .` before the compile gate.
+
Rev 4 answers review round 3:
- **P1 — blocked startup persistence:** `Open` starts cleanup with an independent context immediately after acquiring controller exclusion, before opening or writing local state. It retains exclusion until cleanup joins, including failed and cancelled startup. `TestOpenBlockedPendingPersistenceStillCleansBeforeReleasingExclusion` blocks the pending file’s fsync indefinitely behind a test barrier, cancels the opener and verifies that the orphaned host process exits before that barrier is released. It checks exclusion while fsync is blocked and again after fsync returns while cleanup is still joining. The returned-`ENOSPC` regression remains covered.
@@ -5528,6 +5713,16 @@ The live-lock probe must run inside `Guard.With`, as does the lifetime-lock prob
## Authoring verification
+Rev 5 was verified on 2026-10-06 in a disposable on-disk export of pinned boxguard `8c40aca61d6b25ea5e936ffab171d237f1b13483`, the disjoint main changes at `562f3dfcb4934c0dec027f730e34bbff08bbbd15`, and pushed r713 `f0127321eb97acae7b529eb993910873a720d14d`. The r713 changes were applied from its merge base with boxguard, `47426cc18a85847db7038dc3c428ead34dbef5d3`, including both r713 commits. This check uses committed source, replacing rev 4’s local-snapshot qualification.
+
+- The complete `hostclaim` suite passed with `-race -count=1`, including declaration → handover → admission, owner-policy refusals and isolation, and all prior frozen-loss tests. An isolated Go overlay restored the original kind/phase equality check; the new regression failed because that check refused the post-handover admission. The verified source was unchanged by this negative check.
+- Whole-repository builds passed for Linux/amd64, Darwin/amd64, Windows/amd64 and Linux/arm64. `go test -buildvcs=false -exec=/bin/true ./...` compiled every test package; the full repository test suite was not executed.
+- Whole-repository `go vet -buildvcs=false ./...` passed and `gofmt -l .` was empty. Both exact patches were independently applied to the committed baseline blobs and matched the verified source byte for byte. All 33 embedded files matched that source. The plan’s `git diff --check` passed.
+- The default Go cache was attempted first and refused writes in this sandbox. Verification then used the existing shared on-disk `/home/paulca/.cache/tmp/gocache`.
+- The Opus authority-review attempt timed out after 45 seconds without a verdict. That review remains outstanding before implementation lands.
+
+The rev 4 results below are historical.
+
Rev 4 was verified on 2026-10-06 in a disposable on-disk export of the pinned boxguard/main baseline plus the local r713 native-field snapshot. No remote `origin/feat/hostclaim-r713` ref was available locally, and network restrictions prevented checking the server. The local branch’s committed tip (`47426cc1`) still predated the new fields; snapshots of `claim.go`, `generation.go`, `generation_test.go` and `rev713_test.go` supplied the in-progress API. The `claim.go` snapshot’s SHA-256 was `8394a78337bf51d4ee7837e85515756857872f507d8c034c7014ab228d5933be`; `generation.go` was `03e5cbdb3446d20afbf9f108d82cdc06c14bd8589d0e55aef018c2ac5b0a66b2`. Recheck the exact patch against the pushed r713 tip before implementation.
- The complete `hostclaim` and `hostexec` suites passed with `-race -count=1`, including r713’s native additional-loss tests, blocked startup persistence, multiple target sessions and omission refusal. The new regressions were watched to fail after restoring the old `Open` and `AdmitWriterWithLoss`, then the fixed files were restored and both complete suites passed again.