carlos / platform Public

moves: only the claim's admission is evidence the target admitted (Task 9a fix round 4)

targetAdmitted also counted a landing that reached probing. The record
enters probing (movesland.go) before the probe runs (moveslandprobe.go),
so a landing that crashed or failed at probing before its admission, then
rolled back dirty, was taken as admitted: its return parked the source's
live pre-move generation and the real view refused it for ever.

Admission evidence is now only the claim holder's admission of the move's
prepared generation (an admission appends it atomically and
ReturnToSource keeps it). The landing phase is not consulted.

Test: TestDirtyReturnAtProbingWithoutAdmissionKeepsTheResidue (the record
at probing, the holder with no admission: the return journals the no-op,
keeps the pre-move bytes and completes its install). RED: "park generation
cur: park: unsafe or incomplete input".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 7f512dd0de0d1e330c2d2b07219ce93f54ceff5f parent 854597a
2 files changed, +46 −17
  • internal/host/movesfileslive_test.go +33 −0
  • internal/host/movesinstall.go +13 −17
diff --git a/internal/host/movesfileslive_test.go b/internal/host/movesfileslive_test.go
index 97d4cc0a1..9885ddd8b 100644
--- a/internal/host/movesfileslive_test.go
+++ b/internal/host/movesfileslive_test.go
@@ -575,3 +575,36 @@ func TestReturnResidueParkWaitsOnATransientRefusal(t *testing.T) {
}
}
}
+
+// TestDirtyReturnAtProbingWithoutAdmissionKeepsTheResidue (fix round 4): the
+// record enters probing before the probe runs (movesland.go), so a landing
+// that crashed or failed at probing before its admission and was then
+// rolled back dirty is not evidence that the target admitted. With the
+// holder holding no admission of the move's generation, the return keeps
+// the pre-move generation and completes.
+func TestDirtyReturnAtProbingWithoutAdmissionKeepsTheResidue(t *testing.T) {
+ h := newReturnHarnessWith(t, false, false)
+ if _, err := provision.SetRecordMove(context.Background(), h.s, "bab", "app", p1Host, func(rec *provision.Record) error {
+ rec.Move.LandingPhase = provision.LandProbing
+ return nil
+ }); err != nil {
+ t.Fatal(err)
+ }
+ location := strings.TrimSuffix(h.claim(t).Holder.Location, "/")
+ pre := returnPreMove(t, h, location)
+ h.rcfg.ParkView = movesParkView(MovesRecordsFrom(h.s), h.vs, "data-ie", "ie")
+ if _, err := h.install(t); err != nil {
+ t.Fatalf("the return at probing without an admission: %v", err)
+ }
+ if rb := h.read(t, p1Host).Move.Rollback; rb.SourcePhase != provision.RbSourceRestored {
+ t.Fatalf("the return did not complete its install: %+v", rb)
+ }
+ for k, body := range pre {
+ if got, ok := h.f.buckets["data-ie"][k]; !ok || got.body != body {
+ t.Fatalf("%s changed", k)
+ }
+ }
+ if got := h.returnJournal(t).Steps[installStepResidueKept]; !strings.Contains(got, "never admitted") {
+ t.Fatalf("the journal's no-op line: %q", got)
+ }
+}
diff --git a/internal/host/movesinstall.go b/internal/host/movesinstall.go
index 6ff345b81..dc2d0bcf3 100644
--- a/internal/host/movesinstall.go
+++ b/internal/host/movesinstall.go
@@ -404,9 +404,10 @@ func (ir *installRun) parking(ctx context.Context) (bool, error) {
// A dirty return whose target never admitted this move (ruling
// (a), fix round 3): holder.generation is still the pre-move one,
// the source's live state, so there is no residue to park. This
- // is decided from recorded evidence only, never from a park view's
+ // is decided from the claim's recorded admissions only (fix round
+ // 4: not the landing phase), never from a park view's
// refusal, which can be transient.
- why := fmt.Sprintf("the target never admitted move %s: no probe ran and the claim holds no admission of its generation; the pre-move generation stays the source's live state", id)
+ why := fmt.Sprintf("the target never admitted move %s: the claim holds no admission of its generation; the pre-move generation stays the source's live state", id)
j.Phase = phase
j.Mark(landStepResidue, "[]")
j.Mark(installStepResidueKept, why)
@@ -512,24 +513,19 @@ func (ir *installRun) parking(ctx context.Context) (bool, error) {
return ir.advance(ctx, phase, next, installStamp{})
}
-// targetAdmitted reports whether the record or the claim carries evidence
-// that the move's target admitted a writer (fix round 3): the record's
-// landing reached probing, whose probe is the target's only admission, or
-// the holder's admissions include the move's prepared generation. Without
-// either, nothing of the target's ever became holder.generation.
+// targetAdmitted reports whether the claim carries evidence that the
+// move's target admitted a writer: the holder's admissions include the
+// move's prepared generation (an admission appends its record atomically,
+// and ReturnToSource keeps them). The record's landing phase is not
+// evidence: it enters probing before the probe runs (fix round 4), so a
+// landing that stopped at probing before its admission never admitted.
func targetAdmitted(m *provision.MoveState, c *hostclaim.Claim) bool {
- if m == nil {
+ if m == nil || c == nil || c.Holder == nil {
return false
}
- order := provision.LandingOrder()
- if landingIndex(order, m.LandingPhase) >= landingIndex(order, provision.LandProbing) {
- return true
- }
- if c != nil && c.Holder != nil {
- for _, a := range c.Holder.Admissions {
- if a.Generation == m.ID {
- return true
- }
+ for _, a := range c.Holder.Admissions {
+ if a.Generation == m.ID {
+ return true
}
}
return false