kenn-io--agentsview
f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
293 行
8.7 KiB
Go
293 行
8.7 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestRecallQueryEventRecordsRankedExposureSnapshot(t *testing.T) {
|
|
d := testDB(t)
|
|
event := RecallQueryEvent{
|
|
QueryID: "query-1",
|
|
Query: "recover wrong cwd",
|
|
Surface: "brief",
|
|
FiltersJSON: `{"project":"agentsview","agent":"codex","limit":3}`,
|
|
TrustedOnly: true,
|
|
ScorePolicyVersion: RecallLexicalScorePolicyVersion,
|
|
ResultCount: 3,
|
|
PackedCount: 2,
|
|
TopScore: 9.75,
|
|
MissReason: "context_empty",
|
|
Exposures: []RecallQueryExposure{
|
|
{Rank: 1, EntryID: "m1", Score: 9.75, Packed: true},
|
|
{Rank: 2, EntryID: "m2", Score: 6.5, Packed: false},
|
|
{Rank: 3, EntryID: "m3", Score: 4.25, Packed: true},
|
|
},
|
|
}
|
|
|
|
id, err := d.RecordRecallQueryEvent(context.Background(), event)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "query-1", id)
|
|
got, err := d.GetRecallQueryEvent(context.Background(), id)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, got)
|
|
assert.Equal(t, "query-1", got.QueryID)
|
|
assert.Equal(t, "recover wrong cwd", got.Query)
|
|
assert.Equal(t, "brief", got.Surface)
|
|
assert.Equal(t, event.FiltersJSON, got.FiltersJSON)
|
|
assert.True(t, got.TrustedOnly)
|
|
assert.Equal(t, RecallLexicalScorePolicyVersion, got.ScorePolicyVersion)
|
|
assert.Equal(t, 3, got.ResultCount)
|
|
assert.Equal(t, 2, got.PackedCount)
|
|
assert.Equal(t, 9.75, got.TopScore)
|
|
assert.Equal(t, "context_empty", got.MissReason)
|
|
assert.NotEmpty(t, got.CreatedAt)
|
|
require.Len(t, got.Exposures, 3)
|
|
for i, want := range event.Exposures {
|
|
assert.Equal(t, id, got.Exposures[i].QueryID)
|
|
assert.Equal(t, want.Rank, got.Exposures[i].Rank)
|
|
assert.Equal(t, want.EntryID, got.Exposures[i].EntryID)
|
|
assert.Equal(t, want.Score, got.Exposures[i].Score)
|
|
assert.Equal(t, want.Packed, got.Exposures[i].Packed)
|
|
}
|
|
}
|
|
|
|
func TestRecallQueryEventGeneratesOpaqueID(t *testing.T) {
|
|
d := testDB(t)
|
|
|
|
first, err := d.RecordRecallQueryEvent(context.Background(), RecallQueryEvent{
|
|
Query: "first query",
|
|
Surface: "query",
|
|
})
|
|
require.NoError(t, err)
|
|
second, err := d.RecordRecallQueryEvent(context.Background(), RecallQueryEvent{
|
|
Query: "second query",
|
|
Surface: "query",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, first, 36)
|
|
assert.Len(t, second, 36)
|
|
assert.NotEqual(t, first, second)
|
|
}
|
|
|
|
func TestRecallQueryEventDuplicateExposureRankRollsBackAtomically(t *testing.T) {
|
|
d := testDB(t)
|
|
|
|
_, err := d.RecordRecallQueryEvent(context.Background(), RecallQueryEvent{
|
|
QueryID: "query-duplicate-rank",
|
|
Query: "atomic query",
|
|
Surface: "query",
|
|
ResultCount: 2,
|
|
Exposures: []RecallQueryExposure{
|
|
{Rank: 1, EntryID: "m1", Score: 4},
|
|
{Rank: 1, EntryID: "m2", Score: 3},
|
|
},
|
|
})
|
|
|
|
require.Error(t, err)
|
|
got, getErr := d.GetRecallQueryEvent(
|
|
context.Background(), "query-duplicate-rank",
|
|
)
|
|
require.NoError(t, getErr)
|
|
assert.Nil(t, got)
|
|
var exposureCount int
|
|
require.NoError(t, d.getReader().QueryRow(`
|
|
SELECT COUNT(*) FROM recall_query_exposures
|
|
WHERE query_id = ?`,
|
|
"query-duplicate-rank",
|
|
).Scan(&exposureCount))
|
|
assert.Zero(t, exposureCount)
|
|
}
|
|
|
|
func TestRecallQueryEventPersistsLargeRankedExposureSnapshot(t *testing.T) {
|
|
d := testDB(t)
|
|
exposures := make([]RecallQueryExposure, 205)
|
|
for i := range exposures {
|
|
rank := i + 1
|
|
exposures[i] = RecallQueryExposure{
|
|
QueryID: "ignored-exposure-query-id",
|
|
Rank: rank,
|
|
EntryID: fmt.Sprintf("entry-%03d", rank),
|
|
Score: float64(rank) + 0.25,
|
|
Packed: rank%2 == 0,
|
|
}
|
|
}
|
|
|
|
id, err := d.RecordRecallQueryEvent(context.Background(), RecallQueryEvent{
|
|
QueryID: "query-large-snapshot",
|
|
Query: "large ranked snapshot",
|
|
Surface: "calibration",
|
|
ResultCount: len(exposures),
|
|
PackedCount: 102,
|
|
TopScore: 205.25,
|
|
Exposures: exposures,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
got, err := d.GetRecallQueryEvent(context.Background(), id)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, got)
|
|
require.Len(t, got.Exposures, 205)
|
|
for i, exposure := range got.Exposures {
|
|
assert.Equal(t, i+1, exposure.Rank)
|
|
}
|
|
|
|
boundaries := []struct {
|
|
index int
|
|
rank int
|
|
entryID string
|
|
score float64
|
|
packed bool
|
|
}{
|
|
{index: 0, rank: 1, entryID: "entry-001", score: 1.25},
|
|
{index: 99, rank: 100, entryID: "entry-100", score: 100.25, packed: true},
|
|
{index: 100, rank: 101, entryID: "entry-101", score: 101.25},
|
|
{index: 199, rank: 200, entryID: "entry-200", score: 200.25, packed: true},
|
|
{index: 200, rank: 201, entryID: "entry-201", score: 201.25},
|
|
{index: 204, rank: 205, entryID: "entry-205", score: 205.25},
|
|
}
|
|
for _, boundary := range boundaries {
|
|
exposure := got.Exposures[boundary.index]
|
|
assert.Equal(t, id, exposure.QueryID)
|
|
assert.Equal(t, boundary.rank, exposure.Rank)
|
|
assert.Equal(t, boundary.entryID, exposure.EntryID)
|
|
assert.Equal(t, boundary.score, exposure.Score)
|
|
assert.Equal(t, boundary.packed, exposure.Packed)
|
|
}
|
|
}
|
|
|
|
func TestRecallQueryEventLateDuplicateRankRollsBackAtomically(t *testing.T) {
|
|
d := testDB(t)
|
|
exposures := make([]RecallQueryExposure, 101)
|
|
for i := range exposures {
|
|
rank := i + 1
|
|
exposures[i] = RecallQueryExposure{
|
|
Rank: rank, EntryID: fmt.Sprintf("entry-%03d", rank),
|
|
Score: float64(rank),
|
|
}
|
|
}
|
|
exposures[100].Rank = 100
|
|
|
|
_, err := d.RecordRecallQueryEvent(context.Background(), RecallQueryEvent{
|
|
QueryID: "query-late-duplicate-rank",
|
|
Query: "atomic query after many exposures",
|
|
Surface: "query",
|
|
ResultCount: len(exposures),
|
|
Exposures: exposures,
|
|
})
|
|
require.Error(t, err)
|
|
assert.ErrorContains(t, err, "exposure ranks 100 through 100")
|
|
|
|
got, getErr := d.GetRecallQueryEvent(
|
|
context.Background(), "query-late-duplicate-rank",
|
|
)
|
|
require.NoError(t, getErr)
|
|
assert.Nil(t, got)
|
|
var exposureCount int
|
|
require.NoError(t, d.getReader().QueryRow(`
|
|
SELECT COUNT(*) FROM recall_query_exposures
|
|
WHERE query_id = ?`,
|
|
"query-late-duplicate-rank",
|
|
).Scan(&exposureCount))
|
|
assert.Zero(t, exposureCount)
|
|
}
|
|
|
|
func TestRecallQueryEventSurvivesRecallAndSessionDeletion(t *testing.T) {
|
|
d := testDB(t)
|
|
insertSession(t, d, "s1", "agentsview")
|
|
_, err := d.InsertRecallEntry(RecallEntry{
|
|
ID: "m1",
|
|
Type: "fact",
|
|
Scope: "project",
|
|
Status: "accepted",
|
|
Title: "Durable exposure",
|
|
Body: "The measurement outlives its source row.",
|
|
SourceSessionID: "s1",
|
|
})
|
|
require.NoError(t, err)
|
|
_, err = d.RecordRecallQueryEvent(context.Background(), RecallQueryEvent{
|
|
QueryID: "query-durable",
|
|
Query: "durable query",
|
|
Surface: "query",
|
|
ResultCount: 1,
|
|
PackedCount: 1,
|
|
TopScore: 8,
|
|
Exposures: []RecallQueryExposure{{
|
|
Rank: 1, EntryID: "m1", Score: 8, Packed: true,
|
|
}},
|
|
})
|
|
require.NoError(t, err)
|
|
_, err = d.getWriter().Exec(`DELETE FROM sessions WHERE id = 's1'`)
|
|
require.NoError(t, err)
|
|
|
|
got, err := d.GetRecallQueryEvent(context.Background(), "query-durable")
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, got)
|
|
require.Len(t, got.Exposures, 1)
|
|
assert.Equal(t, "m1", got.Exposures[0].EntryID)
|
|
}
|
|
|
|
func TestRecallQueryEventSurvivesFullResyncWithoutExposedEntry(t *testing.T) {
|
|
dir := t.TempDir()
|
|
srcPath := filepath.Join(dir, "old-query-events.db")
|
|
src, err := Open(srcPath)
|
|
require.NoError(t, err)
|
|
_, err = src.RecordRecallQueryEvent(context.Background(), RecallQueryEvent{
|
|
QueryID: "query-orphan-exposure",
|
|
Query: "missing entry query",
|
|
Surface: "calibration",
|
|
FiltersJSON: `{"project":"missing"}`,
|
|
TrustedOnly: true,
|
|
ResultCount: 1,
|
|
TopScore: 7.25,
|
|
MissReason: "context_empty",
|
|
Exposures: []RecallQueryExposure{{
|
|
Rank: 1, EntryID: "entry-not-in-new-db", Score: 7.25,
|
|
}},
|
|
})
|
|
require.NoError(t, err)
|
|
require.NoError(t, src.Close())
|
|
|
|
dstPath := filepath.Join(dir, "new-query-events.db")
|
|
dst, err := Open(dstPath)
|
|
require.NoError(t, err)
|
|
defer dst.Close()
|
|
require.NoError(t, dst.CopyRecallEntriesFrom(srcPath))
|
|
|
|
got, err := dst.GetRecallQueryEvent(
|
|
context.Background(), "query-orphan-exposure",
|
|
)
|
|
|
|
require.NoError(t, err)
|
|
require.NotNil(t, got)
|
|
assert.Equal(t, "calibration", got.Surface)
|
|
assert.Equal(t, "context_empty", got.MissReason)
|
|
require.Len(t, got.Exposures, 1)
|
|
assert.Equal(t, "entry-not-in-new-db", got.Exposures[0].EntryID)
|
|
}
|
|
|
|
func TestRecallQueryEventCopyToleratesArchiveWithoutLedger(t *testing.T) {
|
|
dir := t.TempDir()
|
|
srcPath := filepath.Join(dir, "old-without-ledger.db")
|
|
src, err := Open(srcPath)
|
|
require.NoError(t, err)
|
|
require.NoError(t, src.Close())
|
|
execRawSQLite(t, srcPath, "DROP TABLE recall_query_exposures")
|
|
execRawSQLite(t, srcPath, "DROP TABLE recall_query_events")
|
|
|
|
dstPath := filepath.Join(dir, "new-with-ledger.db")
|
|
dst, err := Open(dstPath)
|
|
require.NoError(t, err)
|
|
defer dst.Close()
|
|
|
|
assert.NoError(t, dst.CopyRecallEntriesFrom(srcPath))
|
|
}
|