test(intake): rules, PDF text, C2 idempotency, enrich-vs-candidates, pantry hand-off, Slack taps
Unit: merchant pattern, header validation, reconciliation tolerance, verbatim line items, one-call message shape, card action ids; unpdf over the two real Uber Eats exports (Coles $85.74 / 15 lines, Burgertory $22.40 / Michael + Joel). Integration: fetch stubbed at the LiteLLM and pantry boundaries so the PDF path, persistence, match and writes run for real against personal_test. intake-live.test.ts is opt-in (INTAKE_LIVE_TEST=1) and was run green against cloud-budget on both PDFs.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { readFileSync } from "fs";
|
||||
import { resolve } from "path";
|
||||
import { extractPdfText, liteLLMExtractor } from "../../lib/intake-extract";
|
||||
import { reconcileItems, toLineItems, validateHeader } from "../../lib/intake-rules";
|
||||
|
||||
/**
|
||||
* Opt-in: the real model over the real Burgertory export.
|
||||
*
|
||||
* INTAKE_LIVE_TEST=1 LITELLM_BASE_URL=http://localhost:4200 LITELLM_KEY=... npm test
|
||||
*
|
||||
* Skipped otherwise — CI has no LiteLLM, and a unit run must not depend on one.
|
||||
* What it proves is the thing the mock cannot: that `cloud-budget` keeps the
|
||||
* names verbatim ("Michael", "Joel", not "Burger") under the order-item prompt.
|
||||
*/
|
||||
const live = process.env.INTAKE_LIVE_TEST === "1" && !!process.env.LITELLM_BASE_URL && !!process.env.LITELLM_KEY;
|
||||
|
||||
describe.skipIf(!live)("live extraction via LiteLLM (opt-in)", () => {
|
||||
it("Burgertory PDF: header exact, two items named verbatim, reconciles", async () => {
|
||||
const text = await extractPdfText(readFileSync(resolve(__dirname, "../fixtures/intake/ubereats-burgertory-2026-08-19.pdf")));
|
||||
const extracted = await liteLLMExtractor()([{ kind: "text", text, name: "Receipt_19Aug2026.pdf" }]);
|
||||
const header = validateHeader(extracted);
|
||||
expect(header.ok && header.header).toEqual({ merchant: "Burgertory (Werribee)", order_date: "2026-08-19", total: 22.4 });
|
||||
const items = toLineItems(extracted.items);
|
||||
expect(items.map((i) => i.description)).toEqual(["Michael", "Joel"]);
|
||||
expect(reconcileItems(extracted).ok).toBe(true);
|
||||
}, 120_000);
|
||||
|
||||
it("Coles PDF: header exact, 15 items", async () => {
|
||||
const text = await extractPdfText(readFileSync(resolve(__dirname, "../fixtures/intake/ubereats-coles-2026-08-18.pdf")));
|
||||
const extracted = await liteLLMExtractor()([{ kind: "text", text, name: "Receipt_18Aug2026.pdf" }]);
|
||||
const header = validateHeader(extracted);
|
||||
expect(header.ok && header.header).toEqual({ merchant: "Coles (Wyndham Vale)", order_date: "2026-08-18", total: 85.74 });
|
||||
expect(toLineItems(extracted.items)).toHaveLength(15);
|
||||
expect(reconcileItems(extracted).ok).toBe(true);
|
||||
}, 120_000);
|
||||
});
|
||||
Reference in New Issue
Block a user