154 lines
6.2 KiB
TypeScript
154 lines
6.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import { buildDeepAnalysisDebugPayload } from "../src/services/assistantDebugPayloadAssembler";
|
||
|
||
function baseInput() {
|
||
return {
|
||
traceId: "trace-1",
|
||
promptVersion: "normalizer_v2_0_2",
|
||
schemaVersion: "normalized_query_v2_0_2",
|
||
fallbackType: "none",
|
||
routeSummary: { mode: "deterministic_v2" },
|
||
fragments: [{ fragment_id: "F1" }],
|
||
requirementsExtracted: [{ requirement_id: "R1", status: "covered" }],
|
||
coverageReport: { requirements_total: 1, requirements_covered: 1 },
|
||
routes: [{ fragment_id: "F1", route: "hybrid_store_plus_live" }],
|
||
retrievalStatus: [
|
||
{
|
||
fragment_id: "F1",
|
||
requirement_ids: ["R1"],
|
||
route: "hybrid_store_plus_live",
|
||
status: "ok",
|
||
result_type: "summary"
|
||
}
|
||
],
|
||
retrievalResults: [{ fragment_id: "F1", status: "ok" }],
|
||
groundingCheck: { status: "grounded" },
|
||
droppedIntentSegments: [],
|
||
questionTypeClass: "factual_lookup",
|
||
companyAnchors: { companies: ["demo"] },
|
||
runtimeAnalysisContext: {
|
||
active: true,
|
||
as_of_date: "2020-07-31",
|
||
period_from: null,
|
||
period_to: null,
|
||
source: "eval_analysis_date",
|
||
snapshot_mode: "auto" as const
|
||
},
|
||
businessScopeResolution: {
|
||
business_scope_raw: ["company_specific_accounting"],
|
||
business_scope_resolved: ["company_specific_accounting"],
|
||
company_grounding_applied: true,
|
||
scope_resolution_reason: ["resolved"]
|
||
},
|
||
temporalGuard: {
|
||
raw_time_anchor: "2020-07",
|
||
raw_time_scope: "month",
|
||
resolved_time_anchor: "2020-07",
|
||
resolved_primary_period: { from: "2020-07-01", to: "2020-07-31", granularity: "day" },
|
||
effective_primary_period: { from: "2020-07-01", to: "2020-07-31", granularity: "day" },
|
||
temporal_guard_input: "2020-07",
|
||
temporal_alignment_status: "aligned",
|
||
temporal_resolution_source: "analysis_context",
|
||
temporal_guard_basis: "analysis_context",
|
||
temporal_guard_applied: true,
|
||
temporal_guard_outcome: "pass"
|
||
},
|
||
polarityAudit: {
|
||
raw_numeric_tokens: ["60.01"],
|
||
classified_numeric_tokens: [{ token: "60.01" }],
|
||
rejected_as_non_accounts: [],
|
||
resolved_account_anchors: ["60.01"]
|
||
},
|
||
claimAnchorAudit: {
|
||
settlement_role: "supplier",
|
||
settlement_role_resolution_reason: ["account_60_detected"],
|
||
polarity_resolution_status: "resolved"
|
||
},
|
||
targetedEvidenceAudit: { targeted_evidence_hit_rate: 1 },
|
||
evidenceAdmissibilityGateAudit: { admissible_evidence_count: 1 },
|
||
rbpLiveRouteAudit: null,
|
||
faLiveRouteAudit: null,
|
||
groundedAnswerEligibilityGuard: { eligibility_time_basis: "analysis_context", eligible: true },
|
||
followupStateUsage: null,
|
||
compositionDebug: {
|
||
problem_centric_answer_applied: true,
|
||
problem_units_used_count: 2,
|
||
problem_answer_mode: "stage3_lifecycle_aware_v1",
|
||
problem_unit_ids_used: ["pu-1", "pu-2"]
|
||
},
|
||
addressRuntimeMetaForDeep: {
|
||
attempted: true,
|
||
applied: true,
|
||
reason: "ok",
|
||
provider: "openai",
|
||
fallbackRuleHit: null,
|
||
toolGateDecision: "run_address_lane",
|
||
toolGateReason: "detected",
|
||
predecomposeContract: { schema_version: "x" },
|
||
orchestrationContract: { schema_version: "y" }
|
||
},
|
||
outcomeClassV1: "FULLY_ANSWERED",
|
||
assistantOrchestrationContractsV1: { query_frame: {}, execution_plan: {}, evidence_bundle: {}, coverage: {} },
|
||
answerStructureV11: { schema_version: "answer_structure_v1_1" },
|
||
assistantReply: [
|
||
"Коротко: Признак проблемы подтвержден частично.",
|
||
"Что именно проверено:\n- Проверен учетный контур.",
|
||
"Что найдено:\n- Есть признак разрыва цепочки.",
|
||
"Что пока не доказано:\n- Не хватает части подтверждений.",
|
||
"Что проверить первым:\n- Уточнить период."
|
||
].join("\n\n"),
|
||
investigationStateSnapshot: { status: "active" },
|
||
normalizedPayload: { schema_version: "normalized_query_v2_0_2" }
|
||
};
|
||
}
|
||
|
||
describe("assistant debug payload assembler", () => {
|
||
it("builds deep debug payload with analysis context and optional sections", () => {
|
||
const payload = buildDeepAnalysisDebugPayload(baseInput());
|
||
|
||
expect(payload.trace_id).toBe("trace-1");
|
||
expect(payload.analysis_context_applied).toBe(true);
|
||
expect(payload.analysis_context).toMatchObject({
|
||
as_of_date: "2020-07-31",
|
||
source: "eval_analysis_date"
|
||
});
|
||
expect(payload.problem_unit_ids_used).toEqual(["pu-1", "pu-2"]);
|
||
expect(payload.address_llm_predecompose_applied).toBe(true);
|
||
expect(payload.assistant_outcome_class_v1).toBe("FULLY_ANSWERED");
|
||
expect(payload.answer_contract_stage4_v1?.is_stage4_shape).toBe(true);
|
||
});
|
||
|
||
it("omits optional fields when they are not provided", () => {
|
||
const input = baseInput();
|
||
input.runtimeAnalysisContext.active = false;
|
||
input.followupStateUsage = null;
|
||
input.compositionDebug.problem_unit_ids_used = [];
|
||
input.rbpLiveRouteAudit = null;
|
||
input.faLiveRouteAudit = null;
|
||
input.addressRuntimeMetaForDeep = null;
|
||
|
||
const payload = buildDeepAnalysisDebugPayload(input);
|
||
|
||
expect(payload.analysis_context).toBeNull();
|
||
expect(Object.prototype.hasOwnProperty.call(payload, "followup_state_usage")).toBe(false);
|
||
expect(Object.prototype.hasOwnProperty.call(payload, "problem_unit_ids_used")).toBe(false);
|
||
expect(payload.address_llm_predecompose_applied).toBe(false);
|
||
expect(payload.address_llm_predecompose_contract).toBeNull();
|
||
});
|
||
|
||
it("marks non-stage4 answer shapes in contract audit", () => {
|
||
const input = baseInput();
|
||
input.assistantReply = [
|
||
"Коротко: Есть проблема.",
|
||
"Что сломано:\n- Разрыв перехода.",
|
||
"Ограничения:\n- Частичная опора."
|
||
].join("\n\n");
|
||
|
||
const payload = buildDeepAnalysisDebugPayload(input);
|
||
|
||
expect(payload.answer_contract_stage4_v1?.is_stage4_shape).toBe(false);
|
||
expect(payload.answer_contract_stage4_v1?.legacy_blocks_present).toContain("Что сломано");
|
||
expect(payload.answer_contract_stage4_v1?.legacy_blocks_present).toContain("Ограничения");
|
||
});
|
||
});
|