feat(evidence): use server-side Qdrant BM25 retrieval

This commit is contained in:
2026-08-24 18:15:33 +02:00
parent 0e9add09a9
commit 29d41ac258
15 changed files with 253 additions and 34 deletions
@@ -13,7 +13,6 @@ export interface EvidenceJobState {
export interface EvidencePreprocessingDependencies {
runStage(argv: string[]): Promise<Record<string, unknown>>;
persistJob(): void;
semanticPreflight(): Promise<{ ok: true } | { ok: false; code: SemanticFailureCode }>;
evidencePreflight(): Promise<{ ok: true } | { ok: false; code: SemanticFailureCode }>;
requireRunId(value: unknown): string;
numberRecord(value: unknown): Record<string, number> | undefined;
@@ -139,9 +138,9 @@ export async function preprocessEvidence(
}
const policy = evidencePolicy(request.evidence, request.httpPrivateHostAllowlist);
if (policy) return policy;
const semantic = await deps.evidencePreflight();
if (!semantic.ok) {
return { status: "failed", code: semantic.code, runId: request.job.runId };
const preflight = await deps.evidencePreflight();
if (!preflight.ok) {
return { status: "failed", code: preflight.code, runId: request.job.runId };
}
if (request.job.completedStages.includes("evidence") && !request.dryRun) {
return {
@@ -412,7 +412,6 @@ export class WorkspacePreprocessingService {
return {
runStage: async (argv) => await this.runJsonStage(scope.runtime, argv),
persistJob: () => this.state(scope.runtime.workspaceId).writeJob(scope.job),
semanticPreflight: async () => await this.deps.semanticPreflight(scope.runtime.workspace),
evidencePreflight: async () => await this.deps.evidencePreflight(scope.runtime.workspace),
requireRunId: (value) => this.requireRunId(value),
numberRecord: (value) => this.numberRecord(value),
@@ -39,13 +39,11 @@ function job(overrides: Partial<EvidenceJobState> = {}): EvidenceJobState {
function dependencies(payload: Record<string, unknown> = {}): EvidencePreprocessingDependencies & {
runStage: ReturnType<typeof vi.fn>;
persistJob: ReturnType<typeof vi.fn>;
semanticPreflight: ReturnType<typeof vi.fn>;
evidencePreflight: ReturnType<typeof vi.fn>;
} {
return {
runStage: vi.fn(async () => payload),
persistJob: vi.fn(),
semanticPreflight: vi.fn(async () => ({ ok: true as const })),
evidencePreflight: vi.fn(async () => ({ ok: true as const })),
requireRunId(value) {
if (typeof value !== "string" || !/^[0-9a-f]{32}$/.test(value)) {
@@ -72,7 +70,6 @@ test("Evidence maintenance preflights the additive BM25 contract before starting
);
expect(deps.evidencePreflight).toHaveBeenCalledOnce();
expect(deps.semanticPreflight).not.toHaveBeenCalled();
expect(deps.runStage).toHaveBeenCalledWith([
"preprocess", "evidence", "--resume", "b".repeat(32), "--json", "-c", "/dev/fd/3",
]);
@@ -104,7 +101,6 @@ test("owns Evidence egress refusal before shared semantic infrastructure", async
);
expect(result).toEqual({ status: "failed", code: "egress_policy_refused" });
expect(deps.semanticPreflight).not.toHaveBeenCalled();
expect(deps.runStage).not.toHaveBeenCalled();
expect(deps.persistJob).not.toHaveBeenCalled();
});