carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

Moves Phase 1, Plan 3: Probe, Commit and Open Implementation Plan

> For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking. Tasks 5, 6 and 7 need claim Plan 6 (feat/hostclaim-box) merged; build Tasks 1 to 4 and 8 first.

Goal: Prove the target can run the instance (the probe as a cold admission into the prepared generation, within the budgeted attempts and the cut deadline), commit by one record CAS, let the claim follow with its obligations, open the target row, and park the source.

Architecture: The probe policy is pure (internal/moves/probe.go): attempt windows, the retry backoff, deadline checks before the start and before readiness. activator.ProbeWake runs claim Plan 6's admitted-writer start sequence for a held row with that policy, spawning strictly with CARLOS_MOVE_PROBE=1 and requiring the readiness answer from the spawned tree. The commit is provision.MoveCommit conditional on now ≤ cut_deadline, then hostclaim.Commit queues a location park-replica for the source and a lane park-replica for the target and covers the source region's predecessors. The open is registry.ReleaseHold. The source's finalization retires its installation under the host guard and records source_parked_at.

Tech Stack: Go, internal/hostbox (claim Plan 6), internal/hostclaim, internal/genselect, internal/park, internal/hostguard, unix sockets with SO_PEERCRED (golang.org/x/sys/unix), cgroup v2.

Spec: rev 7.18 §5.1 (the start check, step 9), §7.5, §7.7, §7.9, §7.13, §7.14, §19.2 K6, K8. Index: 2026-10-06-moves-phase1-0-index.md. Plans 1 and 2 merged.

Global Constraints

  • Gate before every commit (AGENTS.md); cross-compile; sandboxed GOCACHE. Tests serial and niced. SO_PEERCRED code is //go:build linux with a !linux stub.
  • One attempt is one cold admission; its app may restart under the retry policy (doubling backoff from 1 s, five starts) within the attempt's 30 s readiness window; the deadline is checked before each start and before readiness is accepted (§7.7, R12-2; TestProbeWindow).
  • A landing has at most three attempts and never more than T11 admitted; a probe never marks the host failed (§7.7).
  • The commit is a record CAS conditional on now ≤ cut_deadline; the claim follows unconditionally; holder.generation is never written by the commit (R10-3).
  • The open is the conditional ReleaseHold(host, moveID); the target serves on the session its probe was admitted with; nothing rolls back after a commit.
  • Cold only (P7, index D14): every probe and every wake after the open is a cold admission; nothing here reads a certificate. The switch (D13) gates the probe and the open.
  • No em dashes.

Review Focus

  1. A probe attempt whose readiness arrives exactly at the window's end must fail; one at 29 s must pass; one whose environment becomes ready only after the window must not start the app (R12-2). Test in Task 1 (TestProbeWindow, ported).
  2. A commit attempted one second after cut_deadline must lose and the move must roll back, even if the probe passed (§7.4, INV-9). Test in Task 2 (TestCommitRefusedPastTheDeadline).
  3. A target agent that crashes after the commit record CAS and before the claim CAS must, on restart, write the claim half and open, not probe again (witness wCommitInterrupted). Test in Task 3 and Task 7 (TestCommitClaimHalfReplayed, TestOpenAfterCrashDoesNotReprobe).
  4. A readiness answer from a process outside the host's cgroup (another local service on the same path) must be refused (§7.7, SO_PEERCRED). Test in Task 5 (TestProbeRefusesForeignPeer).
  5. The source must never park its installation until the record says committed, and never while its own hold_op is not the move's (a late finalization from an aborted move). Test in Task 8 (TestSourceParkWaitsForCommit).

---

File structure

| path | responsibility | |---|---| | internal/moves/probe.go | attempt policy and deadlines | | internal/moves/startcheck.go | the start check over the three markers and the claim | | internal/provision/provision.go | MoveCommit, MoveOpened, MoveSourceParked, MoveProbeAttempt | | internal/hostclaim/move.go | Commit | | internal/activator/probewake.go, peercred_linux.go, peercred_other.go | ProbeWake | | internal/host/movesland.go | probing, probed, commit, open | | internal/host/movesfinal.go | the source's finalization park | | internal/registry/registry.go | DeleteIfHold |

---

Task 1: The probe policy

Files: create internal/moves/probe.go, internal/moves/probe_test.go.

Interfaces:

  • moves.ProbeWindow = 30 * time.Second, ProbeSettle = 20 * time.Second, ProbeMaxStarts = 5, LandingAttempts = 3, RecoveryAttempts = 9; moves.Backoff(start int) time.Duration (1 s, 2 s, 4 s, 8 s before starts 2 to 5; 0 before the first); moves.ProbeAttempt{Index int; Opened time.Time; Starts int}; (a *ProbeAttempt) Deadline() time.Time (Opened + ProbeWindow); (a *ProbeAttempt) MayStart(now, cutDeadline time.Time) error (ErrAttemptOver when now >= Deadline() or now > cutDeadline or Starts >= ProbeMaxStarts); (a *ProbeAttempt) AcceptReadiness(answeredAt, cutDeadline time.Time) error (ErrAttemptOver when answeredAt >= Deadline() or answeredAt > cutDeadline); moves.AttemptsFor(kind string, admitted int) int (landing: min(3, admitted); recovery: 9).
  • [ ] Step 1: Write the failing test (port TestProbeWindow from internal/sim/hostlife/witness_test.go:3459 and wProbeWindowAt):
// Ported from the model's TestProbeWindow and wProbeWindowAt (R12-2,
// INV-19): readiness k seconds after the attempt's first start: 29 is
// accepted, 30 fails before the start, 31 fails at the deadline with the
// environment still unready.
func TestProbeWindow(t *testing.T) {
	t0 := time.Date(2026, 10, 6, 9, 0, 0, 0, time.UTC)
	far := t0.Add(time.Hour)
	for k, want := range map[int]bool{29: true, 30: false, 31: false} {
		a := &ProbeAttempt{Index: 1, Opened: t0}
		if err := a.MayStart(t0, far); err != nil {
			t.Fatal(err)
		}
		a.Starts++
		err := a.AcceptReadiness(t0.Add(time.Duration(k)*time.Second), far)
		if (err == nil) != want {
			t.Fatalf("k=%d: %v", k, err)
		}
	}
	// The environment becomes ready after the window: no start at all.
	a := &ProbeAttempt{Index: 1, Opened: t0}
	if err := a.MayStart(t0.Add(ProbeWindow), far); !errors.Is(err, ErrAttemptOver) {
		t.Fatalf("start after the window: %v", err)
	}
	// Five starts, then the attempt is over whatever the clock says.
	b := &ProbeAttempt{Index: 1, Opened: t0, Starts: 5}
	if err := b.MayStart(t0.Add(time.Second), far); !errors.Is(err, ErrAttemptOver) {
		t.Fatal("sixth start")
	}
	// The absolute cut deadline bounds the whole.
	c := &ProbeAttempt{Index: 1, Opened: t0}
	if err := c.AcceptReadiness(t0.Add(5*time.Second), t0.Add(4*time.Second)); !errors.Is(err, ErrAttemptOver) {
		t.Fatal("readiness past the cut deadline")
	}
	if Backoff(1) != 0 || Backoff(2) != time.Second || Backoff(5) != 8*time.Second {
		t.Fatal("backoff")
	}
	if AttemptsFor("landing", 2) != 2 || AttemptsFor("landing", 7) != 3 || AttemptsFor("recovery", 0) != 9 {
		t.Fatal("attempts")
	}
}
  • [ ] Step 2: Run, Step 3: implement per the interface (straightforward arithmetic; ErrAttemptOver = errors.New("moves: probe attempt window or deadline expired"), already on main at d649d8d4 in internal/moves/install_contract.go (claim Plan 6): this task imports it and does not redefine it; every consumer uses errors.Is, so only the identity matters), Step 4: run nice -n 10 go test ./internal/moves -run TestProbeWindow -count=1 → PASS.
  • [ ] Step 5: Commit: git commit -m "moves: the probe attempt policy, ported from the model (§7.7, R12-2)" ...

---

Task 2: Record transitions for commit, open and the source park

Files: modify internal/provision/provision.go, test internal/provision/move_test.go.

Interfaces:

  • MoveProbeAttempt(g MoveGuard, n int) (state landing, phase probing; records Landing.Attempts = n on the MoveLandingJournal, Plan 1 Task 2); MoveCommit(g, now time.Time) func(*Record) error (landing/probed, now <= *CutDeadline, else ErrMoveConflict wrapping ErrCutDeadline; sets State = committed, CommittedAt); MoveOpened(g, now) (committed, OpenedAt); MoveSourceParked(g, now) (committed, SourceParkedAt); MoveClose(g, now time.Time) (committed with OpenedAt and SourceParkedAt set → Move = nil, region already To, and rec.LastMove = &MoveOutcome{ID: g.ID, Outcome: "done", At: now, OfflineS: OpenedAt - CutAt} in the same write, index D11; Plan 5 calls it when both obligations are gone).
  • [ ] Step 1: Write the failing test
func TestCommitRefusedPastTheDeadline(t *testing.T) {
	g := MoveGuard{ID: "mv_abcdefghijklmnopqrstuvwxyz", Incarnation: strings.Repeat("ab", 32)}
	now := time.Date(2026, 10, 6, 9, 0, 0, 0, time.UTC)
	dl := now.Add(115 * time.Second)
	rec := &Record{Region: "uk", Move: &MoveState{ID: g.ID, Incarnation: g.Incarnation, From: "ie", To: "uk", State: MoveLanding, LandingPhase: LandProbed, CutDeadline: &dl}}
	if err := MoveCommit(g, dl.Add(time.Second))(rec); !errors.Is(err, ErrCutDeadline) || rec.Move.State != MoveLanding {
		t.Fatalf("late commit: %v %s", err, rec.Move.State)
	}
	if err := MoveCommit(g, dl)(rec); err != nil || rec.Move.State != MoveCommitted || rec.Move.CommittedAt == nil {
		t.Fatalf("commit at the deadline: %v", err)
	}
	if err := MoveCommit(g, dl)(rec); !errors.Is(err, ErrMoveConflict) {
		t.Fatal("second commit")
	}
	if err := MoveClose(g, now)(rec); !errors.Is(err, ErrMoveConflict) {
		t.Fatal("close before open and park")
	}
	if err := MoveOpened(g, now)(rec); err != nil || rec.Move.OpenedAt == nil {
		t.Fatal(err)
	}
	if err := MoveSourceParked(g, now)(rec); err != nil {
		t.Fatal(err)
	}
	if err := MoveClose(g, now)(rec); err != nil || rec.Move != nil || rec.Region != "uk" || rec.LastMove == nil || rec.LastMove.ID != g.ID || rec.LastMove.Outcome != "done" {
		t.Fatalf("close: %v %+v", err, rec)
	}
}
  • [ ] Step 2: Run, Step 3: implement:
// ErrCutDeadline is a commit attempted after cut_deadline (§7.4): the
// record CAS is the decision, so the deadline cannot be passed between the
// record write and the claim write.
var ErrCutDeadline = fmt.Errorf("%w: the cut deadline has passed", ErrMoveConflict)

func MoveCommit(g MoveGuard, now time.Time) func(*Record) error {
	return func(rec *Record) error {
		if err := g.check(rec); err != nil {
			return err
		}
		if rec.Move.State != MoveLanding || rec.Move.LandingPhase != LandProbed {
			return fmt.Errorf("%w: commit follows probed", ErrMoveConflict)
		}
		if rec.Move.CutDeadline == nil || now.After(*rec.Move.CutDeadline) {
			return ErrCutDeadline
		}
		t := now.UTC()
		rec.Move.State, rec.Move.CommittedAt = MoveCommitted, &t
		return nil
	}
}

with MoveOpened, MoveSourceParked, MoveClose, MoveProbeAttempt in the same style.

  • [ ] Step 4: Run → PASS. Step 5: Commit: git commit -m "provision: commit conditional on the cut deadline, open, source park, close (§7.9)" ...

---

Task 3: hostclaim.Commit

Files: modify internal/hostclaim/move.go, test internal/hostclaim/move_test.go.

Interfaces:

  • hostclaim.Commit(opID, sourceRegion, sourceBox, targetRegion string, sourceScope, stagingScope ParkScope, newID func() string) func(*Claim) error: requires KindLanding with phase probing or probed and Exec == participants[1]; sets phase "committed"; appends location park-replica for sourceRegion with sourceScope (owner region:<source>), park-local for sourceBox, lane park-replica for targetRegion with stagingScope; runs CoverRegionPredecessors(opID, "committed", sourceRegion); idempotent: a claim already at committed under this op returns nil with no second set of obligations (witness wCommitReplayed). holder.generation untouched.
  • PhaseCommitted = "committed".
  • [ ] Step 1: Write the failing test (witnesses wCommitCoverage, wCommitInterrupted, wCommitReplayed):
func TestCommitQueuesObligationsAndCoversTheSourceRegion(t *testing.T) {
	c := movingTestClaim()
	op := "mv_abcdefghijklmnopqrstuvwxyz"
	_ = BeginMove(op, "ops", "ie-box", "uk-box", "uk", time.Now())(c)
	_ = ExecToNone(op, "ie-box", "ev", JournalEvidenceSource)(c)
	_ = SetMovePhase(op, KindMoving, PhaseMoving, PhaseSealed)(c)
	c.Gen = 7
	_ = Flip(op, "uk-box", 3, "")(c)
	// The landing mirrors every record phase into the claim (Plan 2 Task
	// 10), so the claim reaches probed through SetMovePhase, never a
	// fixture edit.
	for _, step := range [][2]string{{"checking", "parking"}, {"parking", "building"}, {"building", "published"}, {"published", "local"}, {"local", "configured"}, {"configured", "restored"}, {"restored", "probing"}, {"probing", "probed"}} {
		if err := SetMovePhase(op, KindLanding, step[0], step[1])(c); err != nil {
			t.Fatal(err)
		}
	}
	// The target's probe admission left a record whose predecessor is in ie.
	c.Holder.Generation = op
	c.Holder.Admissions = []AdmissionRecord{{Region: "uk", PredecessorRegion: "ie", Session: 9, Box: "uk-box", Generation: op, Predecessor: "", Mode: "cold", Coverage: "sealed"}}
	ids := 0
	newID := func() string { ids++; return fmt.Sprintf("id%d", ids) }
	src := ParkScope{Location: "instances/a.go.example.com/" + c.Holder.Incarnation, Incarnation: c.Holder.Incarnation, EvidenceAt: time.Now(), RequestLimit: 120 * time.Second}
	stg := ParkScope{Location: "moves/a.go.example.com/" + op, Incarnation: c.Holder.Incarnation, EvidenceAt: time.Now(), RequestLimit: 120 * time.Second}
	if err := Commit(op, "ie", "ie-box", "uk", src, stg, newID)(c); err != nil {
		t.Fatal(err)
	}
	if c.Op.Kind != KindLanding || c.Op.Phase != PhaseCommitted || c.Op.Exec != "uk-box" || c.Holder.Generation != op {
		t.Fatalf("after commit: %+v gen %q", c.Op, c.Holder.Generation)
	}
	kinds := map[string]int{}
	for _, o := range c.Obligations {
		kinds[o.Kind+"/"+o.Region+o.Box]++
	}
	if kinds["park-replica/ie"] != 1 || kinds["park-local/ie-box"] != 1 || kinds["park-replica/uk"] != 1 || len(c.Obligations) != 3 {
		t.Fatalf("obligations: %+v", c.Obligations)
	}
	if !c.Holder.Admissions[0].Covered {
		t.Fatal("the source-region predecessor is not covered (wCommitCoverage)")
	}
	// Replay: nothing doubles (wCommitReplayed).
	if err := Commit(op, "ie", "ie-box", "uk", src, stg, newID)(c); err != nil || len(c.Obligations) != 3 {
		t.Fatalf("replay: %v %d", err, len(c.Obligations))
	}
	// Not from moving.
	d := movingTestClaim()
	if err := Commit(op, "ie", "ie-box", "uk", src, stg, newID)(d); !errors.Is(err, ErrStaleOp) {
		t.Fatalf("commit on a serving claim: %v", err)
	}
}

(The exact Covered field name and CoverRegionPredecessors' semantics are generation.go's; adjust the assertion to the field it sets.)

  • [ ] Step 2: Run, Step 3: implement:
const PhaseCommitted = "committed"

// Commit is the claim half of the record's commit (§7.5, §7.9 step 1):
// phase committed plus, in the same write, a location park-replica for the
// source's location in its region and box, a lane park-replica for the target's
// staging, and CoverRegionPredecessors for the source region. It writes
// nothing into holder.generation (R10-3). Idempotent under the op.
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 {
			return err
		}
		if c.Op.Kind != KindLanding {
			return fmt.Errorf("%w: kind %q", ErrWrongState, c.Op.Kind)
		}
		if c.Op.Phase == PhaseCommitted {
			return nil
		}
		if c.Op.Phase != "probing" && c.Op.Phase != "probed" {
			return fmt.Errorf("%w: phase %q", ErrWrongState, c.Op.Phase)
		}
		if len(c.Op.Participants) != 2 || c.Op.Exec != c.Op.Participants[1] {
			return fmt.Errorf("%w: exec %q is not the target", ErrWrongState, c.Op.Exec)
		}
		if err := sourceScope.Validate(c.Host); err != nil {
			return err
		}
		if err := stagingScope.Validate(c.Host); err != nil {
			return err
		}
		c.Op.Phase = PhaseCommitted
		s, g := sourceScope, stagingScope
		c.Obligations = append(c.Obligations,
			Obligation{ID: newID(), Op: opID, Kind: "park-replica", Region: sourceRegion, Retirement: newID(), Owner: "region:" + sourceRegion, Park: &s},
			Obligation{ID: newID(), Op: opID, Kind: "park-local", Box: sourceBox, Retirement: newID(), Owner: "box:" + sourceBox},
			Obligation{ID: newID(), Op: opID, Kind: "park-replica", Region: targetRegion, Retirement: newID(), Owner: "region:" + targetRegion, Park: &g})
		return CoverRegionPredecessors(opID, PhaseCommitted, sourceRegion)(c)
	}
}
  • [ ] Step 4: Run → PASS. Step 5: Commit: git commit -m "hostclaim: Commit queues the source and staging parks and covers the source region (§7.9, K8 groundwork)" ...

---

Task 4: The start check

Files: create internal/moves/startcheck.go, internal/moves/startcheck_test.go.

Interfaces:

  • moves.GenerationMarker{Op, Incarnation, Host, Box string; InstalledAt time.Time; ManifestSHA256 string; SnapshotKey, SnapshotVersion string; SnapshotTXID, SnapshotCRC64 uint64} (the generation.json shape, genselect.Marker's fields); moves.FilesGen{Op, Incarnation string}; moves.DBGen{Op, Incarnation, Location string}; moves.PreparedCheck(prepared string, holder hostclaim.Holder, filesGen *FilesGen, dbGen *DBGen) error (the pre-admission validation of a landing probe's inputs: both markers name prepared and the holder's incarnation and location; Plan 3 Task 5 step 3); moves.StartCheck(c *hostclaim.Claim, marker *GenerationMarker, filesGen *FilesGen, dbGen *DBGen) error (the §5.1 start check against the claim after the admission CAS, Task 5 step 6) (§5.1 the start check: (1) marker absent = origin; its Op must be holder.generation or the predecessor of the latest admission or of a chain of admissions each without a marker (walk holder.admissions from the newest: a generation whose Predecessor matches is accepted); its Incarnation the holder's; (2) filesGen when present names the same generation and incarnation as the claim expects (holder.generation); (3) dbGen when present names the same generation and holder.location); errors ErrStartMarker, ErrStartFiles, ErrStartDB with member-safe reasons.
  • [ ] Step 1: Write the failing test: origin everywhere passes; marker naming the holder's generation passes; marker naming the predecessor of the latest admission passes (lagging); marker naming an unrelated generation refuses ErrStartMarker; .files-gen with another op refuses ErrStartFiles; <dbPath>.gen with another location refuses ErrStartDB.
  • [ ] Step 2: Run, Step 3: implement, Step 4: run → PASS.
  • [ ] Step 5: Commit: git commit -m "moves: the start check over the three markers and the claim (§5.1, INV-4)" ...

---

Task 5: ProbeWake (BLOCKED-ON-CLAIM: C1, C2)

Files: create internal/activator/probewake.go, internal/activator/peercred_linux.go, internal/activator/peercred_other.go, internal/activator/probewake_test.go.

Interfaces:

  • Consumes (claim Plan 6): hostbox.Writer (Baseline, Admit, Published), hostbox.GenerationPrefix, spawnClaimed(ctx, enabled, manager, host, limit, selected, identity, build) (*exec.Cmd, *cgroup.Prepared, error) (the *cgroup.Prepared is kept for the process's life and, on every exit path including a failed start, KillAndEmpty then Close run before the attempt is counted), and Plan 6 Task 9's admitted-start sequence exposed as (a *Service) startAdmitted(ctx, e *actEntry, admitted hostclaim.Observed, policy startPolicy) error (index: "exact interfaces needed"). Consumes genselect.SelectPrepared(ctx, s, req, genselect.PreparedPin{Generation, SnapshotKey, SnapshotVersion, SnapshotTXID, SnapshotCRC64}) to plan the prepared generation's restore from the install manifest.
  • Produces: activator.ProbeConfig{Host string; Op string (the claim's op id: the move id, in every kind); HoldOp string (the row's hold_op: the move id for a landing or revert, the rollback id for a rollback's source); PreparedGeneration string (the generation a prepared install produced and the admission opens: the move id for a landing, the rollback id for a dirty return, "" for a clean recovery into the source's own generation); Kind string ("landing" | "recovery"); Prepared *moves.InstallManifest (non-nil exactly when PreparedGeneration != ""); Seal *moves.Seal; Inputs *provision.MoveInputs (the pin a landing probe enforces at spawn; nil for a recovery probe, which records what it rendered); CutDeadline time.Time; Attempt *moves.ProbeAttempt (Index set by the caller; Opened written by the probe at the first app start); RenderHeld func(ctx) (appconfig.HeldRender, error); ReadyPath string; LossID string (empty except for a lost-target return, Plan 4 Task 10, where the admission goes through hostclaim.AdmitWriterWithLoss)}; activator.ProbeResult{Session uint64; Generation string; AnsweredAt time.Time}; (a *Service) ProbeWake(ctx, cfg ProbeConfig) (ProbeResult, error): 1. the row must be held with hold_op == cfg.HoldOp and the claim must name this box op.exec under op cfg.Op (K1, K6), else ErrProbeRefused; 2. render, err := cfg.RenderHeld(ctx) (the caller composes RenderHeld + MaterializeHeld; every probe kind, model 4); the launch-input pin, at spawn (§7.7, round-2 finding 14): for a landing probe (cfg.Inputs != nil) the rendered BundleETags and OverlayETag must equal cfg.Inputs', the materialized release must be cfg.Inputs.Release, and moves.ReportEnv(key, b.LaunchEnvironment(rt)).Digest must equal cfg.Inputs.EnvReport; a mismatch is ErrProbeFailed("configuration changed during the move") before any admission, and the landing rolls back; a recovery probe records what it rendered into Rollback.RecoveryInputs (through the caller's RecordInputs hook) and is bound to nothing (J2-R2-5). Plan 2's configured check stays as the early refusal; this one is the authoritative one, since the environment can change between the two; 3. prepared-input validation, before any admission, when cfg.PreparedGeneration != "" (a landing, or a dirty return): moves.PreparedCheck(cfg.PreparedGeneration, holder, filesGen, dbGen): .files-gen and <dbPath>.gen name that generation and the holder's incarnation and location, and cfg.Prepared exists with N == cfg.Seal.N. This is not the §5.1 start check against holder.generation: before the first probe's admission holder.generation is still the predecessor's (the source's after a flip, the target's after a dirty ReturnToSource, which deliberately keeps it, Plan 4 Task 2; only AdmitWriter moves it, generation.go:27), so a start check here would refuse the install's own files (round-2 finding 13). When cfg.PreparedGeneration == "" (a clean recovery or a revert), the markers, when present, must name holder.generation as observed; 4. cfg.Attempt.MayStart(now, cfg.CutDeadline) is checked with Opened unset (the window has not begun); the cut deadline alone applies here; 5. the admission: decide per §7.14: cold; NewGeneration = cfg.Op when holder.generation is neither cfg.Op nor a descendant admitted from it, else a fresh id (newID()); KeepStamp = holder.stamp > holder.session; Coverage = "sealed" when cfg.Seal != nil && cfg.Seal.FromDB and the generation is the prepared one, else ""; Region, PredecessorRegion per the last admission record; RemoteMaxTXID from the baseline plan (SelectPrepared for the prepared generation; Writer.Baseline for a fresh one); then Writer.Admit; 6. startAdmitted with startPolicy{MaxStarts: moves.ProbeMaxStarts, Window: moves.ProbeWindow, Deadline: cfg.CutDeadline, Probe: true, Prepared: cfg.Prepared} (C1): the sequence purges and restores before the window opens, then sets cfg.Attempt.Opened = now at the first app start and journals it (round-2 finding 19: the 30 s window is the app's, the restore is priced separately in T11); the §5.1 start check runs here, inside the admitted sequence, with moves.StartCheck(claimAfterCAS, marker, filesGen, dbGen) against the generation the admission CAS just named (holder.generation == cfg.Op for a first probe; a fresh id for a restarted one, whose .files-gen still names cfg.Op and is accepted through the admission chain: Task 4's StartCheck takes the claim and walks holder.admissions); the spawn goes through spawnClaimed with CARLOS_MOVE_PROBE=1 in the child's environment and is strict; 7. readiness: GET cfg.ReadyPath over the row's socket with Host: <host>, 200 to 399, the peer's SO_PEERCRED pid a member of carlos-exec@<host> (cgroup.Cleanup.Members), cfg.Attempt.AcceptReadiness(answeredAt, cfg.CutDeadline); a 20 s settle, the process still running, a second request; 8. the marker and publication are startAdmitted's (first upload, generation.json by If-Match or If-None-Match, Writer.Published); the entry stays held: RetireExcept keeps entries whose row IsHold. A failure after the admission stops the tree (FenceAndStop with a fresh generation) and returns ErrProbeFailed with the reason; the attempt is over; the operation decides what next.
  • peercred_linux.go: peerPID(conn net.Conn) (int, error) via unix.GetsockoptUcred; peercred_other.go returns ErrStopEvidenceUnsupported.

Tests: TestProbeRefusesUnheldRowOrForeignExec; TestFirstProbeFromTheSourceGenerationIsAdmitted (the claim as the flip left it: holder.generation is the source's "", .files-gen and <dbPath>.gen name the move id; the probe validates the prepared inputs, admits into the move id, and the start check after the CAS passes; a hand-built claim whose holder.generation is already the move id with a .files-gen naming another op refuses); TestProbeRendersBeforeStart (the RenderHeld hook is called before any spawn, model 4); TestProbeRefusesForeignPeer (Review Focus 4: a fake listener answering 200 from this test process, whose pid is not in the host cgroup → ErrProbeFailed naming the peer); TestProbeAttemptEndsAtTheWindow (the fake start answers at 31 s → ErrAttemptOver); TestProbeIsAColdAdmissionIntoThePreparedGeneration (with Plan 6's fake writer: Admit is called once with NewGeneration == op, Mode == "cold", Coverage == "sealed", before the spawn hook runs; a second attempt admits a fresh generation, KeepStamp false).

  • [ ] Steps 1 to 4: run nice -n 10 go test ./internal/activator -run TestProbe -count=1 → PASS. Cross-compile.
  • [ ] Step 5: Commit: git commit -m "activator: ProbeWake, a cold admission into the prepared generation with the attempt policy (§7.7, §7.14)" ...

---

Task 6: The landing's probing and probed (BLOCKED-ON-CLAIM: C1)

Files: modify internal/host/movesland.go, internal/host/movesland_test.go.

Interfaces:

  • moveCfg.Probe func(ctx, activator.ProbeConfig) (activator.ProbeResult, error); moveCfg.RenderAndMaterialize func(ctx, rt registry.Route, op, version string) (appconfig.HeldRender, error).
  • landingPass phases: restored → probing (MoveLandingPhase, then the claim's SetMovePhase(id, KindLanding, "restored", "probing"), Plan 2 Task 10's mirroring rule, so the admission's ObservedPhase is probing); in probing, attempts from the journal (Journal.Attempt): n = AttemptsFor("landing", targetReport.AttemptsAdmitted); for each attempt not yet recorded: MoveProbeAttempt(g, i) and journal Attempt = i before the call (the attempt is accounted here; its Opened is written by the probe at the first app start, Task 5 step 6, so the restore does not eat the window; a crash restarts only the probe, §7.13, and a journalled attempt with an Opened whose window passed counts as failed), cfg.Probe(...); success → MoveLandingPhase(probing → probed) then SetMovePhase(id, KindLanding, "probing", "probed"); ErrAttemptOver/ErrProbeFailed → next attempt, if any; attempts exhausted or cut_deadline passed → the rollback marker (Plan 4 Task 1's MoveRollBack; until it lands, markForRollback).
  • Tests: TestLandingProbesWithinTheBudget (two admitted attempts: the first fails, the second passes → probed; a third is never attempted); TestLandingProbeCrashRestartsOnlyTheProbe (a fresh worker on a journal at probing with Attempt = 1 does not rerun local or restored: their journal steps are untouched and no second .files-gen write happens); TestLandingExhaustedAttemptsMarkRollback.
  • [ ] Steps 1 to 5. Commit: git commit -m "host: the landing's probing and probed phases (§7.6, §7.7)" ...

---

Task 7: Commit and open on the target (BLOCKED-ON-CLAIM: C1, C2; Tasks 5 and 6 first)

Files: modify internal/host/movesland.go, internal/host/movesland_test.go; modify internal/registry/registry.go (DeleteIfHold).

Interfaces:

  • In landingPass, at probed: provision.SetRecordMove(MoveCommit(g, cfg.Now())); ErrCutDeadline → the rollback marker; success or an already-committed record → the claim half: hostclaim.Update(Commit(id, rec.Move.From, sourceBox, cfg.Region, sourceScope, stagingScope, newID)) where sourceScope = {Location: TrimSuffix(holder.location, "/"), Incarnation, EvidenceAt: the cut's stop evidence time (stopped-source.json's CheckedAt), RequestLimit: 120 s} and stagingScope = {Location: moves.ScopeLocation(host, id), Incarnation, EvidenceAt: seal.Bound(), RequestLimit: 120 s} (the staging lane's own seal bound, claim rev 6.23; Plan 5 Task 3 proves the deadline); the claim half is written by whoever sees the record ahead (§7.5): this pass, or the console's pass (Plan 5).
  • The open: cfg.ReleaseHold(host, id) (registry.ReleaseHold); changed == false with the row already ready and hold_op == "" is a replay and fine; MoveOpened(g, now); nudgeSerial; the activator's entry from the probe is the serving process: no restart.
  • registry.DeleteIfHold is Plan 1 Task 12's (D12); Task 8 uses it without depending on this task.

Tests: TestCommitThenOpenInOrder (witness wCommitBeforeOpen: driven from the flip through every landing phase with the real transitions, no fixture phase edits; the row is ready only after the record says committed and the claim says committed); TestOpenAfterCrashDoesNotReprobe (Review Focus 3: a worker restarted on a record at committed with the claim still landing/probed writes the claim half, opens, and never calls Probe); TestLateCommitRollsBack (Review Focus 2).

  • [ ] Steps 1 to 5. Commit: git commit -m "host: commit as a record CAS, the claim half, the conditional open (§7.5, §7.9 steps 1 and 2)" ...

---

Task 8: The source's finalization park

Files: create internal/host/movesfinal.go, internal/host/movesfinal_test.go; modify internal/host/movespass.go (records in committed whose From == cfg.Region run finalizeSource).

Interfaces:

  • finalizeSource(ctx, s, w, rec) error (§7.9 step 3), on the source box, only when the record is committed and either this box's row has hold_op == rec.Move.ID or the op journal (moves.Journal for this op) has Steps["row-deleted"] (round-2 finding 12: a crash between the row's deletion and MoveSourceParked must not lock the close out; a replacement row with another hold_op is refused by the first condition and does not match the second); Review Focus 5: 1. the remote half: cfg.Park.Run(ctx, park.Work{Host, ID: <the park-replica obligation for cfg.Region under this op, D6>, Op: id}) (the engine takes Leases.Acquire itself; the source holds no lease of its own here); ErrPending is fine: the copies and version deletes are done when cfg.Park.Parked is true; acknowledgement after the horizon is the regional runner's (C4); 2. the local half under the host guard: cfg.Local.RetireInstallation(ctx, host, hostguard.Capture(dataDir, host), <park-local obligation id>, id) parks the database with <dbPath>.gen, the files directory, <host>.env, <db>.corrupt and the op journals into .parked/superseded-<id>/<host>/<retirement>/ (the destination park.Local derives from the obligation's op; if park.Local hardcodes .parked/<inc>/..., add the superseded-<op> form beside Task 9's remote destination); CompleteObligation(opID, parkLocalID) through hostclaim.Update; 3. cfg.ReplaceTimers(host, nil) (clears the timers rows); journal Steps["row-deleted"] = "pending", then cfg.DeleteIfHold(host, id) (the row), then Steps["row-deleted"] = "done" (a replay that finds pending and no row with this hold_op treats the delete as done); the source box's config ack (appconfig.ConfigAckKey(cfg.Box, host), §6.3) is copied to moves.ReportPrefix(...) + "config-ack-source.json" and deleted; 4. MoveSourceParked(g, now); nudgeSerial. Every step journaled in moves.Journal; replayable.

Tests: TestSourceParkWaitsForCommit (Review Focus 5: a landing record, or a committed one whose row's hold_op is another op → nothing parked, nothing deleted); TestSourceParkSurvivesACrashAfterTheRowDelete (round-2 finding 12: the journal says row-deleted: pending, the row is gone; the replay stamps source_parked_at); TestSourceParkRetiresInstallationAndRow (the database, .gen, files dir and env are gone from live paths and present under .parked/superseded-<id>/; the row is gone; timers rows gone; source_parked_at set; the park-local obligation acknowledged); TestSourceParkReplayIsIdempotent.

  • [ ] Steps 1 to 5. Commit: git commit -m "host: the source's finalization park after the commit (§7.9 step 3)" ...

---

Task 9: Gate and copy

  • [ ] Full gate, cross-compile (the peercred_other.go stub).
  • [ ] Copy list for Plan 6: M-C6 "Stopped in <from>. Starting in <to>." (emitted at probing), M-C7 (emitted at the open: "Moved. <host> is served from <to>. It was offline for <seconds> seconds.").

Self-review notes

Coverage: §7.7 every bullet (Tasks 1, 5), §7.14 the landing rows and the admitted writer's start (Task 5, through Plan 6's sequence), §5.1 start check (Task 4), §7.9 steps 1 to 3 (Tasks 2, 3, 7, 8), §7.5 commit row and "any actor writes the claim half" (Tasks 3, 7; Plan 5 adds the console), K6 (Task 5 step 1), §7.13 rows landing: probing, probed and committed, the claim still landing (Tasks 6, 7). Steps 4 and 5 of §7.9 (the target's staging park and the close) are Plan 5's.