Этап 4 corrective pack 2 по family isolation после текущих routing fixes
This commit is contained in:
@@ -201,7 +201,111 @@ describe.sequential("assistant MCP runtime bridge", () => {
|
||||
expect((liveSummary.required_live_calls as unknown[]).length).toBe(4);
|
||||
expect(Array.isArray(liveSummary.executed_live_calls)).toBe(true);
|
||||
expect((liveSummary.executed_live_calls as unknown[]).length).toBe(4);
|
||||
const rbpCallLimits = fetchMock.mock.calls.map(([, requestInit]) => {
|
||||
const init = requestInit as { body?: string };
|
||||
return Number(JSON.parse(String(init.body ?? "{}")).limit ?? 0);
|
||||
});
|
||||
expect(rbpCallLimits).toEqual([96, 96, 96, 128]);
|
||||
expect(liveSummary.matched_rows).toBeGreaterThan(0);
|
||||
expect(result.items.some((item) => Array.isArray((item as Record<string, unknown>).relation_pattern_hits))).toBe(true);
|
||||
});
|
||||
|
||||
it("uses claim-bound live call sequence for fixed-asset amortization coverage query", async () => {
|
||||
process.env[MCP_FLAG] = "1";
|
||||
process.env[MCP_PROXY] = "http://127.0.0.1:6003";
|
||||
process.env[MCP_CHANNEL] = "default";
|
||||
|
||||
const payload = JSON.stringify({
|
||||
success: true,
|
||||
data: [
|
||||
{
|
||||
period: "2020-07-31T00:00:00",
|
||||
registrator: "Начисление амортизации Июль 2020",
|
||||
account_dt: "20.01",
|
||||
account_kt: "02.01",
|
||||
amount: 2471.52
|
||||
},
|
||||
{
|
||||
period: "2020-07-31T00:00:00",
|
||||
registrator: "Начисление амортизации Июль 2020",
|
||||
account_dt: "20.01",
|
||||
account_kt: "02.01",
|
||||
amount: 2465.28
|
||||
}
|
||||
]
|
||||
});
|
||||
const fetchMock = vi.fn(async () => new Response(payload, { status: 200 }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const { AssistantDataLayer } = await import("../src/services/assistantDataLayer");
|
||||
const dataLayer = new AssistantDataLayer(createSnapshotRoot());
|
||||
const result = await dataLayer.executeRouteRuntime(
|
||||
"hybrid_store_plus_live",
|
||||
"31 июля начислена амортизация тремя суммами — 2 471,52, 2 465,28 и 849,83. Есть риск, что объект ОС не попал в амортизацию?"
|
||||
);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(4);
|
||||
const summary = result.summary as Record<string, unknown>;
|
||||
const liveSummary = summary.live_mcp as Record<string, unknown>;
|
||||
expect(liveSummary.claim_type).toBe("prove_fixed_asset_amortization_coverage");
|
||||
expect(liveSummary.source_profile).toBe("claim_bound_fa_live_path");
|
||||
expect(Array.isArray(liveSummary.required_live_calls)).toBe(true);
|
||||
expect((liveSummary.required_live_calls as unknown[]).length).toBe(4);
|
||||
expect(Array.isArray(liveSummary.executed_live_calls)).toBe(true);
|
||||
expect((liveSummary.executed_live_calls as unknown[]).length).toBe(4);
|
||||
const faCallLimits = fetchMock.mock.calls.map(([, requestInit]) => {
|
||||
const init = requestInit as { body?: string };
|
||||
return Number(JSON.parse(String(init.body ?? "{}")).limit ?? 0);
|
||||
});
|
||||
expect(faCallLimits).toEqual([96, 96, 128, 128]);
|
||||
expect(liveSummary.matched_rows).toBeGreaterThan(0);
|
||||
expect(result.items.some((item) => (item as Record<string, unknown>).fa_expected_set_candidate === true)).toBe(true);
|
||||
expect(result.items.some((item) => (item as Record<string, unknown>).fa_actual_set_candidate === true)).toBe(true);
|
||||
});
|
||||
|
||||
it("uses claim-bound VAT live path instead of supplier-tail generic probe for VAT chain query", async () => {
|
||||
process.env[MCP_FLAG] = "1";
|
||||
process.env[MCP_PROXY] = "http://127.0.0.1:6003";
|
||||
process.env[MCP_CHANNEL] = "default";
|
||||
|
||||
const payload = JSON.stringify({
|
||||
success: true,
|
||||
data: [
|
||||
{
|
||||
period: "2020-07-15T00:00:00",
|
||||
registrator: "Реализация товаров 0001",
|
||||
account_dt: "62.01",
|
||||
account_kt: "90.01",
|
||||
amount: 1400
|
||||
},
|
||||
{
|
||||
period: "2020-07-15T00:00:00",
|
||||
registrator: "Счет-фактура выданный 0001",
|
||||
account_dt: "90.03",
|
||||
account_kt: "68.02",
|
||||
amount: 233.33
|
||||
}
|
||||
]
|
||||
});
|
||||
const fetchMock = vi.fn(async () => new Response(payload, { status: 200 }));
|
||||
vi.stubGlobal("fetch", fetchMock);
|
||||
|
||||
const { AssistantDataLayer } = await import("../src/services/assistantDataLayer");
|
||||
const dataLayer = new AssistantDataLayer(createSnapshotRoot());
|
||||
const result = await dataLayer.executeRouteRuntime(
|
||||
"hybrid_store_plus_live",
|
||||
"По поставщику и счету-фактуре проверь НДС-цепочку: есть ли выпадение между документом, регистром и книгой покупок?"
|
||||
);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(4);
|
||||
const summary = result.summary as Record<string, unknown>;
|
||||
const liveSummary = summary.live_mcp as Record<string, unknown>;
|
||||
expect(liveSummary.claim_type).toBe("prove_vat_chain_completeness");
|
||||
expect(liveSummary.query_subject).toBe("vat_chain_conflict");
|
||||
expect(liveSummary.source_profile).toBe("claim_bound_vat_live_path");
|
||||
expect(Array.isArray(liveSummary.required_live_calls)).toBe(true);
|
||||
expect((liveSummary.required_live_calls as unknown[]).length).toBe(4);
|
||||
expect(Array.isArray(liveSummary.account_scope)).toBe(true);
|
||||
expect(liveSummary.account_scope).toEqual(["19", "68"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
resolveDomainPolarityGuard,
|
||||
resolveTemporalGuard
|
||||
} from "../src/services/assistantRuntimeGuards";
|
||||
import { applyTargetedEvidenceAcquisition, resolveClaimBoundAnchors } from "../src/services/assistantClaimBoundEvidence";
|
||||
import { inferP0DomainFromMessage } from "../src/services/investigationState";
|
||||
|
||||
function buildProblemUnit(input: {
|
||||
id: string;
|
||||
@@ -129,7 +131,7 @@ function buildRetrieval(input?: Partial<any>): any {
|
||||
|
||||
describe("stage4 blocker-pack runtime guards", () => {
|
||||
it("flags temporal anchor drift outside July 2020 snapshot", () => {
|
||||
const userMessage = "Почему по оплате от 6 июля 2020 долг по поставщику остался?";
|
||||
const userMessage = "Why supplier debt was not closed after payment on 06.07.2020?";
|
||||
const temporal = resolveTemporalGuard({
|
||||
userMessage,
|
||||
companyAnchors: resolveCompanyAnchors(userMessage),
|
||||
@@ -160,7 +162,7 @@ describe("stage4 blocker-pack runtime guards", () => {
|
||||
});
|
||||
|
||||
it("locks July month window when question has month-only anchor", () => {
|
||||
const userMessage = "В июльском срезе почему по счету 60 остался хвост?";
|
||||
const userMessage = "In July snapshot why does account 60 still have an open tail?";
|
||||
const temporal = resolveTemporalGuard({
|
||||
userMessage,
|
||||
companyAnchors: resolveCompanyAnchors(userMessage),
|
||||
@@ -182,7 +184,7 @@ describe("stage4 blocker-pack runtime guards", () => {
|
||||
expect(temporal.temporal_guard_outcome).toBe("passed");
|
||||
expect(temporal.resolved_time_anchor).toBe("2020-07");
|
||||
expect(temporal.effective_primary_period?.from).toBe("2020-07-01");
|
||||
expect(hintedPlan[0].fragment_text).toMatch(/июля 2020|2020-07-01/);
|
||||
expect(hintedPlan[0].fragment_text).toMatch(/2020-07-01|july 2020/i);
|
||||
});
|
||||
|
||||
it("filters customer settlement semantics from supplier/payable case", () => {
|
||||
@@ -409,5 +411,100 @@ describe("stage4 blocker-pack runtime guards", () => {
|
||||
expect(grounded.status).toBe("no_grounded_answer");
|
||||
expect(grounded.reasons.join(" ")).toMatch(/Недостаточно допустимого evidence|Temporal anchor/i);
|
||||
});
|
||||
|
||||
it("reconstructs fixed-asset expected vs actual coverage in claim-bound targeting", () => {
|
||||
const userMessage =
|
||||
"31 июля начислена амортизация тремя суммами — 2 471,52, 2 465,28 и 849,83. Есть риск, что объект ОС не попал в амортизацию?";
|
||||
const claimAudit = resolveClaimBoundAnchors({
|
||||
userMessage,
|
||||
focusDomainHint: "fixed_asset_amortization",
|
||||
companyAnchors: resolveCompanyAnchors(userMessage),
|
||||
primaryPeriod: {
|
||||
from: "2020-07-31",
|
||||
to: "2020-07-31",
|
||||
granularity: "day"
|
||||
}
|
||||
});
|
||||
|
||||
expect(claimAudit.claim_type).toBe("prove_fixed_asset_amortization_coverage");
|
||||
expect(claimAudit.required_anchors).toContain("fixed_asset_signal");
|
||||
expect(claimAudit.claim_anchor_resolution_rate).toBeGreaterThan(0.7);
|
||||
|
||||
const targeted = applyTargetedEvidenceAcquisition({
|
||||
claimAudit,
|
||||
retrievalResults: [
|
||||
buildRetrieval({
|
||||
items: [
|
||||
{
|
||||
source_entity: "MCPLiveMovement",
|
||||
source_id: "fa-1",
|
||||
display_name: "Станок A",
|
||||
period: "2020-07-31",
|
||||
account_debit: "20.01",
|
||||
account_credit: "02.01",
|
||||
relation_pattern_hits: ["asset_card_to_depreciation", "document_to_posting"],
|
||||
fa_object_hint: "Станок A",
|
||||
fa_expected_set_candidate: true,
|
||||
fa_actual_set_candidate: true,
|
||||
fa_coverage_status: "covered"
|
||||
},
|
||||
{
|
||||
source_entity: "MCPLiveMovement",
|
||||
source_id: "fa-2",
|
||||
display_name: "Станок B",
|
||||
period: "2020-07-31",
|
||||
account_debit: "20.01",
|
||||
account_credit: "02.01",
|
||||
relation_pattern_hits: ["asset_card_to_depreciation"],
|
||||
fa_object_hint: "Станок B",
|
||||
fa_expected_set_candidate: true,
|
||||
fa_actual_set_candidate: false,
|
||||
fa_coverage_status: "expected_only"
|
||||
}
|
||||
],
|
||||
evidence: []
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
expect(targeted.audit.check_status.expected_fa_set_reconstructed).toBe("found");
|
||||
expect(targeted.audit.check_status.actual_fa_set_reconstructed).toBe("found");
|
||||
expect(targeted.audit.check_status.movement_or_posting_link_found).toBe("found");
|
||||
expect(Array.isArray(targeted.audit.fa_expected_set)).toBe(true);
|
||||
expect(targeted.audit.fa_expected_set).toContain("станок a");
|
||||
expect(targeted.audit.fa_expected_set).toContain("станок b");
|
||||
expect(targeted.audit.fa_actual_set_from_amortization).toContain("станок a");
|
||||
expect(targeted.audit.fa_missing_candidates).toContain("станок b");
|
||||
expect((targeted.audit.fa_relation_map ?? []).length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("does not misclassify settlement 62.02 question into VAT or FA claim paths", () => {
|
||||
const userMessage =
|
||||
"Покупатель перечислил аванс на 62.02, но закрытие не произошло. Есть ли хвост по расчетам?";
|
||||
const claimAudit = resolveClaimBoundAnchors({
|
||||
userMessage,
|
||||
focusDomainHint: "settlements_60_62",
|
||||
companyAnchors: resolveCompanyAnchors(userMessage),
|
||||
primaryPeriod: {
|
||||
from: "2020-07-01",
|
||||
to: "2020-07-31",
|
||||
granularity: "month"
|
||||
}
|
||||
});
|
||||
|
||||
expect(claimAudit.claim_type).toBe("prove_advance_offset_state");
|
||||
expect(claimAudit.resolved_anchors.vat_signal).toHaveLength(0);
|
||||
expect(claimAudit.resolved_anchors.fixed_asset_signal).toHaveLength(0);
|
||||
expect(claimAudit.required_anchors).toContain("advance_signal");
|
||||
});
|
||||
|
||||
it("keeps VAT priority over supplier wording in shared domain inference", () => {
|
||||
const vatQuestion =
|
||||
"По поставщику и счету-фактуре проверь НДС-цепочку: есть ли выпадение между документом, регистром и книгой покупок?";
|
||||
const settlementQuestion = "Покупатель перечислил аванс на 62.02, но закрытие не произошло. Есть ли хвост?";
|
||||
|
||||
expect(inferP0DomainFromMessage(vatQuestion)).toBe("vat_document_register_book");
|
||||
expect(inferP0DomainFromMessage(settlementQuestion)).toBe("settlements_60_62");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user