Этап 4 / Волна 19.2 исправление живого replay-контура для слоя адресного сбора доказательной базы
This commit is contained in:
@@ -576,6 +576,8 @@ export interface TemporalGuardAudit {
|
||||
raw_time_scope: string | null;
|
||||
resolved_time_anchor: string | null;
|
||||
resolved_primary_period: TemporalWindow | null;
|
||||
effective_primary_period: TemporalWindow | null;
|
||||
temporal_guard_input: string | null;
|
||||
temporal_alignment_status: TemporalAlignmentStatus;
|
||||
temporal_resolution_source: string;
|
||||
temporal_guard_basis: "resolved_primary_period" | "raw_time_scope_unlocked" | "none";
|
||||
@@ -620,6 +622,14 @@ function inferPrimaryWindowFromAnchor(anchor: string | null): TemporalWindow | n
|
||||
};
|
||||
}
|
||||
|
||||
function toTemporalGuardInput(window: TemporalWindow | null, fallback: string | null): string | null {
|
||||
if (window) {
|
||||
return `${window.from}..${window.to}`;
|
||||
}
|
||||
const value = String(fallback ?? "").trim();
|
||||
return value || null;
|
||||
}
|
||||
|
||||
export function resolveTemporalGuard(input: {
|
||||
userMessage: string;
|
||||
normalized: NormalizedPayload | null | undefined;
|
||||
@@ -631,11 +641,14 @@ export function resolveTemporalGuard(input: {
|
||||
const reasonCodes: string[] = [];
|
||||
if (!julyAnchor.applyGuard) {
|
||||
const resolvedWindow = inferPrimaryWindowFromAnchor(normalizedAnchor.value);
|
||||
const guardInput = toTemporalGuardInput(resolvedWindow, normalizedAnchor.value);
|
||||
return {
|
||||
raw_time_anchor: julyAnchor.raw,
|
||||
raw_time_scope: normalizedAnchor.value,
|
||||
resolved_time_anchor: normalizedAnchor.value,
|
||||
resolved_primary_period: resolvedWindow,
|
||||
effective_primary_period: resolvedWindow,
|
||||
temporal_guard_input: guardInput,
|
||||
temporal_alignment_status: normalizedAnchor.value ? "aligned" : "conflicting",
|
||||
temporal_resolution_source: normalizedAnchor.source,
|
||||
temporal_guard_basis: normalizedAnchor.value ? "raw_time_scope_unlocked" : "none",
|
||||
@@ -662,11 +675,16 @@ export function resolveTemporalGuard(input: {
|
||||
reasonCodes.push("missing_time_anchor_under_snapshot_lock");
|
||||
}
|
||||
const allowedContextWindow = buildAllowedContextWindow(julyAnchor.window);
|
||||
const resolvedPrimaryPeriod = julyAnchor.window;
|
||||
const effectivePrimaryPeriod = resolvedPrimaryPeriod ?? inferPrimaryWindowFromAnchor(julyAnchor.resolved ?? normalizedAnchor.value);
|
||||
const guardInput = toTemporalGuardInput(effectivePrimaryPeriod, julyAnchor.resolved ?? normalizedAnchor.value);
|
||||
return {
|
||||
raw_time_anchor: julyAnchor.raw,
|
||||
raw_time_scope: normalizedAnchor.value,
|
||||
resolved_time_anchor: julyAnchor.resolved ?? normalizedAnchor.value,
|
||||
resolved_primary_period: julyAnchor.window,
|
||||
resolved_primary_period: resolvedPrimaryPeriod,
|
||||
effective_primary_period: effectivePrimaryPeriod,
|
||||
temporal_guard_input: guardInput,
|
||||
temporal_alignment_status: temporalAlignmentStatus,
|
||||
temporal_resolution_source: julyAnchor.source,
|
||||
temporal_guard_basis: julyAnchor.window ? "resolved_primary_period" : "none",
|
||||
@@ -690,10 +708,11 @@ export function applyTemporalHintToExecutionPlan<
|
||||
if (!temporal.temporal_guard_applied) {
|
||||
return executionPlan;
|
||||
}
|
||||
const primaryWindow = temporal.effective_primary_period ?? temporal.primary_period_window;
|
||||
const hint =
|
||||
temporal.primary_period_window?.granularity === "day" && temporal.resolved_time_anchor
|
||||
primaryWindow?.granularity === "day" && temporal.resolved_time_anchor
|
||||
? `primary period ${temporal.resolved_time_anchor}; controlled temporal expansion only for linked entities`
|
||||
: `primary period July 2020 (${JULY_WINDOW.from}..${JULY_WINDOW.to}); controlled temporal expansion only for linked entities`;
|
||||
: `primary period July 2020 (${primaryWindow?.from ?? JULY_WINDOW.from}..${primaryWindow?.to ?? JULY_WINDOW.to}); controlled temporal expansion only for linked entities`;
|
||||
return executionPlan.map((item) => {
|
||||
if (!item.should_execute) {
|
||||
return item;
|
||||
@@ -1145,6 +1164,10 @@ function withinAllowedContextWindow(normalizedPeriod: string, temporal: Temporal
|
||||
return normalizedPeriod >= temporal.allowed_context_window.from && normalizedPeriod <= temporal.allowed_context_window.to;
|
||||
}
|
||||
|
||||
function effectivePrimaryPeriodWindow(temporal: TemporalGuardAudit): TemporalWindow | null {
|
||||
return temporal.effective_primary_period ?? temporal.primary_period_window;
|
||||
}
|
||||
|
||||
function evidenceAdmissibilityReasons(input: {
|
||||
evidence: EvidenceItem;
|
||||
temporal: TemporalGuardAudit;
|
||||
@@ -1160,14 +1183,15 @@ function evidenceAdmissibilityReasons(input: {
|
||||
reasons.add("zero_live_match");
|
||||
}
|
||||
const period = extractEvidencePeriod(input.evidence);
|
||||
if (period && input.temporal.primary_period_window) {
|
||||
const primaryWindow = effectivePrimaryPeriodWindow(input.temporal);
|
||||
if (period && primaryWindow) {
|
||||
const normalized = normalizeEvidenceDate(period);
|
||||
const expansionMeta = evidenceContextExpansionMeta(input.evidence);
|
||||
if (normalized && !isPeriodWithinWindow(normalized, input.temporal.primary_period_window)) {
|
||||
if (normalized && !isPeriodWithinWindow(normalized, primaryWindow)) {
|
||||
const insideAllowed = withinAllowedContextWindow(normalized, input.temporal);
|
||||
if (insideAllowed && expansionMeta.allowed && expansionMeta.reason) {
|
||||
// Allowed controlled temporal expansion: period is outside primary but linked and explained.
|
||||
} else if (normalized > input.temporal.primary_period_window.to && !insideAllowed) {
|
||||
} else if (normalized > primaryWindow.to && !insideAllowed) {
|
||||
reasons.add("future_dated_or_out_of_window");
|
||||
} else {
|
||||
reasons.add("wrong_period");
|
||||
@@ -1217,14 +1241,15 @@ function itemRejectReasons(input: {
|
||||
reasons.add("zero_live_match");
|
||||
}
|
||||
const period = itemPeriod(input.item);
|
||||
if (period && input.temporal.primary_period_window) {
|
||||
const primaryWindow = effectivePrimaryPeriodWindow(input.temporal);
|
||||
if (period && primaryWindow) {
|
||||
const normalized = normalizeEvidenceDate(period);
|
||||
const expansionMeta = itemContextExpansionMeta(input.item);
|
||||
if (normalized && !isPeriodWithinWindow(normalized, input.temporal.primary_period_window)) {
|
||||
if (normalized && !isPeriodWithinWindow(normalized, primaryWindow)) {
|
||||
const insideAllowed = withinAllowedContextWindow(normalized, input.temporal);
|
||||
if (insideAllowed && expansionMeta.allowed && expansionMeta.reason) {
|
||||
// Allowed controlled temporal expansion: period is outside primary but linked and explained.
|
||||
} else if (normalized > input.temporal.primary_period_window.to && !insideAllowed) {
|
||||
} else if (normalized > primaryWindow.to && !insideAllowed) {
|
||||
reasons.add("future_dated_or_out_of_window");
|
||||
} else {
|
||||
reasons.add("wrong_period");
|
||||
|
||||
@@ -159,6 +159,104 @@ function resolveBusinessScopeAlignment(input) {
|
||||
route_summary_resolved: resolvedSummary
|
||||
};
|
||||
}
|
||||
function isJuly2020TemporalResolved(temporalGuard) {
|
||||
if (!temporalGuard || typeof temporalGuard !== "object") {
|
||||
return false;
|
||||
}
|
||||
const resolvedAnchor = String(temporalGuard.resolved_time_anchor ?? "").trim();
|
||||
if (/^2020-07(?:-\d{2})?$/.test(resolvedAnchor)) {
|
||||
return true;
|
||||
}
|
||||
const effective = temporalGuard.effective_primary_period && typeof temporalGuard.effective_primary_period === "object"
|
||||
? temporalGuard.effective_primary_period
|
||||
: null;
|
||||
if (effective) {
|
||||
const from = String(effective.from ?? "").trim();
|
||||
const to = String(effective.to ?? "").trim();
|
||||
if (/^2020-07-\d{2}$/.test(from) && /^2020-07-\d{2}$/.test(to)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const resolvedPrimary = temporalGuard.resolved_primary_period && typeof temporalGuard.resolved_primary_period === "object"
|
||||
? temporalGuard.resolved_primary_period
|
||||
: null;
|
||||
if (!resolvedPrimary) {
|
||||
return false;
|
||||
}
|
||||
const from = String(resolvedPrimary.from ?? "").trim();
|
||||
const to = String(resolvedPrimary.to ?? "").trim();
|
||||
return /^2020-07-\d{2}$/.test(from) && /^2020-07-\d{2}$/.test(to);
|
||||
}
|
||||
function hasP0ClaimSignal(claimType, focusDomainHint) {
|
||||
const claim = String(claimType ?? "").trim();
|
||||
if (claim === "prove_settlement_closure_state" ||
|
||||
claim === "prove_advance_offset_state" ||
|
||||
claim === "prove_vat_chain_completeness" ||
|
||||
claim === "prove_month_close_state" ||
|
||||
claim === "prove_rbp_tail_state") {
|
||||
return true;
|
||||
}
|
||||
return (focusDomainHint === "settlements_60_62" ||
|
||||
focusDomainHint === "vat_document_register_book" ||
|
||||
focusDomainHint === "month_close_costs_20_44" ||
|
||||
focusDomainHint === "fixed_asset_amortization");
|
||||
}
|
||||
function resolveBusinessScopeFromLiveContext(input) {
|
||||
const current = input.current;
|
||||
const routeSummary = current?.route_summary_resolved;
|
||||
const julyResolved = isJuly2020TemporalResolved(input.temporalGuard);
|
||||
const p0Signal = hasP0ClaimSignal(input.claimType, input.focusDomainHint);
|
||||
if (!julyResolved || !p0Signal) {
|
||||
return current;
|
||||
}
|
||||
const reasons = Array.isArray(current.scope_resolution_reason) ? [...current.scope_resolution_reason] : [];
|
||||
if (!reasons.includes("temporal_claim_bound_company_scope_recovery")) {
|
||||
reasons.push("temporal_claim_bound_company_scope_recovery");
|
||||
}
|
||||
const currentScopes = Array.isArray(current.business_scope_resolved) ? current.business_scope_resolved : [];
|
||||
let changed = false;
|
||||
const normalizedScopes = currentScopes
|
||||
.map((item) => String(item ?? "").trim())
|
||||
.filter(Boolean)
|
||||
.map((item) => {
|
||||
if (item === "generic_accounting" || item === "unclear") {
|
||||
changed = true;
|
||||
return "company_specific_accounting";
|
||||
}
|
||||
return item;
|
||||
});
|
||||
if (!normalizedScopes.includes("company_specific_accounting")) {
|
||||
normalizedScopes.push("company_specific_accounting");
|
||||
changed = true;
|
||||
}
|
||||
let routeSummaryResolved = routeSummary;
|
||||
if (routeSummary && routeSummary.mode === "deterministic_v2" && Array.isArray(routeSummary.decisions)) {
|
||||
const decisions = routeSummary.decisions.map((decision) => {
|
||||
const scopeValue = String(decision.business_scope ?? "").trim();
|
||||
if (scopeValue !== "generic_accounting" && scopeValue !== "unclear") {
|
||||
return decision;
|
||||
}
|
||||
changed = true;
|
||||
return {
|
||||
...decision,
|
||||
business_scope: "company_specific_accounting"
|
||||
};
|
||||
});
|
||||
routeSummaryResolved = changed
|
||||
? {
|
||||
...routeSummary,
|
||||
decisions
|
||||
}
|
||||
: routeSummary;
|
||||
}
|
||||
return {
|
||||
...current,
|
||||
business_scope_resolved: Array.from(new Set(normalizedScopes)),
|
||||
company_grounding_applied: current.company_grounding_applied || changed,
|
||||
scope_resolution_reason: reasons,
|
||||
route_summary_resolved: routeSummaryResolved
|
||||
};
|
||||
}
|
||||
function escapeRegex(value) {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
@@ -1296,19 +1394,20 @@ export class AssistantService {
|
||||
};
|
||||
const normalized = await this.normalizerService.normalize(normalizePayload);
|
||||
const companyAnchors = (0, companyAnchorResolver_1.resolveCompanyAnchors)(userMessage);
|
||||
const businessScopeResolution = resolveBusinessScopeAlignment({
|
||||
const initialBusinessScopeResolution = resolveBusinessScopeAlignment({
|
||||
userMessage,
|
||||
companyAnchors,
|
||||
normalized: normalized.normalized,
|
||||
routeSummary: normalized.route_hint_summary
|
||||
});
|
||||
const resolvedRouteSummary = businessScopeResolution.route_summary_resolved;
|
||||
const inferredDomainByMessage = inferP0DomainFromMessage(userMessage);
|
||||
const focusDomainForGuards = inferredDomainByMessage === "settlements_60_62" ||
|
||||
inferredDomainByMessage === "vat_document_register_book" ||
|
||||
inferredDomainByMessage === "month_close_costs_20_44"
|
||||
? inferredDomainByMessage
|
||||
: null;
|
||||
const focusDomainForGuards = inferredDomainByMessage === "fixed_asset_amortization"
|
||||
? "month_close_costs_20_44"
|
||||
: inferredDomainByMessage === "settlements_60_62" ||
|
||||
inferredDomainByMessage === "vat_document_register_book" ||
|
||||
inferredDomainByMessage === "month_close_costs_20_44"
|
||||
? inferredDomainByMessage
|
||||
: null;
|
||||
const temporalGuard = (0, assistantRuntimeGuards_1.resolveTemporalGuard)({
|
||||
userMessage,
|
||||
normalized: normalized.normalized,
|
||||
@@ -1323,8 +1422,15 @@ export class AssistantService {
|
||||
userMessage,
|
||||
companyAnchors,
|
||||
focusDomainHint: focusDomainForGuards,
|
||||
primaryPeriod: temporalGuard.primary_period_window
|
||||
primaryPeriod: temporalGuard.effective_primary_period ?? temporalGuard.primary_period_window
|
||||
});
|
||||
const businessScopeResolution = resolveBusinessScopeFromLiveContext({
|
||||
current: initialBusinessScopeResolution,
|
||||
temporalGuard,
|
||||
claimType: claimAnchorAudit.claim_type,
|
||||
focusDomainHint: focusDomainForGuards
|
||||
});
|
||||
const resolvedRouteSummary = businessScopeResolution.route_summary_resolved;
|
||||
const requirementExtraction = extractRequirements(resolvedRouteSummary, normalized.normalized, userMessage);
|
||||
let executionPlan = toExecutionPlan(resolvedRouteSummary, normalized.normalized, userMessage, requirementExtraction.byFragment);
|
||||
executionPlan = (0, assistantRuntimeGuards_1.applyTemporalHintToExecutionPlan)(executionPlan, temporalGuard);
|
||||
@@ -1500,10 +1606,13 @@ export class AssistantService {
|
||||
business_scope_resolved: businessScopeResolution.business_scope_resolved,
|
||||
company_grounding_applied: businessScopeResolution.company_grounding_applied,
|
||||
scope_resolution_reason: businessScopeResolution.scope_resolution_reason,
|
||||
company_scope_resolution_reason: businessScopeResolution.scope_resolution_reason,
|
||||
raw_time_anchor: temporalGuard.raw_time_anchor,
|
||||
raw_time_scope: temporalGuard.raw_time_scope,
|
||||
resolved_time_anchor: temporalGuard.resolved_time_anchor,
|
||||
resolved_primary_period: temporalGuard.resolved_primary_period,
|
||||
effective_primary_period: temporalGuard.effective_primary_period,
|
||||
temporal_guard_input: temporalGuard.temporal_guard_input,
|
||||
temporal_alignment_status: temporalGuard.temporal_alignment_status,
|
||||
temporal_resolution_source: temporalGuard.temporal_resolution_source,
|
||||
temporal_guard_basis: temporalGuard.temporal_guard_basis,
|
||||
@@ -1589,10 +1698,13 @@ export class AssistantService {
|
||||
business_scope_resolved: businessScopeResolution.business_scope_resolved,
|
||||
company_grounding_applied: businessScopeResolution.company_grounding_applied,
|
||||
scope_resolution_reason: businessScopeResolution.scope_resolution_reason,
|
||||
company_scope_resolution_reason: businessScopeResolution.scope_resolution_reason,
|
||||
raw_time_anchor: temporalGuard.raw_time_anchor,
|
||||
raw_time_scope: temporalGuard.raw_time_scope,
|
||||
resolved_time_anchor: temporalGuard.resolved_time_anchor,
|
||||
resolved_primary_period: temporalGuard.resolved_primary_period,
|
||||
effective_primary_period: temporalGuard.effective_primary_period,
|
||||
temporal_guard_input: temporalGuard.temporal_guard_input,
|
||||
temporal_alignment_status: temporalGuard.temporal_alignment_status,
|
||||
temporal_resolution_source: temporalGuard.temporal_resolution_source,
|
||||
temporal_guard_basis: temporalGuard.temporal_guard_basis,
|
||||
|
||||
@@ -82,6 +82,12 @@ export interface TemporalGuardDebug {
|
||||
to: string;
|
||||
granularity: "day" | "month";
|
||||
} | null;
|
||||
effective_primary_period: {
|
||||
from: string;
|
||||
to: string;
|
||||
granularity: "day" | "month";
|
||||
} | null;
|
||||
temporal_guard_input: string | null;
|
||||
temporal_alignment_status: "aligned" | "corrected" | "conflicting";
|
||||
temporal_resolution_source: string;
|
||||
temporal_guard_basis: "resolved_primary_period" | "raw_time_scope_unlocked" | "none";
|
||||
@@ -267,6 +273,7 @@ export interface AssistantDebugPayload {
|
||||
business_scope_resolved?: string[];
|
||||
company_grounding_applied?: boolean;
|
||||
scope_resolution_reason?: string[];
|
||||
company_scope_resolution_reason?: string[];
|
||||
raw_time_anchor?: string | null;
|
||||
raw_time_scope?: string | null;
|
||||
resolved_time_anchor?: string | null;
|
||||
@@ -275,6 +282,12 @@ export interface AssistantDebugPayload {
|
||||
to: string;
|
||||
granularity: "day" | "month";
|
||||
} | null;
|
||||
effective_primary_period?: {
|
||||
from: string;
|
||||
to: string;
|
||||
granularity: "day" | "month";
|
||||
} | null;
|
||||
temporal_guard_input?: string | null;
|
||||
temporal_alignment_status?: TemporalGuardDebug["temporal_alignment_status"];
|
||||
temporal_resolution_source?: string;
|
||||
temporal_guard_basis?: TemporalGuardDebug["temporal_guard_basis"];
|
||||
|
||||
Reference in New Issue
Block a user