返回 DeepSeek-Reasonix
metadata_unchanged_test.go
根目录 / internal / sessioncatalog / metadata_unchanged_test.go
1 package sessioncatalog
2
3 import (
4 "context"
5 "os"
6 "path/filepath"
7 "testing"
8
9 "reasonix/internal/agent"
10 )
11
12 func TestMetadataUnchangedDiscoveryOnlyUpdatesPresence(t *testing.T) {
13 dir := t.TempDir()
14 paths := []string{filepath.Join(dir, "keep.jsonl"), filepath.Join(dir, "remove.jsonl")}
15 for _, path := range paths {
16 if err := os.WriteFile(path, []byte("unread transcript\n"), 0600); err != nil {
17 t.Fatal(err)
18 }
19 }
20 c, err := Open(t.Context(), Options{InMemory: true, MetadataOnly: true})
21 if err != nil {
22 t.Fatal(err)
23 }
24 t.Cleanup(func() { _ = c.Close(context.Background()) })
25 target := DirectoryTarget{Path: dir, Scope: "global"}
26 if err := c.ReconcileDirectory(t.Context(), target); err != nil {
27 t.Fatal(err)
28 }
29 _, err = c.db.Exec(`CREATE TABLE metadata_writes(kind TEXT);
30 CREATE TRIGGER record_session_write AFTER UPDATE OF preview,turns,topic_id ON catalog_sessions
31 BEGIN INSERT INTO metadata_writes VALUES('session'); END;
32 CREATE TRIGGER record_topic_write AFTER UPDATE ON catalog_topics
33 BEGIN INSERT INTO metadata_writes VALUES('topic'); END;`)
34 if err != nil {
35 t.Fatal(err)
36 }
37 if err := c.ReconcileDirectory(t.Context(), target); err != nil {
38 t.Fatal(err)
39 }
40 var writes, absent int
41 if err := c.db.QueryRow(`SELECT count(*) FROM metadata_writes`).Scan(&writes); err != nil || writes != 0 {
42 t.Fatalf("unchanged discovery rewrote %d projections: %v", writes, err)
43 }
44 if err := c.db.QueryRow(`SELECT count(*) FROM catalog_sessions s JOIN catalog_directories d ON s.directory_key=d.path_key
45 WHERE s.seen_generation<>d.scan_generation OR s.missing_since<>0`).Scan(&absent); err != nil || absent != 0 {
46 t.Fatalf("unchanged sources lost scan presence: %d %v", absent, err)
47 }
48 // A real metadata edit still updates the row and its topic. Removing a
49 // sibling must not hide the unchanged source at this scan's EOF.
50 if err := agent.SaveBranchMeta(paths[0], agent.BranchMeta{TopicID: "renamed", TopicTitle: "New title", Scope: "global"}); err != nil {
51 t.Fatal(err)
52 }
53 if err := os.Remove(paths[1]); err != nil {
54 t.Fatal(err)
55 }
56 if err := c.ReconcileDirectory(t.Context(), target); err != nil {
57 t.Fatal(err)
58 }
59 row, found, err := c.GetSession(t.Context(), paths[0])
60 if err != nil || !found || row.TopicID != "renamed" || row.MissingSince != 0 {
61 t.Fatalf("changed metadata was skipped: %+v %v %v", row, found, err)
62 }
63 if err := c.db.QueryRow(`SELECT count(*) FROM metadata_writes`).Scan(&writes); err != nil || writes == 0 {
64 t.Fatalf("source edit did not update the projection: %d %v", writes, err)
65 }
66 if err := c.ReconcileDirectory(t.Context(), target); err != nil {
67 t.Fatal(err)
68 }
69 row, found, err = c.GetSession(t.Context(), paths[0])
70 if err != nil || !found || row.MissingSince != 0 {
71 t.Fatalf("unchanged source vanished after sibling removal: %+v %v %v", row, found, err)
72 }
73 }
74
75 func TestMetadataUnchangedComparisonIncludesBranchAndVisibility(t *testing.T) {
76 base := SessionRecord{Path: "/history/a.jsonl", Directory: "/history", Scope: "global", TopicID: "topic",
77 RecoveryRole: RecoveryRoleNormal, OrdinaryVisible: true, LogFormat: 2, HeadCount: 2, SelectedHeadID: "first"}
78 for name, mutate := range map[string]func(*SessionRecord){
79 "head": func(r *SessionRecord) { r.SelectedHeadID = "second" },
80 "head count": func(r *SessionRecord) { r.HeadCount = 3 },
81 "format": func(r *SessionRecord) { r.LogFormat = 1 },
82 "visibility": func(r *SessionRecord) { r.OrdinaryVisible = false },
83 "lineage": func(r *SessionRecord) { r.RecoveryGroupID = "other" },
84 "missing": func(r *SessionRecord) { r.MissingSince = 1 },
85 } {
86 t.Run(name, func(t *testing.T) {
87 changed := base
88 mutate(&changed)
89 if sameMetadataProjection(changed, base) {
90 t.Fatal("changed projected identity accepted as unchanged")
91 }
92 })
93 }
94 }
95
95 lines GO