import { describe, it, expect } from "vitest"; import { formatStandingRulesBlock, resolveActiveRules, activeRuleSet, queryActiveRuleCandidates, type RuleCandidate, } from "./index.js"; // A fake Neo4j session that dispatches on query text: the owner-resolution // query (matches `role: 'owner'`) returns a configurable owner userId or none; // the candidate query (matches HAS_PREFERENCE) returns configurable pref rows // and asserts it was pinned to the resolved owner userId. function fakeSession(opts: { ownerId?: string | null; ownerThrows?: boolean; prefRows?: Array>; }) { return { calls: [] as string[], candidateRuns: 0, async run(q: string, p: Record) { this.calls.push(q); if (/role:\s*'owner'/.test(q)) { if (opts.ownerThrows) throw new Error("neo4j down"); const recs = opts.ownerId ? [{ get: (_k: string) => opts.ownerId }] : []; return { records: recs }; } // candidate query — must be pinned to the resolved owner userId this.candidateRuns++; expect(p.ownerUserId).toBe(opts.ownerId); return { records: (opts.prefRows ?? []).map((r) => ({ get: (k: string) => r[k], })), }; }, }; } const prefRow = (over: Partial): Record => ({ preferenceId: "p", category: "communication", key: "k", value: "v", confidence: 0.6, observedAt: "2026-07-01T00:00:00Z", embedding: null, ...over, }); describe("resolveActiveRules — owner-scoped, uncapped, verbatim", () => { it("returns the owner's prefs with source=owner when an owner exists", async () => { const s = fakeSession({ ownerId: "owner-35fed05e", prefRows: [ prefRow({ preferenceId: "a", value: "brand", confidence: 0.9 }), prefRow({ preferenceId: "b", value: "pricing", confidence: 0.7 }), prefRow({ preferenceId: "c", value: "tender", confidence: 0.5 }), ], }); const res = await resolveActiveRules(s, "acct-1"); expect(res.source).toBe("owner"); expect(res.ownerUserId).toBe("owner-35fed05e"); expect(res.rules.map((r) => r.preferenceId)).toEqual(["a", "b", "c"]); expect(s.candidateRuns).toBe(1); }); it("returns MORE than 12 candidates with no cap and no truncation", async () => { const rows = Array.from({ length: 20 }, (_, i) => prefRow({ preferenceId: `p${i}`, value: `rule ${i}`, confidence: 1 - i * 0.01, }), ); const s = fakeSession({ ownerId: "owner-x", prefRows: rows }); const res = await resolveActiveRules(s, "acct-1"); expect(res.rules.length).toBe(20); expect(res.rules.map((r) => r.preferenceId)).toEqual( rows.map((r) => r.preferenceId), ); }); it("preserves the candidate order verbatim (no reordering, no dedup)", async () => { // Two rows that a cosine dedup would once have folded (identical embeddings) // are BOTH returned now — injection never dedups. const s = fakeSession({ ownerId: "owner-1", prefRows: [ prefRow({ preferenceId: "a", value: "use header A", embedding: [1, 0, 0, 0] }), prefRow({ preferenceId: "b", value: "use header A restated", embedding: [1, 0, 0, 0] }), ], }); const res = await resolveActiveRules(s, "acct-1"); expect(res.rules.map((r) => r.preferenceId)).toEqual(["a", "b"]); }); it("returns empty with source=no-owner and never runs the candidate query", async () => { const s = fakeSession({ ownerId: null }); const res = await resolveActiveRules(s, "acct-1"); expect(res.source).toBe("no-owner"); expect(res.ownerUserId).toBeNull(); expect(res.rules).toEqual([]); expect(s.candidateRuns).toBe(0); }); it("returns empty with source=owner when the owner has zero prefs", async () => { const s = fakeSession({ ownerId: "owner-x", prefRows: [] }); const res = await resolveActiveRules(s, "acct-1"); expect(res.source).toBe("owner"); expect(res.ownerUserId).toBe("owner-x"); expect(res.rules).toEqual([]); expect(s.candidateRuns).toBe(1); }); it("degrades to empty with source=owner-error on an owner-resolution failure (never throws)", async () => { const s = fakeSession({ ownerThrows: true }); const res = await resolveActiveRules(s, "acct-1"); expect(res.source).toBe("owner-error"); expect(res.ownerUserId).toBeNull(); expect(res.rules).toEqual([]); expect(s.candidateRuns).toBe(0); }); it("activeRuleSet returns just the owner's rule array", async () => { const s = fakeSession({ ownerId: "owner-1", prefRows: [prefRow({ preferenceId: "a" })], }); const rules = await activeRuleSet(s, "acct-1"); expect(rules.map((r) => r.preferenceId)).toEqual(["a"]); }); it("queryActiveRuleCandidates stays owner-scoped (empty on no owner)", async () => { const s = fakeSession({ ownerId: null }); expect(await queryActiveRuleCandidates(s, "acct-1")).toEqual([]); }); }); describe("formatStandingRulesBlock", () => { it("returns empty string for no rules", () => { expect(formatStandingRulesBlock([])).toBe(""); }); it("renders every rule, with no cap", () => { const rules = Array.from({ length: 20 }, (_, i) => ({ preferenceId: `p${i}`, category: "communication", key: `k${i}`, value: `rule ${i}`, confidence: 1 - i * 0.01, observedAt: "2026-07-01T00:00:00Z", })); const block = formatStandingRulesBlock(rules); expect(block).toContain("## Standing rules"); expect((block.match(/^- /gm) ?? []).length).toBe(20); }); });