Этап 4 / Волна 19.2 исправление живого replay-контура для слоя адресного сбора доказательной базы

This commit is contained in:
2026-03-29 08:58:16 +03:00
parent d461cedf35
commit 095e74ad3b
9 changed files with 863 additions and 34 deletions
@@ -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");