Этап 4 / Пакет по РБП восстановление живого контура сбора данных и доказательной базы

This commit is contained in:
2026-03-29 10:38:04 +03:00
parent 095e74ad3b
commit 133b6dca3c
83 changed files with 265742 additions and 77 deletions
@@ -582,6 +582,159 @@ function toExecutionPlan(routeSummary, normalized, userMessage, requirementByFra
};
});
}
function enrichRbpFragmentForLive(fragmentText, temporalGuard) {
const base = compactWhitespace(String(fragmentText ?? ""));
const hints = ["Списание РБП", "объект РБП", "остаток на конец периода", "счет 97"];
const effective = temporalGuard && typeof temporalGuard === "object" ? temporalGuard.effective_primary_period : null;
if (effective && effective.from && effective.to) {
hints.push(`период ${effective.from}..${effective.to}`);
}
const hintText = hints.filter(Boolean).join(", ");
if (!base) {
return hintText;
}
if (/списани[ея]\s+рбп|счет\s*97|account\s*97|остат/i.test(base)) {
return base;
}
return `${base}; ${hintText}`;
}
function enforceRbpLiveRoutePlan(input) {
if (input.claimType !== "prove_rbp_tail_state") {
return {
executionPlan: input.executionPlan,
audit: null
};
}
const requiredLiveCalls = [
"find_rbp_writeoff_documents_in_period",
"find_rbp_object_movements_account_97",
"find_month_close_entries_linked_to_rbp",
"compute_end_period_residual_by_rbp_object"
];
let routeAdjusted = 0;
let rescuedNoRoute = 0;
const replacedRoutes = [];
const adjustedPlan = input.executionPlan.map((item) => {
if (!item || typeof item !== "object") {
return item;
}
if (item.should_execute !== true && item.no_route_reason === "insufficient_specificity") {
rescuedNoRoute += 1;
routeAdjusted += 1;
return {
...item,
route: "live_mcp_drilldown",
should_execute: true,
no_route_reason: null,
clarification_reason: null,
fragment_text: enrichRbpFragmentForLive(item.fragment_text, input.temporalGuard)
};
}
if (item.should_execute === true && item.route !== "hybrid_store_plus_live" && item.route !== "live_mcp_drilldown") {
routeAdjusted += 1;
if (item.route && item.route !== "no_route") {
replacedRoutes.push(String(item.route));
}
return {
...item,
route: "hybrid_store_plus_live",
fragment_text: enrichRbpFragmentForLive(item.fragment_text, input.temporalGuard)
};
}
if (item.should_execute === true) {
return {
...item,
fragment_text: enrichRbpFragmentForLive(item.fragment_text, input.temporalGuard)
};
}
return item;
});
return {
executionPlan: adjustedPlan,
audit: {
claim_type: "prove_rbp_tail_state",
required_live_calls: requiredLiveCalls,
route_adjustments_applied: routeAdjusted,
rescued_no_route_fragments: rescuedNoRoute,
replaced_routes: Array.from(new Set(replacedRoutes)),
route_gap_reason: routeAdjusted > 0 ? "rbp_claim_bound_live_route_override_applied" : null
}
};
}
function collectRbpLiveRouteAudit(input) {
if (input.claimType !== "prove_rbp_tail_state") {
return null;
}
const required = new Set(Array.isArray(input.planAudit?.required_live_calls) ? input.planAudit.required_live_calls : []);
const executed = [];
const missing = new Set();
const routeGaps = [];
let matchedRowsTotal = 0;
let returnedRowsTotal = 0;
let fetchedRowsTotal = 0;
for (const result of input.retrievalResults) {
if (!result || typeof result !== "object") {
continue;
}
const summary = result.summary && typeof result.summary === "object" ? result.summary : null;
const live = summary && typeof summary.live_mcp === "object" && summary.live_mcp ? summary.live_mcp : null;
if (!live) {
continue;
}
const requiredCalls = Array.isArray(live.required_live_calls) ? live.required_live_calls : [];
for (const callId of requiredCalls) {
required.add(String(callId ?? "").trim());
}
const executedCalls = Array.isArray(live.executed_live_calls) ? live.executed_live_calls : [];
for (const call of executedCalls) {
if (!call || typeof call !== "object") {
continue;
}
executed.push(call);
}
const missingCalls = Array.isArray(live.missing_live_calls) ? live.missing_live_calls : [];
for (const callId of missingCalls) {
const token = String(callId ?? "").trim();
if (token) {
missing.add(token);
}
}
const routeGapReason = String(live.route_gap_reason ?? "").trim();
if (routeGapReason) {
routeGaps.push(routeGapReason);
}
fetchedRowsTotal += Number(live.fetched_rows ?? 0) || 0;
matchedRowsTotal += Number(live.matched_rows ?? 0) || 0;
returnedRowsTotal += Number(live.returned_rows ?? 0) || 0;
}
const requiredList = Array.from(required).filter(Boolean);
const executedList = executed;
const missingFromExecuted = requiredList.filter((callId) => !executedList.some((item) => String(item.call_id ?? "") === callId));
for (const callId of missingFromExecuted) {
missing.add(callId);
}
const missingList = Array.from(missing);
const routeGapReason = missingList.length > 0
? "required_live_calls_not_executed"
: matchedRowsTotal <= 0
? "claim_live_calls_executed_but_zero_matches"
: routeGaps[0] ?? null;
const executionRate = requiredList.length > 0
? Number(((requiredList.length - missingList.length) / requiredList.length).toFixed(4))
: 1;
return {
claim_type: "prove_rbp_tail_state",
required_live_calls: requiredList,
executed_live_calls: executedList,
missing_live_calls: missingList,
route_gap_reason: routeGapReason,
live_route_execution_rate: executionRate,
fetched_rows_total: fetchedRowsTotal,
matched_rows_total: matchedRowsTotal,
returned_rows_total: returnedRowsTotal,
plan_override: input.planAudit ?? null
};
}
function toDebugRoutes(routeSummary) {
if (!routeSummary) {
return [];
@@ -1433,6 +1586,12 @@ export class AssistantService {
const resolvedRouteSummary = businessScopeResolution.route_summary_resolved;
const requirementExtraction = extractRequirements(resolvedRouteSummary, normalized.normalized, userMessage);
let executionPlan = toExecutionPlan(resolvedRouteSummary, normalized.normalized, userMessage, requirementExtraction.byFragment);
const rbpRoutePlanEnforcement = enforceRbpLiveRoutePlan({
executionPlan,
claimType: claimAnchorAudit.claim_type,
temporalGuard
});
executionPlan = rbpRoutePlanEnforcement.executionPlan;
executionPlan = (0, assistantRuntimeGuards_1.applyTemporalHintToExecutionPlan)(executionPlan, temporalGuard);
executionPlan = (0, assistantRuntimeGuards_1.applyPolarityHintToExecutionPlan)(executionPlan, domainPolarityGuardInitial);
const retrievalCalls = [];
@@ -1515,6 +1674,11 @@ export class AssistantService {
userMessage
});
retrievalResults = evidenceGateResult.retrievalResults;
const rbpLiveRouteAudit = collectRbpLiveRouteAudit({
claimType: claimAnchorAudit.claim_type,
retrievalResults,
planAudit: rbpRoutePlanEnforcement.audit
});
const coverageEvaluation = evaluateCoverage(requirementExtraction.requirements, retrievalResults);
const groundingCheckBase = checkGrounding(userMessage, coverageEvaluation.requirements, coverageEvaluation.coverage, retrievalResults);
const groundedAnswerEligibilityGuard = (0, assistantRuntimeGuards_1.evaluateGroundedAnswerEligibility)({
@@ -1627,6 +1791,7 @@ export class AssistantService {
claim_anchor_audit: claimAnchorAudit,
targeted_evidence_acquisition: targetedEvidenceResult.audit,
evidence_admissibility_gate: evidenceGateResult.audit,
...(rbpLiveRouteAudit ? { rbp_live_route_audit: rbpLiveRouteAudit } : {}),
eligibility_time_basis: groundedAnswerEligibilityGuard.eligibility_time_basis,
grounded_answer_eligibility_guard: groundedAnswerEligibilityGuard,
...(followupBinding.usage ? { followup_state_usage: followupBinding.usage } : {}),