Skip to content

Commit eefe91b

Browse files
Copilotdevlux76
andcommitted
Apply review feedback: sort results, JSDoc, TODO comment, stub formatting, add missing tests
Co-authored-by: devlux76 <86517969+devlux76@users.noreply.github.com>
1 parent a7c17fb commit eefe91b

4 files changed

Lines changed: 107 additions & 3 deletions

File tree

cortex/Query.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ function dot(a: Float32Array, b: Float32Array): number {
2323
return sum;
2424
}
2525

26+
/**
27+
* Concatenates an array of equal-length vectors into a single flat buffer.
28+
* @param vectors - Must be non-empty; every element must have the same length.
29+
*/
2630
function concatVectors(vectors: Float32Array[]): Float32Array {
2731
const dim = vectors[0].length;
2832
const out = new Float32Array(vectors.length * dim);
@@ -128,6 +132,7 @@ export async function query(
128132
}
129133

130134
const combined = [...hotpathResults, ...coldResults];
135+
combined.sort((a, b) => b.score - a.score);
131136

132137
// Update activity for returned pages
133138
await Promise.all(combined.map(async ({ page }) => {

storage/IndexedDbMetadataStore.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,10 @@ export class IndexedDbMetadataStore implements MetadataStore {
145145
return this._get<Page>(STORE.pages, pageId);
146146
}
147147

148-
/** Returns all pages in the store. Used for warm/cold fallbacks in query. */
148+
/** Returns all pages in the store. Used for warm/cold fallbacks in query.
149+
* TODO: Replace with a paginated or indexed scan before production use —
150+
* loading every page into memory is expensive for large corpora.
151+
*/
149152
async getAllPages(): Promise<Page[]> {
150153
return new Promise((resolve, reject) => {
151154
const tx = this.db.transaction(STORE.pages, "readonly");

tests/SalienceEngine.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ class MockMetadataStore implements MetadataStore {
104104

105105
// --- Stubs for unused MetadataStore methods ---
106106
async putPage(): Promise<void> { /* stub */ }
107-
async getPage(): Promise<undefined> { return undefined; } async getAllPages(): Promise<any[]> { return []; } async putBook(): Promise<void> { /* stub */ }
107+
async getPage(): Promise<undefined> { return undefined; }
108+
async getAllPages(): Promise<any[]> { return []; }
109+
async putBook(): Promise<void> { /* stub */ }
108110
async getBook(): Promise<undefined> { return undefined; }
109111
async putVolume(): Promise<void> { /* stub */ }
110112
async getVolume(): Promise<undefined> { return undefined; }

tests/cortex/Query.test.ts

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type { ModelProfile } from "../../core/ModelProfile";
1313
import type { VectorBackend } from "../../VectorBackend";
1414

1515
class TestVectorBackend implements VectorBackend {
16-
readonly kind = "test" as const;
16+
readonly kind = "wasm" as const;
1717

1818
async dotMany(
1919
query: Float32Array,
@@ -61,6 +61,44 @@ describe("cortex query (minimal)", () => {
6161
(globalThis as any).IDBKeyRange = FakeIDBKeyRange;
6262
});
6363

64+
it("returns empty results for an empty corpus", async () => {
65+
const metadataStore = await IndexedDbMetadataStore.open(freshDbName());
66+
const vectorStore = new MemoryVectorStore();
67+
68+
const backend = new DeterministicDummyEmbeddingBackend({ dimension: 4 });
69+
const vectorBackend = new TestVectorBackend();
70+
71+
const runner = new EmbeddingRunner(async () => ({
72+
backend,
73+
selectedKind: "dummy" as const,
74+
reason: "forced" as const,
75+
supportedKinds: ["dummy" as const],
76+
measurements: [],
77+
}));
78+
79+
const profile: ModelProfile = {
80+
modelId: "test-model",
81+
embeddingDimension: 4,
82+
contextWindowTokens: 64,
83+
truncationTokens: 48,
84+
maxChunkTokens: 5,
85+
source: "metadata",
86+
};
87+
88+
const result = await query("anything", {
89+
modelProfile: profile,
90+
embeddingRunner: runner,
91+
vectorStore,
92+
metadataStore,
93+
vectorBackend,
94+
topK: 5,
95+
});
96+
97+
expect(result.pages).toHaveLength(0);
98+
expect(result.scores).toHaveLength(0);
99+
expect(result.metadata.returned).toBe(0);
100+
});
101+
64102
it("returns the most relevant page and updates activity", async () => {
65103
const metadataStore = await IndexedDbMetadataStore.open(freshDbName());
66104
const vectorStore = new MemoryVectorStore();
@@ -120,4 +158,60 @@ describe("cortex query (minimal)", () => {
120158
expect(activity?.queryHitCount).toBe(1);
121159
expect(activity?.lastQueryAt).toBeDefined();
122160
});
161+
162+
it("returns results in descending score order (relevance)", async () => {
163+
const metadataStore = await IndexedDbMetadataStore.open(freshDbName());
164+
const vectorStore = new MemoryVectorStore();
165+
const keyPair = await generateKeyPair();
166+
167+
const backend = new DeterministicDummyEmbeddingBackend({ dimension: 4 });
168+
const vectorBackend = new TestVectorBackend();
169+
170+
const runner = new EmbeddingRunner(async () => ({
171+
backend,
172+
selectedKind: "dummy" as const,
173+
reason: "forced" as const,
174+
supportedKinds: ["dummy" as const],
175+
measurements: [],
176+
}));
177+
178+
const profile: ModelProfile = {
179+
modelId: "test-model",
180+
embeddingDimension: 4,
181+
contextWindowTokens: 64,
182+
truncationTokens: 48,
183+
maxChunkTokens: 5,
184+
source: "metadata",
185+
};
186+
187+
const text = "One two three four five six seven eight nine ten.";
188+
const ingestResult = await ingestText(text, {
189+
modelProfile: profile,
190+
embeddingRunner: runner,
191+
vectorStore,
192+
metadataStore,
193+
keyPair,
194+
});
195+
196+
expect(ingestResult.pages.length).toBeGreaterThanOrEqual(2);
197+
198+
const targetPage = ingestResult.pages[0];
199+
200+
const result = await query(targetPage.content, {
201+
modelProfile: profile,
202+
embeddingRunner: runner,
203+
vectorStore,
204+
metadataStore,
205+
vectorBackend,
206+
topK: ingestResult.pages.length,
207+
});
208+
209+
// Results must include the page whose content matches the query.
210+
expect(result.pages.map((p) => p.pageId)).toContain(targetPage.pageId);
211+
212+
// Scores must be in non-increasing order.
213+
for (let i = 1; i < result.scores.length; i++) {
214+
expect(result.scores[i]).toBeLessThanOrEqual(result.scores[i - 1]);
215+
}
216+
});
123217
});

0 commit comments

Comments
 (0)