|
6 | 6 | fetchDenseCandidates, |
7 | 7 | hnswEfSearch, |
8 | 8 | snippet, |
| 9 | + toHit, |
9 | 10 | type CandidateRow, |
10 | 11 | } from "./search.ts"; |
11 | 12 |
|
@@ -523,3 +524,69 @@ describe("fetchDenseCandidates kind/entity filtering", () => { |
523 | 524 | expect(chunkIds).toContain("chunk-note"); |
524 | 525 | }); |
525 | 526 | }); |
| 527 | + |
| 528 | +describe("toHit — wire attribution (CL-5870)", () => { |
| 529 | + it("surfaces provenance, temporal, corroboration, and derived_from on the hit", () => { |
| 530 | + const hit = toHit( |
| 531 | + candidate({ |
| 532 | + provenance: "inferred", |
| 533 | + sourceClass: "derived", |
| 534 | + temporalClass: "state", |
| 535 | + validUntil: new Date("2026-12-01T00:00:00Z"), |
| 536 | + supports: 2, |
| 537 | + contradicts: 0, |
| 538 | + derivedFrom: ["kv_source_1", "kv_source_2"], |
| 539 | + generatorAgentId: "resident-distiller", |
| 540 | + createdByKind: "agent", |
| 541 | + }), |
| 542 | + ); |
| 543 | + expect(hit.version_id).toBe("ver_1"); |
| 544 | + expect(hit.provenance).toBe("inferred"); |
| 545 | + expect(hit.source_class).toBe("derived"); |
| 546 | + expect(hit.temporal_class).toBe("state"); |
| 547 | + expect(hit.valid_until).toBe("2026-12-01T00:00:00.000Z"); |
| 548 | + expect(hit.supports).toBe(2); |
| 549 | + expect(hit.contradicts).toBe(0); |
| 550 | + expect(hit.derived_from).toEqual(["kv_source_1", "kv_source_2"]); |
| 551 | + expect(hit.generator_agent_id).toBe("resident-distiller"); |
| 552 | + expect(hit.created_by_kind).toBe("agent"); |
| 553 | + }); |
| 554 | + |
| 555 | + it("omits optional attribution fields when absent (additive wire)", () => { |
| 556 | + const hit = toHit(candidate()); |
| 557 | + expect(hit.provenance).toBeUndefined(); |
| 558 | + expect(hit.source_class).toBeUndefined(); |
| 559 | + expect(hit.derived_from).toBeUndefined(); |
| 560 | + expect(hit.generator_agent_id).toBeUndefined(); |
| 561 | + expect(hit.supports).toBe(0); |
| 562 | + expect(hit.contradicts).toBe(0); |
| 563 | + expect(hit.temporal_class).toBe("event"); |
| 564 | + }); |
| 565 | + |
| 566 | + it("distinguishes stated human vs inferred agent attribution shapes", () => { |
| 567 | + const human = toHit( |
| 568 | + candidate({ |
| 569 | + provenance: "stated", |
| 570 | + sourceClass: "native", |
| 571 | + createdByKind: "human", |
| 572 | + generatorAgentId: null, |
| 573 | + }), |
| 574 | + ); |
| 575 | + const distilled = toHit( |
| 576 | + candidate({ |
| 577 | + provenance: "inferred", |
| 578 | + sourceClass: "derived", |
| 579 | + createdByKind: "agent", |
| 580 | + generatorAgentId: "resident-distiller", |
| 581 | + derivedFrom: ["kv_raw"], |
| 582 | + }), |
| 583 | + ); |
| 584 | + expect(human.provenance).toBe("stated"); |
| 585 | + expect(human.created_by_kind).toBe("human"); |
| 586 | + expect(human.generator_agent_id).toBeUndefined(); |
| 587 | + expect(distilled.provenance).toBe("inferred"); |
| 588 | + expect(distilled.created_by_kind).toBe("agent"); |
| 589 | + expect(distilled.generator_agent_id).toBe("resident-distiller"); |
| 590 | + expect(distilled.derived_from).toEqual(["kv_raw"]); |
| 591 | + }); |
| 592 | +}); |
0 commit comments