carlos / platform Public

hostclaim: Commit follows probed only (Plan 3 Task 7, platform-1e m-2)

A commit from probing is refused and leaves the claim untouched, so
Group D's adjacent-step rule (probing, probed, committed) holds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev c327cfacd0f345ae4f17396edefde265c21a97c8 parent fa2f5ab
3 files changed, +33 −4
  • internal/hostclaim/move.go +7 −3
  • internal/hostclaim/move_commit_m2_test.go +25 −0
  • internal/hostclaim/move_test.go +1 −1
diff --git a/internal/hostclaim/move.go b/internal/hostclaim/move.go
index 4215bfcec..b05bf963e 100644
--- a/internal/hostclaim/move.go
+++ b/internal/hostclaim/move.go
@@ -581,8 +581,9 @@ func CompleteLocalPark(opID, box string, earlierStamp uint64) func(*Claim) error
// admission records. holder.stamp, session and generation are not touched
// (R10-3, H3).
//
-// Idempotent under the op: a landing already committed returns nil and queues
-// nothing. A refused commit leaves the claim as it found it.
+// It follows probed only (platform-1e m-2). Idempotent under the op: a
+// landing already committed returns nil and queues nothing. A refused commit
+// leaves the claim as it found it.
func Commit(opID, sourceRegion, sourceBox, targetRegion string, sourceScope, stagingScope ParkScope, newID func() string) func(*Claim) error {
return func(c *Claim) error {
if err := RequireOp(opID)(c); err != nil {
@@ -594,7 +595,10 @@ func Commit(opID, sourceRegion, sourceBox, targetRegion string, sourceScope, sta
if c.Op.Phase == PhaseCommitted {
return nil
}
- if c.Op.Phase != "probing" && c.Op.Phase != "probed" {
+ // The commit follows probed only (platform-1e m-2): with Group D's
+ // adjacent-step rule (probing, probed, committed) the admitted
+ // session survives it.
+ if c.Op.Phase != PhaseLandingProbed {
return fmt.Errorf("%w: phase %q", ErrWrongState, c.Op.Phase)
}
if len(c.Op.Participants) != 2 || c.Op.Exec != c.Op.Participants[1] {
diff --git a/internal/hostclaim/move_commit_m2_test.go b/internal/hostclaim/move_commit_m2_test.go
new file mode 100644
index 000000000..6bea518dc
--- /dev/null
+++ b/internal/hostclaim/move_commit_m2_test.go
@@ -0,0 +1,25 @@
+package hostclaim
+
+import (
+ "errors"
+ "testing"
+)
+
+// m-2 (platform-1e; moves Plan 3 Task 7): the commit follows probed only, so
+// Group D's adjacent-step rule (probing, probed, committed) holds. A commit
+// from probing is refused and leaves the claim as it found it.
+func TestCommitAcceptsOnlyProbed(t *testing.T) {
+ c := probedLanding(t)
+ c.Op.Phase = "probing"
+ before := string(mustJSON(t, c))
+ src, stg := commitScopes(c)
+ if err := Commit(moveA, "ie", "ie-box", "uk", src, stg, counter())(c); !errors.Is(err, ErrWrongState) || string(mustJSON(t, c)) != before {
+ t.Fatalf("a commit from probing: %v", err)
+ }
+ c = probedLanding(t)
+ c.Op.Phase = "probed"
+ src, stg = commitScopes(c)
+ if err := KeepWriterSession(moveA, Commit(moveA, "ie", "ie-box", "uk", src, stg, counter()))(c); err != nil || c.Op.Phase != PhaseCommitted {
+ t.Fatalf("a commit from probed under the session guard: %v %+v", err, c.Op)
+ }
+}
diff --git a/internal/hostclaim/move_test.go b/internal/hostclaim/move_test.go
index 465dff847..2c6f6777b 100644
--- a/internal/hostclaim/move_test.go
+++ b/internal/hostclaim/move_test.go
@@ -1193,7 +1193,7 @@ func obligationKinds(c *Claim) map[string]int {
// wCommitCoverage, wCommitReplayed, H3, H5(b).
func TestCommitQueuesObligationsAndCoversTheSourceRegion(t *testing.T) {
- for _, from := range []string{"probing", "probed"} {
+ for _, from := range []string{"probed"} {
c := probedLanding(t)
c.Op.Phase = from
// The source box holds paths of the stay the move leaves: stamp S = 3.