From 77ee04396516d81d629caa6d251211280836668d Mon Sep 17 00:00:00 2001 From: santoshkumarradha Date: Mon, 26 Oct 2026 08:48:41 -0400 Subject: [PATCH 1/3] Prove a store written by furrow 0.2.0 keeps working under a newer engine --- internal/cellstore/storecompat_test.go | 87 ++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 internal/cellstore/storecompat_test.go diff --git a/internal/cellstore/storecompat_test.go b/internal/cellstore/storecompat_test.go new file mode 100644 index 0000000000..74a94ef9b2 --- /dev/null +++ b/internal/cellstore/storecompat_test.go @@ -0,0 +1,87 @@ +package cellstore + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/Agent-Field/codeaf/internal/cell" + "github.com/Agent-Field/codeaf/internal/furrow" +) + +// oldEngineEnv names an older furrow release binary. The store-format tests +// below skip without it: they prove that a store written by that release opens +// and keeps capturing under the embedded engine, and the other way round. +const oldEngineEnv = "CODEAF_FURROW_OLD" + +// TestStoreWrittenByAnOlderEngineOpensUnderTheEmbeddedOne seals and captures a +// cell with the old release, then with the embedded engine on the SAME data +// root, then with the old release again. The chain must continue unbroken in +// both directions: a user who upgrades keeps their history, and a codeaf that +// is rolled back still reads what the newer one wrote. +func TestStoreWrittenByAnOlderEngineOpensUnderTheEmbeddedOne(t *testing.T) { + old := os.Getenv(oldEngineEnv) + if old == "" { + t.Skipf("%s not set", oldEngineEnv) + } + current, err := furrow.ResolveOwned() + if err != nil { + t.Skipf("no embedded engine: %v", err) + } + if current == old { + t.Skip("the embedded engine is the old engine") + } + ctx := context.Background() + dataRoot := t.TempDir() + c, err := cell.CreateIn(t.TempDir(), cell.Options{Class: cell.Sandboxed}) + if err != nil { + t.Fatal(err) + } + engineOf := func(bin string) Engine { + return Engine{Binary: bin, DataRoot: dataRoot, Transport: Spawn{Binary: bin}} + } + note := filepath.Join(c.Root, "note.txt") + write := func(s string) { + t.Helper() + if err := os.WriteFile(note, []byte(s), 0o600); err != nil { + t.Fatal(err) + } + } + + write("written by the old engine") + first, err := engineOf(old).Seal(ctx, c, TurnInfo{}) + if err != nil { + t.Fatalf("old engine seal: %v", err) + } + + write("written under the new engine") + second, err := engineOf(current).Seal(ctx, c, TurnInfo{}) + if err != nil { + t.Fatalf("embedded engine could not seal into the old store: %v", err) + } + if second.Turn.Parent != first.Turn.ID { + t.Fatalf("chain broke across the upgrade: parent %q, want %q", second.Turn.Parent, first.Turn.ID) + } + + snap, err := engineOf(current).Capture(ctx, c) + if err != nil || snap == "" { + t.Fatalf("embedded engine capture in the old store: %q, %v", snap, err) + } + write("scribbled over") + if err := engineOf(current).Restore(ctx, c, snap, []string{"note.txt"}); err != nil { + t.Fatalf("embedded engine restore: %v", err) + } + if got, _ := os.ReadFile(note); string(got) != "written under the new engine" { + t.Fatalf("restore gave %q", got) + } + + write("written after rolling back") + third, err := engineOf(old).Seal(ctx, c, TurnInfo{}) + if err != nil { + t.Fatalf("old engine could not seal into a store the newer engine wrote: %v", err) + } + if third.Turn.Parent != second.Turn.ID { + t.Fatalf("chain broke across the rollback: parent %q, want %q", third.Turn.Parent, second.Turn.ID) + } +} From 68ab95a3ac818a01781a107f46148e8485820a4c Mon Sep 17 00:00:00 2001 From: santoshkumarradha Date: Mon, 26 Oct 2026 08:49:07 -0400 Subject: [PATCH 2/3] Add the change entry for the furrow store compatibility test --- docs/changes/unreleased/1962-furrow-store-compat-test.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/changes/unreleased/1962-furrow-store-compat-test.md diff --git a/docs/changes/unreleased/1962-furrow-store-compat-test.md b/docs/changes/unreleased/1962-furrow-store-compat-test.md new file mode 100644 index 0000000000..8c88863df0 --- /dev/null +++ b/docs/changes/unreleased/1962-furrow-store-compat-test.md @@ -0,0 +1,8 @@ +--- +kind: internal +title: A store written by an older furrow is proven to open under the embedded engine +pr: 1962 +surface: [engine] +invalidates: [] +--- +Staging for the furrow bump: the compat test seals with an older release, then the embedded engine, then the older release again. From 7692c687ce4c8d974d6bd81463ae31bade50dba5 Mon Sep 17 00:00:00 2001 From: agentfield-bot Date: Mon, 26 Oct 2026 09:10:22 -0400 Subject: [PATCH 3/3] Bump embedded furrow to v0.3.3 --- .../unreleased/1962-furrow-store-compat-test.md | 6 +++--- internal/furrowbin/pin.json | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/changes/unreleased/1962-furrow-store-compat-test.md b/docs/changes/unreleased/1962-furrow-store-compat-test.md index 8c88863df0..81ce1a1385 100644 --- a/docs/changes/unreleased/1962-furrow-store-compat-test.md +++ b/docs/changes/unreleased/1962-furrow-store-compat-test.md @@ -1,8 +1,8 @@ --- -kind: internal -title: A store written by an older furrow is proven to open under the embedded engine +kind: changed +title: The embedded storage engine is furrow 0.3.3, which opens a large store without scanning it pr: 1962 surface: [engine] invalidates: [] --- -Staging for the furrow bump: the compat test seals with an older release, then the embedded engine, then the older release again. +furrow 0.3.3 validates a store's pack checkpoint with one index seek instead of counting every object, opens a settled store without taking the pack lock, and answers `status` without writing. Saving and attaching no longer slow down as the store grows. A compat test seals with furrow 0.2.0, then the embedded engine, then 0.2.0 again on the same store, so existing stores keep working in both directions. diff --git a/internal/furrowbin/pin.json b/internal/furrowbin/pin.json index e52e1e91b7..0353daa797 100644 --- a/internal/furrowbin/pin.json +++ b/internal/furrowbin/pin.json @@ -1,31 +1,31 @@ { "repository": "Agent-Field/furrow", - "tag": "v0.2.0", - "version": "0.2.0", + "tag": "v0.3.3", + "version": "0.3.3", "artifacts": { "darwin-amd64": { "asset": "furrow-darwin-amd64", - "sha256": "fc9ead1c78582086d05f859f354fac2ade8b28b43ea54a4e04f9f03a3fb92ed1" + "sha256": "a1b689f8863b578de10caef5d6cf5d09c4de1959b4f6256574e0e748687f36db" }, "darwin-arm64": { "asset": "furrow-darwin-arm64", - "sha256": "23c713db4544de5e169a902d6d42e581c205d7c85e3605fb28bbf1250bdd0c86" + "sha256": "6599f2e58bd2652610099956756de229ef2762cb4cf378a2c7f3533711e8cef1" }, "linux-amd64": { "asset": "furrow-linux-amd64", - "sha256": "be982dc8e991192d338b6daaa4f9a5765e7598eb3664b3dafd2f8e4834c4b508" + "sha256": "7ed29c0de43988c9c550426c8494b8a114c9b15a3a17a160a18d16c47d2eca4f" }, "linux-arm64": { "asset": "furrow-linux-arm64", - "sha256": "b9cecb657ee253116ebd7c1969e920d9b95cdd99267b2068e8e78b07277b1e2c" + "sha256": "4cdb22b14f11338ecab250a812bd2d25ff75aa6395eb5d7d6a0ff6c34c6c2acd" }, "windows-amd64": { "asset": "furrow-windows-amd64.exe", - "sha256": "327cc31320544e4c24f101cecc71ec7f68feae68921f7bb1ab1a6d165d0e01c7" + "sha256": "52d2223f1eb181cf4a3486bd6dfca906d99238ae92dbbe77c50ec955f91ed3a3" }, "windows-arm64": { "asset": "furrow-windows-arm64.exe", - "sha256": "f5435d6d38c87d001a008fd19db399dd8e722ca3044c2f236c3174b0a7827e77" + "sha256": "dc351ae8b48aee76fc70b142623b11a0b90da828000614aa3ced24017b3420f0" } } }