From d02226bfd10ebbfa77e951ce87cfae6b54c02720 Mon Sep 17 00:00:00 2001 From: santoshkumarradha Date: Mon, 2 Nov 2026 05:11:27 -0500 Subject: [PATCH 1/4] tests: the writer's return after a clean quit is the new ownership a stale consent meets app/v3 resumes the same hold when a chat's installed copy opens again (F1, TestFenceF1StartupRenewsExistingHold and TestFenceF1IdleWatchReconnectAnd- ProcessResume), and a clean quit releases it. TestAReturnAfterTheWriter- ReopensIsNotALostRace came from dev, where every open acquired a new fence, so on app/v3 its plain reopen kept the fence and the test failed before it reached the consent check. The writer now quits cleanly and opens again, which is the return that makes a new ownership under F1, and the stale and fresh consent assertions are unchanged. --- internal/syncsetup/continue_reopened_writer_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/syncsetup/continue_reopened_writer_test.go b/internal/syncsetup/continue_reopened_writer_test.go index b504bb0a68..d85db69540 100644 --- a/internal/syncsetup/continue_reopened_writer_test.go +++ b/internal/syncsetup/continue_reopened_writer_test.go @@ -22,6 +22,10 @@ func TestAReturnAfterTheWriterReopensIsNotALostRace(t *testing.T) { moved, err := h.continuerB().Take(ctx, h.cell.ID) mustNil(t, err) stale := &directory.LeaseExpectation{Device: h.b.Device.ID(), Fence: moved.Taken.Driving.Fence} + // Opening an installed copy resumes the same hold (F1, #2009); a clean + // quit releases it, so the writer's return is a new ownership. + first := h.openOn(h.b, h.engB, moved.Taken.Cell, workspaceOf(moved.Taken.Cell.Root), nameB) + mustNil(t, first.drive.Close(ctx)) h.openOn(h.b, h.engB, moved.Taken.Cell, workspaceOf(moved.Taken.Cell.Root), nameB) current, err := h.a.Dir.Cell(ctx, h.cell.ID) mustNil(t, err) From ba651ca6e3d57ec383ebe0442c1ff8d5e7c6979e Mon Sep 17 00:00:00 2001 From: santoshkumarradha Date: Mon, 2 Nov 2026 05:12:35 -0500 Subject: [PATCH 2/4] docs: change entry for this pull request --- docs/changes/unreleased/2183-reopen-fence-test.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 docs/changes/unreleased/2183-reopen-fence-test.md diff --git a/docs/changes/unreleased/2183-reopen-fence-test.md b/docs/changes/unreleased/2183-reopen-fence-test.md new file mode 100644 index 0000000000..255e0cdba8 --- /dev/null +++ b/docs/changes/unreleased/2183-reopen-fence-test.md @@ -0,0 +1,6 @@ +--- +kind: internal +title: The stale-consent test makes the writer's return a clean quit and reopen, as F1 requires +pr: 2183 +surface: [chat] +--- From e6761fcf970a11c7dba0f77ed3075f00652ef25c Mon Sep 17 00:00:00 2001 From: santoshkumarradha Date: Mon, 2 Nov 2026 05:50:02 -0500 Subject: [PATCH 3/4] tests: the hosted take-back resumes the taken hold instead of acquiring again Same root cause as the reopen test: under F1 the hosted writer that reopens after a take-back resumes the fence the take acquired with a heartbeat, so TestHostedTakeBackReachesAcquireWithoutSharedUploadsOrReleaseDelay, which counted two acquires, failed with the real engine since #2009. It now records the relay's heartbeats too and requires the reopened writer to resume the taken hold within the same 5s bound; the first-acquire bound and the no-shared-upload check are unchanged. --- cmd/codeaf/hosted_takeback_test.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/cmd/codeaf/hosted_takeback_test.go b/cmd/codeaf/hosted_takeback_test.go index 83d73feffb..993a2cef0b 100644 --- a/cmd/codeaf/hosted_takeback_test.go +++ b/cmd/codeaf/hosted_takeback_test.go @@ -15,6 +15,7 @@ import ( "os" "os/exec" "path/filepath" + "slices" "strings" "sync" "sync/atomic" @@ -49,6 +50,7 @@ type hostedMoveRig struct { mu sync.Mutex requests []string acquires []time.Time + resumes []time.Time changes chan struct{} } @@ -87,6 +89,9 @@ func newHostedMoveRig(t *testing.T, wrap ...func(http.Handler) http.Handler) *ho if strings.HasSuffix(r.URL.Path, "/acquire") { h.acquires = append(h.acquires, time.Now()) } + if strings.HasSuffix(r.URL.Path, "/heartbeat") { + h.resumes = append(h.resumes, time.Now()) + } h.mu.Unlock() service.ServeHTTP(w, r) })) @@ -321,7 +326,7 @@ func TestHostedTakeBackReachesAcquireWithoutSharedUploadsOrReleaseDelay(t *testi h.wait("take-back card", func() bool { return strings.Contains(screen.String(), "Continue this chat here?") }) h.mu.Lock() h.requests = nil - h.acquires = nil + h.acquires, h.resumes = nil, nil h.mu.Unlock() started = time.Now() if _, err := io.WriteString(typed, "1\r"); err != nil { @@ -330,8 +335,18 @@ func TestHostedTakeBackReachesAcquireWithoutSharedUploadsOrReleaseDelay(t *testi h.wait("hosted take-back arrival", func() bool { return strings.Contains(screen.String(), "Moved from other computer") }) h.mu.Lock() defer h.mu.Unlock() - if len(h.acquires) < 2 { - t.Fatalf("take and reopened hosted writer made %d acquires; want both", len(h.acquires)) + if len(h.acquires) == 0 { + t.Fatal("take-back made no acquire") + } + // The reopened writer resumes the hold the take acquired (F1, #2009): it + // renews that fence rather than acquiring another. + resumed := slices.IndexFunc(h.resumes, func(at time.Time) bool { return !at.Before(h.acquires[0]) }) + if resumed < 0 { + t.Fatal("the reopened hosted writer never resumed the taken hold") + } + t.Logf("relay resume after first acquire: %s", h.resumes[resumed].Sub(h.acquires[0])) + if gap := h.resumes[resumed].Sub(h.acquires[0]); gap >= 5*time.Second { + t.Errorf("resume gap=%s", gap) } t.Logf("relay first acquire after key: %s", h.acquires[0].Sub(started)) if elapsed := h.acquires[0].Sub(started); elapsed > time.Second { From 9cb3fa33b62d20b73a9fa7f5514dd8908e6126e7 Mon Sep 17 00:00:00 2001 From: santoshkumarradha Date: Mon, 2 Nov 2026 05:50:44 -0500 Subject: [PATCH 4/4] docs: the change entry names both F1 tests --- docs/changes/unreleased/2183-reopen-fence-test.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changes/unreleased/2183-reopen-fence-test.md b/docs/changes/unreleased/2183-reopen-fence-test.md index 255e0cdba8..94fd0ba996 100644 --- a/docs/changes/unreleased/2183-reopen-fence-test.md +++ b/docs/changes/unreleased/2183-reopen-fence-test.md @@ -1,6 +1,6 @@ --- kind: internal -title: The stale-consent test makes the writer's return a clean quit and reopen, as F1 requires +title: F1 reopen resumes the same hold in the stale-consent and hosted take-back tests pr: 2183 surface: [chat] ---