import { createMemoryDataSource } from "@conusai-kit/data" import { DEFAULT_FILES_POLICY, type FilesDeps, files } from "@conusai-kit/files" import type { Knowledge, KnowledgeSearchHit } from "@conusai-kit/platform" import { fakeObjectStore } from "@conusai-kit/testing" import { describe, expect, it } from "vitest" import { platformKnowledgeSearch } from "../adapters/platform-knowledge.js" import type { KnowledgeScope } from "../core/ports.js" const scope: KnowledgeScope = { level: "project", actor: { userId: "01900000-0000-7000-0000-000000000009" }, orgId: "01900000-0000-7000-0000-000000000001", workspaceId: "01900000-0000-7000-0000-000000000002", projectId: "01900000-0000-7000-0000-000000000003", } const otherScope: KnowledgeScope = { ...scope, projectId: "01900000-0000-7000-0000-000000000004", } const storageKey = `files/${scope.workspaceId}/${scope.projectId}/01900000-0000-7000-0000-000000000100` const otherStorageKey = `files/${otherScope.workspaceId}/${otherScope.projectId}/01900000-0000-7000-0000-000000000101` const pathname = `org/${scope.orgId}/${storageKey}` interface ClientStub { indexed: string[] removed: string[] searches: Array[0]> results: readonly KnowledgeSearchHit[] } function knowledgeClient(stub: ClientStub): Knowledge { return { readiness: async () => ({ state: "ready", reasons: [], checkedAt: new Date().toISOString() }), createCollection: async (input) => input, search: async (input) => { stub.searches.push(input) return stub.results }, index: async (input) => { stub.indexed.push(input.documentRef) return { jobId: "job-1" } }, job: async (jobId) => ({ jobId, status: "succeeded", progress: 1, generation: 1, error: null }), cancel: async () => undefined, remove: async (documentRef) => { stub.removed.push(documentRef) }, } } function stub(results: readonly KnowledgeSearchHit[] = []): ClientStub { return { indexed: [], removed: [], searches: [], results } } function makeFiles() { const data = createMemoryDataSource({ entities: [files] }) const deps: FilesDeps = { data, store: fakeObjectStore(), policy: DEFAULT_FILES_POLICY } return { data, deps } } async function seedFile( data: ReturnType, atScope: KnowledgeScope, key: string, filename = "contract.txt", ): Promise { const row = await data.forScope(atScope).of(files).insert({ status: "stored", storageKey: key, filename, contentType: "text/plain", size: 17, sha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", uploadedBy: atScope.actor.userId, storedAt: "2026-10-24T00:00:00.000Z", uploadId: null, declaredSize: null, partSize: null, deletingAt: null, }) return row.id } describe("the managed knowledge Blob reference", () => { it("indexes and removes by Blob pathname rather than opaque file id", async () => { const { data, deps } = makeFiles() const fileId = await seedFile(data, scope, storageKey) const client = stub() const service = platformKnowledgeSearch(knowledgeClient(client), deps) await service.index(scope, { collectionName: "contracts", fileId, filename: "contract.txt", bytes: new TextEncoder().encode("managed knowledge"), }) await service.remove(scope, { collectionName: "contracts", fileId }) expect(client.indexed).toEqual([pathname]) expect(client.removed).toEqual([pathname]) }) it("maps citations through scoped file rows and drops foreign or stale references", async () => { const { data, deps } = makeFiles() const fileId = await seedFile(data, scope, storageKey) await seedFile(data, otherScope, otherStorageKey, "other-project.txt") const client = stub([ { documentRef: pathname, snippet: "own snippet", score: 0.9, citations: [{ page: 1 }] }, { documentRef: `org/${scope.orgId}/${otherStorageKey}`, snippet: "other project snippet", score: 0.8, citations: [], }, { documentRef: `org/01900000-0000-7000-0000-000000000777/${storageKey}`, snippet: "other organization snippet", score: 0.7, citations: [], }, { documentRef: `org/${scope.orgId}/files/${scope.workspaceId}/${scope.projectId}/01900000-0000-7000-0000-000000000200`, snippet: "stale snippet", score: 0.6, citations: [], }, ]) const service = platformKnowledgeSearch(knowledgeClient(client), deps) const hits = await service.search(scope, { collectionName: "contracts", query: "contract", limit: 10, actorId: scope.actor.userId, }) expect(hits).toEqual([ { fileId, filename: "contract.txt", collectionName: "contracts", score: 0.9, chunk: 1, snippet: "own snippet", }, ]) expect(client.searches).toHaveLength(1) expect(client.searches[0]).toMatchObject({ collection: "contracts", query: "contract", limit: 10 }) expect(client.searches[0]).not.toHaveProperty("tenant") expect(client.searches[0]).not.toHaveProperty("ownerRef") }) it("refuses a foreign file id before any managed index call", async () => { const { data, deps } = makeFiles() const foreignFileId = await seedFile(data, otherScope, otherStorageKey) const client = stub() const service = platformKnowledgeSearch(knowledgeClient(client), deps) await expect( service.index(scope, { collectionName: "contracts", fileId: foreignFileId, filename: "other-project.txt", bytes: new TextEncoder().encode("foreign content"), }), ).rejects.toThrow() expect(client.indexed).toEqual([]) }) })