| 1 | package session |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "encoding/json" |
| 6 | "errors" |
| 7 | "os" |
| 8 | "path/filepath" |
| 9 | "testing" |
| 10 | |
| 11 | "reasonix/internal/agent" |
| 12 | "reasonix/internal/provider" |
| 13 | ) |
| 14 | |
| 15 | func TestNativePairedHistoryResolutionPreservesNewestSource(t *testing.T) { |
| 16 | message := func(text string) provider.Message { |
| 17 | return provider.Message{ID: text, Role: provider.RoleUser, Content: text} |
| 18 | } |
| 19 | for _, tc := range []struct { |
| 20 | name string |
| 21 | legacy, stored []provider.Message |
| 22 | found, conflict bool |
| 23 | }{ |
| 24 | {"stored-newer", []provider.Message{message("a")}, []provider.Message{message("a"), message("b")}, true, false}, |
| 25 | {"legacy-newer", []provider.Message{message("a"), message("b")}, []provider.Message{message("a")}, false, false}, |
| 26 | {"equal", []provider.Message{message("a")}, []provider.Message{message("a")}, true, false}, |
| 27 | {"diverged", []provider.Message{message("a")}, []provider.Message{message("b")}, false, true}, |
| 28 | } { |
| 29 | t.Run(tc.name, func(t *testing.T) { |
| 30 | root := t.TempDir() |
| 31 | path := filepath.Join(root, "prototype.jsonl") |
| 32 | dir := filepath.Join(root, "stores", agent.BranchID(path)) |
| 33 | payload, _ := json.Marshal(map[string]any{"messages": tc.stored}) |
| 34 | writePrototypeStore(t, dir, []Event{{Kind: "context/replace", Payload: payload}}, "") |
| 35 | manifestPath := filepath.Join(dir, "manifest.json") |
| 36 | manifest, err := readStoredManifest(manifestPath) |
| 37 | if err != nil { |
| 38 | t.Fatal(err) |
| 39 | } |
| 40 | manifest.SessionID = agent.BranchID(path) |
| 41 | if err := writeManifestFile(manifestPath, manifest); err != nil { |
| 42 | t.Fatal(err) |
| 43 | } |
| 44 | before, _ := os.ReadFile(manifestPath) |
| 45 | service, err := NewService("local", NewFilesystemPersistence(filepath.Dir(dir))) |
| 46 | if err != nil { |
| 47 | t.Fatal(err) |
| 48 | } |
| 49 | t.Cleanup(func() { _ = service.CloseAll(t.Context()) }) |
| 50 | ref, found, err := service.ExistingCanonicalForLegacy(path, agent.NewSession("").CloneWithMessages(tc.legacy)) |
| 51 | if found != tc.found || errors.Is(err, ErrImportConflict) != tc.conflict || err != nil && !tc.conflict { |
| 52 | t.Fatalf("resolution = %+v %v %v", ref, found, err) |
| 53 | } |
| 54 | after, _ := os.ReadFile(manifestPath) |
| 55 | if !bytes.Equal(before, after) { |
| 56 | t.Fatal("read-only resolution changed the source") |
| 57 | } |
| 58 | if _, open := service.Runtime(SessionRef{HostID: "local", SessionID: agent.BranchID(path)}); open { |
| 59 | t.Fatal("resolution acquired a writer") |
| 60 | } |
| 61 | }) |
| 62 | } |
| 63 | } |
| 64 |