Repository navigation
Expand file tree
/
Copy pathcompiler_intake_test.go
More file actions
185 lines (181 loc) · 7.03 KB
/
Copy pathcompiler_intake_test.go
File metadata and controls
185 lines (181 loc) · 7.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package knowledge_test
import (
"context"
"encoding/json"
"errors"
"github.com/Agent-Field/codeaf/internal/knowledge"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
)
func TestKnowledgeRevisitConstrainsQuotesToExactWindow(t *testing.T) {
v := knowledge.Open(t.TempDir())
if err := v.StartBuild(); err != nil {
t.Fatal(err)
}
source := knowledge.Source{ID: "s", Session: "chat", Role: "user", TS: "2026-10-25T12:00:00Z", Text: "Cedar queues jobs. Cedar retains receipts."}
if err := v.Capture(source); err != nil {
t.Fatal(err)
}
calls := 0
withKnowledgeModel(t, func(p map[string]any) map[string]any {
if p["messages"] == nil {
return map[string]any{"subjects": []any{}}
}
calls++
quote := "Cedar queues jobs."
if calls == 2 {
m := p["messages"].([]any)[0].(map[string]any)
if m["text"] != "Cedar retains receipts." || m["source_window"] == nil {
t.Fatalf("not exact source window: %+v", m)
}
}
return map[string]any{"claims": []any{map[string]any{"local_id": "c", "text": "Cedar queues jobs.", "scope": "Cedar", "topic": "Queues", "kind": "fact", "evidence": []any{map[string]any{"source": "s", "quote": quote}}}}}
})
if err := v.Flush(context.Background(), "fixture", true); err != nil {
t.Fatal(err)
}
if err := v.Revisit([]string{"s"}, map[string]knowledge.SourceWindow{"s": {Start: 19, Length: 23}}); err != nil {
t.Fatal(err)
}
if err := v.Flush(context.Background(), "fixture", true); err != nil {
t.Fatal(err)
}
snapshot, err := v.Snapshot()
if err != nil || len(snapshot.Pages) != 1 || len(snapshot.Pages[0].Claims) != 1 || calls != 2 {
t.Fatalf("window revisit lost original or accepted hidden quote: %+v calls=%d %v", snapshot, calls, err)
}
}
func TestKnowledgeStagesResponseProposalsAsExtractionHints(t *testing.T) {
v := knowledge.Open(t.TempDir())
if err := v.StartBuild(); err != nil {
t.Fatal(err)
}
source := knowledge.Source{ID: "answer", Project: "Cedar", Session: "chat", Role: "assistant", TS: "2026-10-25T12:00:00Z", Text: "Cedar may queue invoices."}
if err := v.Capture(source); err != nil {
t.Fatal(err)
}
envelope := json.RawMessage(`{"knowledge_delta":[{"op":"learn","text":"Cedar may queue invoices.","subject":"Queues","evidence":[{"source":"self","quote":"may queue invoices"}]}]}`)
if _, err := v.StageProposals("answer", map[string]string{"owner": "test", "project": "Cedar"}, envelope); err != nil {
t.Fatal(err)
}
withKnowledgeModel(t, func(p map[string]any) map[string]any {
if p["messages"] == nil {
return map[string]any{"subjects": []any{}}
}
hints, ok := p["proposals"].([]any)
if !ok || len(hints) != 1 || !strings.Contains(hints[0].(map[string]any)["text"].(string), "may queue invoices") {
t.Fatalf("proposal hint absent: %+v", p)
}
return map[string]any{"claims": []any{}}
})
if err := v.Flush(context.Background(), "fixture", true); err != nil {
t.Fatal(err)
}
snapshot, err := v.Snapshot()
if err != nil || len(snapshot.Pages) != 0 {
t.Fatalf("unaccepted sidecar became knowledge: %+v %v", snapshot, err)
}
}
func TestKnowledgeRevisitRejectsPendingSourceWithoutChangingItsContext(t *testing.T) {
v := knowledge.Open(t.TempDir())
if err := v.StartBuild(); err != nil {
t.Fatal(err)
}
text := "Cedar queues jobs. Cedar retains receipts."
if err := v.Capture(knowledge.Source{ID: "s", Session: "chat", Role: "user", TS: "2026-10-25T12:00:00Z", Text: text}); err != nil {
t.Fatal(err)
}
if err := v.Revisit([]string{"s"}, map[string]knowledge.SourceWindow{"s": {Start: 19, Length: 23}}); !errors.Is(err, knowledge.ErrCompilerBusy) {
t.Fatalf("pending revisit must be retryable without mutation: %v", err)
}
// A leaked 23-character window would admit both sources despite their
// original combined size exceeding the compiler's 24,000-character cap.
if err := v.Capture(knowledge.Source{ID: "next", Session: "chat", Role: "user", TS: "2026-10-25T12:00:01Z", Text: strings.Repeat("x", 23970)}); err != nil {
t.Fatal(err)
}
withKnowledgeModel(t, func(p map[string]any) map[string]any {
if p["messages"] == nil {
return map[string]any{"subjects": []any{}}
}
messages := p["messages"].([]any)
if len(messages) != 1 {
t.Fatalf("rejected window altered batch budgeting: messages=%d", len(messages))
}
m := messages[0].(map[string]any)
if m["text"] != text || m["source_window"] != nil {
t.Fatalf("rejected revisit changed first extraction context: %+v", m)
}
return map[string]any{"claims": []any{}}
})
if err := v.Flush(context.Background(), "fixture", true); err != nil {
t.Fatal(err)
}
snapshot, err := v.Status()
if err != nil || snapshot.Pending != 1 {
t.Fatalf("first extraction consumed the next bounded batch: pending=%d %v", snapshot.Pending, err)
}
// A later valid revisit must get its own requested span, never the rejected one.
if err := v.Revisit([]string{"s"}, map[string]knowledge.SourceWindow{"s": {Start: 0, Length: 18}}); err != nil {
t.Fatal(err)
}
}
func TestKnowledgeProposalStagingRetriesAfterInFlightExtraction(t *testing.T) {
v := knowledge.Open(t.TempDir())
if err := v.StartBuild(); err != nil {
t.Fatal(err)
}
if err := v.Capture(knowledge.Source{ID: "answer", Project: "Cedar", Session: "chat", Role: "assistant", TS: "2026-10-25T12:00:00Z", Text: "Cedar may queue invoices."}); err != nil {
t.Fatal(err)
}
envelope := json.RawMessage(`{"knowledge_delta":[{"op":"learn","text":"Cedar may queue invoices.","subject":"Queues","evidence":[{"source":"self","quote":"may queue invoices"}]}]}`)
started, release, finished := make(chan struct{}), make(chan struct{}), make(chan struct{})
var once sync.Once
unblock := func() { once.Do(func() { close(release) }) }
var calls atomic.Int32
withKnowledgeModel(t, func(p map[string]any) map[string]any {
if p["messages"] == nil {
return map[string]any{"subjects": []any{}}
}
if calls.Add(1) == 1 {
close(started)
<-release
} else {
hints, ok := p["proposals"].([]any)
if !ok || len(hints) != 1 {
t.Errorf("retried sidecar not supplied to extraction: %+v", p["proposals"])
}
}
return map[string]any{"claims": []any{}}
})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var flushErr error
go func() { defer close(finished); flushErr = v.Flush(ctx, "fixture", true) }()
defer func() { unblock(); <-finished }()
select {
case <-started:
case <-ctx.Done():
t.Fatal("extraction did not start")
}
if _, err := v.StageProposals("answer", map[string]string{"owner": "test", "project": "Cedar"}, envelope); !errors.Is(err, knowledge.ErrCompilerBusy) {
t.Fatalf("in-flight staging must return retryable busy: %v", err)
}
unblock()
<-finished
if flushErr != nil {
t.Fatal(flushErr)
}
receipt, err := v.StageProposals("answer", map[string]string{"owner": "test", "project": "Cedar"}, envelope)
if err != nil || receipt.New != 1 {
t.Fatalf("retry did not stage exactly one new proposal: %+v %v", receipt, err)
}
if err = v.Flush(context.Background(), "fixture", true); err != nil {
t.Fatal(err)
}
if calls.Load() != 2 {
t.Fatalf("staged hint lost instead of reopening extraction: calls=%d", calls.Load())
}
}