Этап 4 / Пакет по РБП восстановление живого контура сбора данных и доказательной базы
This commit is contained in:
@@ -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 } : {}),
|
||||
|
||||
Reference in New Issue
Block a user