NODEDC_1C/llm_normalizer/backend/tests/addressQueryRuntimeM23.test.ts

163 lines
7.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, expect, it } from "vitest";
import { resolveAddressIntent } from "../src/services/addressIntentResolver";
import { classifyAddressQueryShape } from "../src/services/addressQueryShapeClassifier";
import { extractAddressFilters } from "../src/services/addressFilterExtractor";
import { AddressQueryService } from "../src/services/addressQueryService";
import { buildAddressRecipePlan, selectAddressRecipe } from "../src/services/addressRecipeCatalog";
describe("address query shape classifier", () => {
it("classifies explain question as deep-shape", () => {
const result = classifyAddressQueryShape("Why VAT chain does not match?");
expect(result.shape).toBe("EXPLAIN_OR_REASON");
expect(result.confidence).toBe("high");
});
it("classifies aggregate lookup question", () => {
const result = classifyAddressQueryShape("who owes us today?");
expect(result.shape).toBe("AGGREGATE_LOOKUP");
});
it("classifies compound factual question", () => {
const result = classifyAddressQueryShape("who owes us and who we owe today?");
expect(result.shape).toBe("COMPOUND_FACTUAL_QUERY");
});
});
describe("address intent resolver expansion (M2.3a)", () => {
it("resolves documents by counterparty intent", () => {
const result = resolveAddressIntent("show documents by counterparty Alfa from 2020-07-01 to 2020-07-31");
expect(result.intent).toBe("list_documents_by_counterparty");
});
it("resolves bank operations by counterparty intent", () => {
const result = resolveAddressIntent("show bank operations by counterparty Alfa");
expect(result.intent).toBe("bank_operations_by_counterparty");
});
it("resolves documents forming balance intent", () => {
const result = resolveAddressIntent("which documents form balance for account 62 as of 2020-07-31");
expect(result.intent).toBe("documents_forming_balance");
});
});
describe("address filter extraction for balance drilldown", () => {
it("defaults as_of_date for documents_forming_balance when date is omitted", () => {
const result = extractAddressFilters("which documents form balance for account 62", "documents_forming_balance");
expect(result.extracted_filters.account).toBe("62");
expect(result.extracted_filters.as_of_date).toBeDefined();
expect(result.missing_required_filters).toEqual([]);
});
it("cuts period tail from counterparty anchor", () => {
const result = extractAddressFilters(
"Покажи документы по контрагенту test_cp с 2020-07-01 по 2020-07-31",
"list_documents_by_counterparty"
);
expect(result.extracted_filters.counterparty).toBe("test_cp");
expect(result.extracted_filters.period_from).toBe("2020-07-01");
expect(result.extracted_filters.period_to).toBe("2020-07-31");
});
it("cuts all-time tail from counterparty anchor and skips 90-day default window", () => {
const result = extractAddressFilters(
"Покажи документы по контрагенту тестовый за все время",
"list_documents_by_counterparty"
);
expect(result.extracted_filters.counterparty).toBe("тестовый");
expect(result.extracted_filters.period_from).toBeUndefined();
expect(result.extracted_filters.period_to).toBeUndefined();
expect(result.warnings).not.toContain("period_defaulted_last_90_days");
});
});
describe("address query limited taxonomy and stage diagnostics", () => {
it("returns missing_anchor for open items without concrete counterparty/contract anchor", async () => {
const service = new AddressQueryService();
const result = await service.tryHandle("show open items by contract");
expect(result?.handled).toBe(true);
expect(result?.response_type).toBe("LIMITED_WITH_REASON");
expect(result?.debug.limited_reason_category).toBe("missing_anchor");
expect(result?.debug.mcp_call_status).toBe("skipped");
});
it("returns unsupported for not-implemented contract document list intent", async () => {
const service = new AddressQueryService();
const result = await service.tryHandle("show documents by contract 15/24");
expect(result?.handled).toBe(true);
expect(result?.response_type).toBe("LIMITED_WITH_REASON");
expect(result?.debug.limited_reason_category).toBe("unsupported");
expect(result?.debug.mcp_call_status).toBe("skipped");
});
it("includes resolver and row-stage diagnostics", async () => {
const service = new AddressQueryService();
const result = await service.tryHandle("which documents form balance for account 62 as of 2020-07-31");
expect(result?.handled).toBe(true);
expect(result?.response_type).toBe("LIMITED_WITH_REASON");
expect(result?.debug.anchor_type).toBe("account");
expect(result?.debug.rows_fetched).toBeTypeOf("number");
expect(result?.debug.raw_rows_received).toBeTypeOf("number");
expect(result?.debug.rows_after_account_scope).toBeTypeOf("number");
expect(result?.debug.rows_materialized).toBeTypeOf("number");
expect(result?.debug.rows_after_recipe_filter).toBeTypeOf("number");
expect(result?.debug.rows_matched).toBeTypeOf("number");
expect(["strict", "preferred"]).toContain(result?.debug.account_scope_mode);
expect(result?.debug.account_scope_fallback_applied).toBeTypeOf("boolean");
expect(result?.debug.mcp_call_status_legacy).toBeDefined();
expect(result?.debug.match_failure_stage).toBeDefined();
expect([
"no_raw_rows",
"raw_rows_received_but_not_materialized",
"materialized_but_not_anchor_matched",
"materialized_but_filtered_out_by_recipe",
"materialized_but_not_matched",
"matched_non_empty"
]).toContain(result?.debug.mcp_call_status);
expect(result?.debug.raw_row_keys_sample).toBeDefined();
expect(result?.debug.materialization_drop_reason).toBeDefined();
expect(result?.debug.account_scope_fields_checked).toBeDefined();
expect(result?.debug.account_scope_match_strategy).toBe("account_code_regex_plus_alias_map_v1");
expect(result?.debug.account_scope_drop_reason).toBeDefined();
});
});
describe("address recipe catalog counterparty filtering", () => {
it("boosts limit for all-time counterparty queries", () => {
const filters = extractAddressFilters(
"Покажи документы по контрагенту тестовый за все время",
"list_documents_by_counterparty"
).extracted_filters;
const selected = selectAddressRecipe("list_documents_by_counterparty", filters);
expect(selected.selected_recipe).toBeTruthy();
const plan = buildAddressRecipePlan(selected.selected_recipe!, filters);
expect(plan.limit).toBe(200);
});
it("boosts limit for english all-time counterparty queries", () => {
const filters = extractAddressFilters(
"show documents by counterparty test_cp for all time",
"list_documents_by_counterparty"
).extracted_filters;
const selected = selectAddressRecipe("list_documents_by_counterparty", filters);
expect(selected.selected_recipe).toBeTruthy();
const plan = buildAddressRecipePlan(selected.selected_recipe!, filters);
expect(plan.limit).toBe(200);
});
it("cuts english all-time tail from counterparty anchor", () => {
const result = extractAddressFilters(
"show documents by counterparty test_cp for all time",
"list_documents_by_counterparty"
);
expect(result.extracted_filters.counterparty).toBe("test_cp");
expect(result.extracted_filters.period_from).toBeUndefined();
expect(result.extracted_filters.period_to).toBeUndefined();
expect(result.warnings).not.toContain("period_defaulted_last_90_days");
});
});