Закрепить дату складского supplier-overlap follow-up

This commit is contained in:
dctouch 2026-06-03 12:26:08 +03:00
parent f0b84822d3
commit fdd04abbde
9 changed files with 500 additions and 3 deletions

View File

@ -0,0 +1,80 @@
{
"schema_version": "domain_truth_harness_spec_v1",
"scenario_id": "address_truth_harness_inventory_supplier_overlap_temporal_carryover",
"domain": "inventory_supplier_overlap_temporal_carryover",
"title": "Supplier-overlap follow-up keeps the inventory root date",
"description": "Targeted replay for temporal carryover: after an inventory root slice for September 2021, colloquial supplier-overlap follow-ups with 'сейчас' / 'текущий товарный остаток' must stay on the confirmed root slice date instead of drifting to the wall-clock date.",
"bindings": {},
"steps": [
{
"step_id": "step_01_current_stock_anchor",
"title": "Historical inventory root anchor",
"question": "какие остатки на складе на сентябрь 2021",
"allowed_reply_types": [
"factual"
],
"expected_intents": [
"inventory_on_hand_as_of_date"
],
"required_filters": {
"as_of_date": "2021-09-30",
"period_from": "2021-09-01",
"period_to": "2021-09-30"
},
"required_answer_patterns_all": [
"(?i)30\\.09\\.2021",
"(?i)склад|остат"
],
"forbidden_answer_patterns": [
"(?i)03\\.06\\.2026",
"(?i)route_id|capability_id|runtime_|snapshot_items|answer_object|debug"
]
},
{
"step_id": "step_02_supplier_overlap_now",
"title": "Supplier overlap inherits root date despite сейчас",
"question": "У какого поставщика были куплены товары, которые сейчас лежат на складе Основной склад",
"allowed_reply_types": [
"factual"
],
"expected_intents": [
"inventory_supplier_stock_overlap_as_of_date"
],
"required_filters": {
"as_of_date": "2021-09-30"
},
"required_answer_patterns_all": [
"(?i)30\\.09\\.2021",
"(?i)поставщик|поставщиков|закупочн",
"(?i)Следующий шаг|проверьте|партионн"
],
"forbidden_answer_patterns": [
"(?i)03\\.06\\.2026",
"(?i)route_id|capability_id|runtime_|snapshot_items|answer_object|debug"
]
},
{
"step_id": "step_03_supplier_residue_now",
"title": "Current residue wording keeps root date",
"question": "По какому поставщику проходит текущий товарный остаток на складе Основной склад",
"allowed_reply_types": [
"factual"
],
"expected_intents": [
"inventory_supplier_stock_overlap_as_of_date"
],
"required_filters": {
"as_of_date": "2021-09-30"
},
"required_answer_patterns_all": [
"(?i)30\\.09\\.2021",
"(?i)поставщик|поставщиков|закупочн",
"(?i)Следующий шаг|проверьте|партионн"
],
"forbidden_answer_patterns": [
"(?i)03\\.06\\.2026",
"(?i)route_id|capability_id|runtime_|snapshot_items|answer_object|debug"
]
}
]
}

View File

@ -534,6 +534,7 @@ function shouldPreferRawFollowupMessage(userMessage, addressInputMessage, carryo
const previousIntent = toNonEmptyString(followupContext?.previous_intent);
const rootIntent = toNonEmptyString(followupContext?.root_intent);
const previousAnchorType = toNonEmptyString(followupContext?.previous_anchor_type);
const previousFilters = toRecordObject(followupContext?.previous_filters);
const hasReferentialDocumentExclusionFollowupCue = /(?:\u043a\u0440\u043e\u043c\u0435|\u043f\u043e\u043c\u0438\u043c\u043e)\s+(?:\u044d\u0442\u043e\u0433\u043e|\u044d\u0442\u043e\u0439|\u044d\u0442\u043e\u0442|\u044d\u0442\u0443|\u044d\u0442\u0438\u0445)(?:\s+(?:\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430|\u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0430|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430))?/iu.test(rawMessage);
const hasInventoryItemCarryover = previousAnchorType === "item" && isInventorySelectedObjectOrRootIntent(previousIntent);
const hasInventoryFrameCarryover = isInventorySelectedObjectOrRootIntent(previousIntent) ||
@ -543,10 +544,11 @@ function shouldPreferRawFollowupMessage(userMessage, addressInputMessage, carryo
const hasInventoryMarginRankingAccountCorrection = hasInventoryMarginRankingCarryover &&
[rawMessage, canonicalMessage].some((message) => hasInventoryMarginRankingAccountCorrectionCue(message));
const hasDocumentCarryover = previousIntent === "list_documents_by_counterparty" || previousIntent === "list_documents_by_contract";
const hasCounterpartyCarryover = previousAnchorType === "counterparty" || Boolean(toNonEmptyString(previousFilters?.counterparty));
if (mode === "unsupported" && intent === "unknown") {
return true;
}
if (hasDocumentCarryover && hasReferentialDocumentExclusionFollowupCue) {
if ((hasDocumentCarryover || hasCounterpartyCarryover) && hasReferentialDocumentExclusionFollowupCue) {
return true;
}
if (hasSameDateFollowupSignal(rawMessage) && hasExplicitCurrentDateSignal(canonicalMessage)) {

View File

@ -27,6 +27,25 @@ function createAssistantTransitionPolicy(deps) {
return wantsFoundRows || account41Not01;
});
}
function hasInventorySupplierOverlapRootFollowupSignal(userMessage, alternateMessage = null, sourceIntentHint = null, hasInventoryRootFrame = false) {
if (!hasInventoryRootFrame ||
(sourceIntentHint !== "inventory_on_hand_as_of_date" &&
sourceIntentHint !== "inventory_supplier_stock_overlap_as_of_date")) {
return false;
}
return [userMessage, alternateMessage]
.filter((value) => deps.toNonEmptyString(value))
.map((value) => normalizeFollowupText(value))
.some((normalized) => {
if (!normalized) {
return false;
}
const hasSupplierCue = /(?:\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|supplier|vendor|\u0443\s+\u043a\u0430\u043a\u043e\u0433\u043e|\u0443\s+\u043a\u043e\u0433\u043e|\u043f\u043e\s+\u043a\u0430\u043a\u043e\u043c\u0443)/iu.test(normalized);
const hasStockCue = /(?:\u043e\u0441\u0442\u0430\u0442|\u0441\u043a\u043b\u0430\u0434|\u0442\u043e\u0432\u0430\u0440|\u043f\u043e\u0437\u0438\u0446|\u043b\u0435\u0436|\u0432\u0438\u0441|\u0442\u0435\u043a\u0443\u0449)/iu.test(normalized);
const hasPurchaseCue = /(?:\u043a\u0443\u043f\u0438\u043b|\u043a\u0443\u043f\u043b\u0435\u043d|\u043f\u043e\u043a\u0443\u043f|\u0437\u0430\u043a\u0443\u043f|\u043f\u043e\u0441\u0442\u0443\u043f\u043b|purchase|bought)/iu.test(normalized);
return hasSupplierCue && (hasStockCue || hasPurchaseCue);
});
}
function hasSamePeriodReferenceCue(...values) {
return values
.map((value) => normalizeFollowupText(value))
@ -866,6 +885,7 @@ function createAssistantTransitionPolicy(deps) {
const hasInventoryRootRestatementAlternate = deps.toNonEmptyString(alternateMessage)
? hasInventoryRootRestatementLikeSignal(String(alternateMessage ?? ""), sourceIntentHint, Boolean(recentInventoryRootFrame))
: false;
const hasInventorySupplierOverlapRootFollowup = hasInventorySupplierOverlapRootFollowupSignal(userMessage, alternateMessage, sourceIntentHint, Boolean(recentInventoryRootFrame));
const hasExplicitInventorySameDatePivotPrimary = hasExplicitInventorySameDatePivotSignal(userMessage);
const hasExplicitInventorySameDatePivotAlternate = deps.toNonEmptyString(alternateMessage)
? hasExplicitInventorySameDatePivotSignal(String(alternateMessage ?? ""))
@ -882,6 +902,7 @@ function createAssistantTransitionPolicy(deps) {
hasInventoryRootTemporalFollowupAlternate ||
hasInventoryRootRestatementPrimary ||
hasInventoryRootRestatementAlternate ||
hasInventorySupplierOverlapRootFollowup ||
inventoryPurchaseDateVatBridge ||
explicitSummaryBundleReuseSignal ||
Boolean(debtRoleSwapIntent) ||
@ -907,6 +928,7 @@ function createAssistantTransitionPolicy(deps) {
hasInventoryRootTemporalFollowupAlternate ||
hasInventoryRootRestatementPrimary ||
hasInventoryRootRestatementAlternate ||
hasInventorySupplierOverlapRootFollowup ||
inventoryPurchaseDateVatBridge ||
explicitSummaryBundleReuseSignal ||
Boolean(debtRoleSwapIntent) ||
@ -938,6 +960,7 @@ function createAssistantTransitionPolicy(deps) {
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!hasInventorySupplierOverlapRootFollowup &&
!shortValueFlowRetargetPrimary &&
!shortValueFlowRetargetAlternate &&
!selectedCounterpartyDocumentFollowupSignal &&
@ -955,6 +978,7 @@ function createAssistantTransitionPolicy(deps) {
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!hasInventorySupplierOverlapRootFollowup &&
!shortValueFlowRetargetPrimary &&
!shortValueFlowRetargetAlternate &&
!selectedCounterpartyDocumentFollowupSignal &&
@ -1037,6 +1061,7 @@ function createAssistantTransitionPolicy(deps) {
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!hasInventorySupplierOverlapRootFollowup &&
!inventoryShortFollowupPrimary &&
!inventoryShortFollowupAlternate &&
!businessOverviewBoundaryFollowupPrimary &&
@ -1104,6 +1129,7 @@ function createAssistantTransitionPolicy(deps) {
inventoryMarginRankingFollowup ||
explicitSummaryBundleReuseSignal ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventorySupplierOverlapRootFollowup ||
mcpDiscoveryOrganizationClarificationContinuation;
hasAlternateFollowupSignal = deps.toNonEmptyString(alternateMessage)
? deps.hasAddressFollowupContextSignal(alternateMessage) ||
@ -1116,6 +1142,7 @@ function createAssistantTransitionPolicy(deps) {
inventoryMarginRankingFollowup ||
explicitSummaryBundleReuseSignal ||
hasInventoryRootTemporalFollowupAlternate ||
hasInventorySupplierOverlapRootFollowup ||
mcpDiscoveryOrganizationClarificationContinuation
: false;
hasStrongFollowupReference =
@ -1129,6 +1156,7 @@ function createAssistantTransitionPolicy(deps) {
inventoryShortFollowupAlternate ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventoryRootTemporalFollowupAlternate ||
hasInventorySupplierOverlapRootFollowup ||
inventoryPurchaseDateVatBridge ||
explicitSummaryBundleReuseSignal ||
Boolean(debtRoleSwapIntent) ||
@ -1261,7 +1289,8 @@ function createAssistantTransitionPolicy(deps) {
}
const predecomposeIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
const carryoverTargetIntentPreview = explicitIntent ?? predecomposeIntent ?? previousIntent;
if (shouldClearStaleDateScopeForCounterpartyDocsRoot(carryoverTargetIntentPreview, sourceIntentHint, userMessage, alternateMessage)) {
if (!selectedCounterpartyDocumentFollowupSignal &&
shouldClearStaleDateScopeForCounterpartyDocsRoot(carryoverTargetIntentPreview, sourceIntentHint, userMessage, alternateMessage)) {
delete previousFilters.as_of_date;
delete previousFilters.period_from;
delete previousFilters.period_to;
@ -1280,6 +1309,7 @@ function createAssistantTransitionPolicy(deps) {
inventoryShortFollowupAlternate ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventoryRootTemporalFollowupAlternate ||
hasInventorySupplierOverlapRootFollowup ||
hasInventoryRootRestatementPrimary ||
hasInventoryRootRestatementAlternate ||
hasSelectedObjectInventorySignalPrimary ||

View File

@ -765,6 +765,7 @@ function shouldPreferRawFollowupMessage(
const previousIntent = toNonEmptyString(followupContext?.previous_intent);
const rootIntent = toNonEmptyString(followupContext?.root_intent);
const previousAnchorType = toNonEmptyString(followupContext?.previous_anchor_type);
const previousFilters = toRecordObject(followupContext?.previous_filters);
const hasReferentialDocumentExclusionFollowupCue = /(?:\u043a\u0440\u043e\u043c\u0435|\u043f\u043e\u043c\u0438\u043c\u043e)\s+(?:\u044d\u0442\u043e\u0433\u043e|\u044d\u0442\u043e\u0439|\u044d\u0442\u043e\u0442|\u044d\u0442\u0443|\u044d\u0442\u0438\u0445)(?:\s+(?:\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430|\u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0430|\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430))?/iu.test(
rawMessage
);
@ -781,12 +782,14 @@ function shouldPreferRawFollowupMessage(
[rawMessage, canonicalMessage].some((message) => hasInventoryMarginRankingAccountCorrectionCue(message));
const hasDocumentCarryover =
previousIntent === "list_documents_by_counterparty" || previousIntent === "list_documents_by_contract";
const hasCounterpartyCarryover =
previousAnchorType === "counterparty" || Boolean(toNonEmptyString(previousFilters?.counterparty));
if (mode === "unsupported" && intent === "unknown") {
return true;
}
if (hasDocumentCarryover && hasReferentialDocumentExclusionFollowupCue) {
if ((hasDocumentCarryover || hasCounterpartyCarryover) && hasReferentialDocumentExclusionFollowupCue) {
return true;
}

View File

@ -72,6 +72,42 @@ export function createAssistantTransitionPolicy(deps) {
});
}
function hasInventorySupplierOverlapRootFollowupSignal(
userMessage,
alternateMessage = null,
sourceIntentHint = null,
hasInventoryRootFrame = false
) {
if (
!hasInventoryRootFrame ||
(sourceIntentHint !== "inventory_on_hand_as_of_date" &&
sourceIntentHint !== "inventory_supplier_stock_overlap_as_of_date")
) {
return false;
}
return [userMessage, alternateMessage]
.filter((value) => deps.toNonEmptyString(value))
.map((value) => normalizeFollowupText(value))
.some((normalized) => {
if (!normalized) {
return false;
}
const hasSupplierCue =
/(?:\u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a|supplier|vendor|\u0443\s+\u043a\u0430\u043a\u043e\u0433\u043e|\u0443\s+\u043a\u043e\u0433\u043e|\u043f\u043e\s+\u043a\u0430\u043a\u043e\u043c\u0443)/iu.test(
normalized
);
const hasStockCue =
/(?:\u043e\u0441\u0442\u0430\u0442|\u0441\u043a\u043b\u0430\u0434|\u0442\u043e\u0432\u0430\u0440|\u043f\u043e\u0437\u0438\u0446|\u043b\u0435\u0436|\u0432\u0438\u0441|\u0442\u0435\u043a\u0443\u0449)/iu.test(
normalized
);
const hasPurchaseCue =
/(?:\u043a\u0443\u043f\u0438\u043b|\u043a\u0443\u043f\u043b\u0435\u043d|\u043f\u043e\u043a\u0443\u043f|\u0437\u0430\u043a\u0443\u043f|\u043f\u043e\u0441\u0442\u0443\u043f\u043b|purchase|bought)/iu.test(
normalized
);
return hasSupplierCue && (hasStockCue || hasPurchaseCue);
});
}
function hasSamePeriodReferenceCue(...values) {
return values
.map((value) => normalizeFollowupText(value))
@ -1180,6 +1216,12 @@ export function createAssistantTransitionPolicy(deps) {
Boolean(recentInventoryRootFrame)
)
: false;
const hasInventorySupplierOverlapRootFollowup = hasInventorySupplierOverlapRootFollowupSignal(
userMessage,
alternateMessage,
sourceIntentHint,
Boolean(recentInventoryRootFrame)
);
const hasExplicitInventorySameDatePivotPrimary = hasExplicitInventorySameDatePivotSignal(userMessage);
const hasExplicitInventorySameDatePivotAlternate = deps.toNonEmptyString(alternateMessage)
? hasExplicitInventorySameDatePivotSignal(String(alternateMessage ?? ""))
@ -1197,6 +1239,7 @@ export function createAssistantTransitionPolicy(deps) {
hasInventoryRootTemporalFollowupAlternate ||
hasInventoryRootRestatementPrimary ||
hasInventoryRootRestatementAlternate ||
hasInventorySupplierOverlapRootFollowup ||
inventoryPurchaseDateVatBridge ||
explicitSummaryBundleReuseSignal ||
Boolean(debtRoleSwapIntent) ||
@ -1223,6 +1266,7 @@ export function createAssistantTransitionPolicy(deps) {
hasInventoryRootTemporalFollowupAlternate ||
hasInventoryRootRestatementPrimary ||
hasInventoryRootRestatementAlternate ||
hasInventorySupplierOverlapRootFollowup ||
inventoryPurchaseDateVatBridge ||
explicitSummaryBundleReuseSignal ||
Boolean(debtRoleSwapIntent) ||
@ -1259,6 +1303,7 @@ export function createAssistantTransitionPolicy(deps) {
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!hasInventorySupplierOverlapRootFollowup &&
!shortValueFlowRetargetPrimary &&
!shortValueFlowRetargetAlternate &&
!selectedCounterpartyDocumentFollowupSignal &&
@ -1278,6 +1323,7 @@ export function createAssistantTransitionPolicy(deps) {
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!hasInventorySupplierOverlapRootFollowup &&
!shortValueFlowRetargetPrimary &&
!shortValueFlowRetargetAlternate &&
!selectedCounterpartyDocumentFollowupSignal &&
@ -1412,6 +1458,7 @@ export function createAssistantTransitionPolicy(deps) {
!hasInventoryRootTemporalFollowupAlternate &&
!hasInventoryRootRestatementPrimary &&
!hasInventoryRootRestatementAlternate &&
!hasInventorySupplierOverlapRootFollowup &&
!inventoryShortFollowupPrimary &&
!inventoryShortFollowupAlternate &&
!businessOverviewBoundaryFollowupPrimary &&
@ -1483,6 +1530,7 @@ export function createAssistantTransitionPolicy(deps) {
inventoryMarginRankingFollowup ||
explicitSummaryBundleReuseSignal ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventorySupplierOverlapRootFollowup ||
mcpDiscoveryOrganizationClarificationContinuation;
hasAlternateFollowupSignal = deps.toNonEmptyString(alternateMessage)
? deps.hasAddressFollowupContextSignal(alternateMessage) ||
@ -1495,6 +1543,7 @@ export function createAssistantTransitionPolicy(deps) {
inventoryMarginRankingFollowup ||
explicitSummaryBundleReuseSignal ||
hasInventoryRootTemporalFollowupAlternate ||
hasInventorySupplierOverlapRootFollowup ||
mcpDiscoveryOrganizationClarificationContinuation
: false;
hasStrongFollowupReference =
@ -1508,6 +1557,7 @@ export function createAssistantTransitionPolicy(deps) {
inventoryShortFollowupAlternate ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventoryRootTemporalFollowupAlternate ||
hasInventorySupplierOverlapRootFollowup ||
inventoryPurchaseDateVatBridge ||
explicitSummaryBundleReuseSignal ||
Boolean(debtRoleSwapIntent) ||
@ -1728,6 +1778,7 @@ export function createAssistantTransitionPolicy(deps) {
const predecomposeIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
const carryoverTargetIntentPreview = explicitIntent ?? predecomposeIntent ?? previousIntent;
if (
!selectedCounterpartyDocumentFollowupSignal &&
shouldClearStaleDateScopeForCounterpartyDocsRoot(
carryoverTargetIntentPreview,
sourceIntentHint,
@ -1754,6 +1805,7 @@ export function createAssistantTransitionPolicy(deps) {
inventoryShortFollowupAlternate ||
hasInventoryRootTemporalFollowupPrimary ||
hasInventoryRootTemporalFollowupAlternate ||
hasInventorySupplierOverlapRootFollowup ||
hasInventoryRootRestatementPrimary ||
hasInventoryRootRestatementAlternate ||
hasSelectedObjectInventorySignalPrimary ||

View File

@ -153,6 +153,133 @@ describe("assistantTransitionPolicy", () => {
expect(carryover?.followupContext?.root_intent).toBe("inventory_on_hand_as_of_date");
});
it("carries inventory root date into supplier-overlap current-stock follow-up", () => {
const organization = "\u041e\u041e\u041e \"\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441\"";
const warehouse = "\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043a\u043b\u0430\u0434";
const rootFilters = {
period_from: "2021-09-01",
period_to: "2021-09-30",
as_of_date: "2021-09-30",
organization,
warehouse
};
const policy = buildPolicy({
findLastAddressAssistantItem: () => ({
text: "\u041d\u0430 30.09.2021 \u043f\u043e \u0441\u043a\u043b\u0430\u0434\u0443 \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043a\u043b\u0430\u0434 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u044b \u043e\u0441\u0442\u0430\u0442\u043a\u0438.",
debug: {
detected_intent: "inventory_on_hand_as_of_date",
selected_recipe: "address_inventory_on_hand_as_of_date_v1",
extracted_filters: rootFilters,
anchor_type: "warehouse",
anchor_value_resolved: warehouse
}
}),
findRecentInventoryRootFrame: () => ({
intent: "inventory_on_hand_as_of_date",
filters: rootFilters,
anchorType: "warehouse",
anchorValue: warehouse,
currentFrameKind: "inventory_root"
}),
hasAddressFollowupContextSignal: () => false,
hasStandaloneAddressTopicSignal: () => true,
resolveAddressIntent: () => ({ intent: "inventory_supplier_stock_overlap_as_of_date" }),
resolveAddressIntentFamily: (intent: unknown) =>
String(intent ?? "").startsWith("inventory_") ? "inventory" : null
});
const carryover = policy.resolveAddressFollowupCarryoverContext(
"\u0423 \u043a\u0430\u043a\u043e\u0433\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0430 \u0431\u044b\u043b\u0438 \u043a\u0443\u043f\u043b\u0435\u043d\u044b \u0442\u043e\u0432\u0430\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u043b\u0435\u0436\u0430\u0442 \u043d\u0430 \u0441\u043a\u043b\u0430\u0434\u0435 \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043a\u043b\u0430\u0434",
[],
"\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043d\u0430 \u0441\u043a\u043b\u0430\u0434\u0435 \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043a\u043b\u0430\u0434 \u0432 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442",
{
predecomposeContract: {
intent: "inventory_supplier_stock_overlap_as_of_date"
}
},
{
session_context: {
date_scope: rootFilters,
organization_scope: organization,
active_focus_object: {
object_type: "organization",
label: organization
}
}
}
);
expect(carryover?.followupContext?.previous_intent).toBe("inventory_on_hand_as_of_date");
expect(carryover?.followupContext?.target_intent).toBe("inventory_supplier_stock_overlap_as_of_date");
expect(carryover?.followupContext?.previous_filters).toMatchObject(rootFilters);
expect(carryover?.followupContext?.root_intent).toBe("inventory_on_hand_as_of_date");
expect(carryover?.followupContext?.root_filters).toMatchObject(rootFilters);
expect(carryover?.followupContext?.current_frame_kind).toBe("inventory_root");
});
it("keeps supplier-overlap date on repeated current-residue supplier wording", () => {
const organization = "\u041e\u041e\u041e \"\u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441\"";
const warehouse = "\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043a\u043b\u0430\u0434";
const rootFilters = {
period_from: "2021-09-01",
period_to: "2021-09-30",
as_of_date: "2021-09-30",
organization,
warehouse
};
const policy = buildPolicy({
findLastAddressAssistantItem: () => ({
text: "\u041f\u043e \u0441\u043a\u043b\u0430\u0434\u0441\u043a\u043e\u043c\u0443 \u043e\u0441\u0442\u0430\u0442\u043a\u0443 \u043d\u0430 30.09.2021 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0438.",
debug: {
detected_intent: "inventory_supplier_stock_overlap_as_of_date",
selected_recipe: "address_inventory_supplier_stock_overlap_as_of_date_v1",
extracted_filters: rootFilters,
anchor_type: "warehouse",
anchor_value_resolved: warehouse
}
}),
findRecentInventoryRootFrame: () => ({
intent: "inventory_on_hand_as_of_date",
filters: rootFilters,
anchorType: "warehouse",
anchorValue: warehouse,
currentFrameKind: "inventory_root"
}),
hasAddressFollowupContextSignal: () => false,
hasStandaloneAddressTopicSignal: () => true,
resolveAddressIntent: () => ({ intent: "inventory_supplier_stock_overlap_as_of_date" }),
resolveAddressIntentFamily: (intent: unknown) =>
String(intent ?? "").startsWith("inventory_") ? "inventory" : null
});
const carryover = policy.resolveAddressFollowupCarryoverContext(
"\u041f\u043e \u043a\u0430\u043a\u043e\u043c\u0443 \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0443 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0442\u043e\u0432\u0430\u0440\u043d\u044b\u0439 \u043e\u0441\u0442\u0430\u0442\u043e\u043a \u043d\u0430 \u0441\u043a\u043b\u0430\u0434\u0435 \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043a\u043b\u0430\u0434",
[],
"\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0430, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043b\u0438 \u0442\u043e\u0432\u0430\u0440\u044b, \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0449\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043e\u0441\u0442\u0430\u0442\u043e\u043a \u043d\u0430 \u0441\u043a\u043b\u0430\u0434\u0435 \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u043a\u043b\u0430\u0434",
{
predecomposeContract: {
intent: "inventory_supplier_stock_overlap_as_of_date"
}
},
{
session_context: {
date_scope: rootFilters,
organization_scope: organization,
active_focus_object: {
object_type: "warehouse",
label: warehouse
}
}
}
);
expect(carryover?.followupContext?.previous_intent).toBe("inventory_supplier_stock_overlap_as_of_date");
expect(carryover?.followupContext?.target_intent).toBe("inventory_supplier_stock_overlap_as_of_date");
expect(carryover?.followupContext?.previous_filters).toMatchObject(rootFilters);
expect(carryover?.followupContext?.root_intent).toBe("inventory_on_hand_as_of_date");
expect(carryover?.followupContext?.current_frame_kind).toBe("inventory_root");
});
it("builds continuation contract from extracted root carryover", () => {
const policy = buildPolicy();

View File

@ -1,4 +1,40 @@
[
{
"generation_id": "gen-ag06030918-32dc7c",
"created_at": "2026-06-03T09:18:35+00:00",
"mode": "saved_user_sessions",
"title": "AGENT | Supplier-overlap follow-up keeps the inventory root date",
"count": 3,
"domain": "inventory_supplier_overlap_temporal_carryover",
"questions": [
"какие остатки на складе на сентябрь 2021",
"У какого поставщика были куплены товары, которые сейчас лежат на складе Основной склад",
"По какому поставщику проходит текущий товарный остаток на складе Основной склад"
],
"generated_by": "codex_agent",
"saved_case_set_file": "assistant_autogen_saved_user_sessions_20260603091835_gen-ag06030918-32dc7c.json",
"context": {
"llm_provider": null,
"model": null,
"assistant_prompt_version": null,
"decomposition_prompt_version": null,
"prompt_fingerprint": null,
"autogen_personality_id": null,
"autogen_personality_prompt": null,
"source_session_id": null,
"saved_session_file": "assistant_saved_session_20260603091835_gen-ag06030918-32dc7c.json",
"saved_case_set_kind": "agent_semantic_scenario",
"agent_run": true,
"agent_focus": "Targeted replay for temporal carryover: after an inventory root slice for September 2021, colloquial supplier-overlap follow-ups with 'сейчас' / 'текущий товарный остаток' must stay on the confirmed root slice date instead of drifting to the wall-clock date.",
"architecture_phase": "turnaround_11",
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_inventory_supplier_overlap_temporal_carryover.json",
"scenario_id": "address_truth_harness_inventory_supplier_overlap_temporal_carryover",
"semantic_tags": [],
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\inventory_supplier_overlap_temporal_carryover_p2",
"saved_after_validated_replay": true
}
},
{
"generation_id": "gen-ag06030841-d61275",
"created_at": "2026-06-03T08:41:17+00:00",

View File

@ -0,0 +1,133 @@
{
"saved_at": "2026-06-03T09:18:35+00:00",
"generation_id": "gen-ag06030918-32dc7c",
"mode": "saved_user_sessions",
"title": "AGENT | Supplier-overlap follow-up keeps the inventory root date",
"agent_run": true,
"questions": [
"какие остатки на складе на сентябрь 2021",
"У какого поставщика были куплены товары, которые сейчас лежат на складе Основной склад",
"По какому поставщику проходит текущий товарный остаток на складе Основной склад"
],
"metadata": {
"assistant_prompt_version": null,
"decomposition_prompt_version": null,
"prompt_fingerprint": null,
"agent_focus": "Targeted replay for temporal carryover: after an inventory root slice for September 2021, colloquial supplier-overlap follow-ups with 'сейчас' / 'текущий товарный остаток' must stay on the confirmed root slice date instead of drifting to the wall-clock date.",
"architecture_phase": "turnaround_11",
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_inventory_supplier_overlap_temporal_carryover.json",
"scenario_id": "address_truth_harness_inventory_supplier_overlap_temporal_carryover",
"semantic_tags": [],
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\inventory_supplier_overlap_temporal_carryover_p2",
"saved_after_validated_replay": true,
"save_gate": {
"schema_version": "agent_semantic_save_gate_v1",
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\inventory_supplier_overlap_temporal_carryover_p2",
"final_status": "accepted",
"review_overall_status": "pass",
"business_overall_status": "pass",
"steps_total": 3,
"steps_passed": 3,
"steps_failed": 0,
"steps_with_business_failures": 0,
"steps_with_business_warnings": 0,
"acceptance_gate_passed": true,
"effective_runtime": {
"manifest_path": "artifacts\\domain_runs\\inventory_supplier_overlap_temporal_carryover_p2\\effective_runtime.json",
"runner": "domain_truth_harness.run-live",
"git_sha": "f0b84822d3e9283b5a8b823bd22ed571322a905f",
"backend_url": "http://127.0.0.1:8787",
"mcp_proxy_url": "http://127.0.0.1:6003",
"llm_provider": "local",
"llm_model": "unsloth/qwen3-30b-a3b-instruct-2507",
"temperature": 0.8,
"max_output_tokens": 900,
"prompt_version": "normalizer_v2_0_2",
"prompt_source": "file",
"prompt_hash": "f36e36a5e491cd24511b380e0c0059cb01aea5e2af738fb9f01671cd291735c1",
"prompt_registry_status": "pass"
},
"saved_after_validated_replay": true
}
},
"source_session_id": null,
"session": {
"session_id": null,
"mode": "agent_semantic_run",
"items": [
{
"message_id": "agent-user-001",
"role": "user",
"text": "какие остатки на складе на сентябрь 2021",
"created_at": "2026-06-03T09:18:35+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-002",
"role": "user",
"text": "У какого поставщика были куплены товары, которые сейчас лежат на складе Основной склад",
"created_at": "2026-06-03T09:18:35+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
},
{
"message_id": "agent-user-003",
"role": "user",
"text": "По какому поставщику проходит текущий товарный остаток на складе Основной склад",
"created_at": "2026-06-03T09:18:35+00:00",
"reply_type": null,
"trace_id": null,
"debug": null
}
],
"agent_run": true,
"metadata": {
"assistant_prompt_version": null,
"decomposition_prompt_version": null,
"prompt_fingerprint": null,
"agent_focus": "Targeted replay for temporal carryover: after an inventory root slice for September 2021, colloquial supplier-overlap follow-ups with 'сейчас' / 'текущий товарный остаток' must stay on the confirmed root slice date instead of drifting to the wall-clock date.",
"architecture_phase": "turnaround_11",
"source_spec_file": "X:\\1C\\NDC_1C\\docs\\orchestration\\address_truth_harness_inventory_supplier_overlap_temporal_carryover.json",
"scenario_id": "address_truth_harness_inventory_supplier_overlap_temporal_carryover",
"semantic_tags": [],
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\inventory_supplier_overlap_temporal_carryover_p2",
"saved_after_validated_replay": true,
"save_gate": {
"schema_version": "agent_semantic_save_gate_v1",
"validation_status": "accepted_live_replay",
"validated_run_dir": "artifacts\\domain_runs\\inventory_supplier_overlap_temporal_carryover_p2",
"final_status": "accepted",
"review_overall_status": "pass",
"business_overall_status": "pass",
"steps_total": 3,
"steps_passed": 3,
"steps_failed": 0,
"steps_with_business_failures": 0,
"steps_with_business_warnings": 0,
"acceptance_gate_passed": true,
"effective_runtime": {
"manifest_path": "artifacts\\domain_runs\\inventory_supplier_overlap_temporal_carryover_p2\\effective_runtime.json",
"runner": "domain_truth_harness.run-live",
"git_sha": "f0b84822d3e9283b5a8b823bd22ed571322a905f",
"backend_url": "http://127.0.0.1:8787",
"mcp_proxy_url": "http://127.0.0.1:6003",
"llm_provider": "local",
"llm_model": "unsloth/qwen3-30b-a3b-instruct-2507",
"temperature": 0.8,
"max_output_tokens": 900,
"prompt_version": "normalizer_v2_0_2",
"prompt_source": "file",
"prompt_hash": "f36e36a5e491cd24511b380e0c0059cb01aea5e2af738fb9f01671cd291735c1",
"prompt_registry_status": "pass"
},
"saved_after_validated_replay": true
}
}
}
}

View File

@ -0,0 +1,34 @@
{
"suite_id": "assistant_saved_session_gen-ag06030918-32dc7c",
"suite_version": "0.1.0",
"schema_version": "assistant_saved_session_suite_v0_1",
"generated_at": "2026-06-03T09:18:35+00:00",
"generation_id": "gen-ag06030918-32dc7c",
"mode": "saved_user_sessions",
"title": "AGENT | Supplier-overlap follow-up keeps the inventory root date",
"domain": "inventory_supplier_overlap_temporal_carryover",
"scenario_count": 1,
"case_ids": [
"SAVED-001"
],
"cases": [
{
"case_id": "SAVED-001",
"scenario_tag": "agent_saved_user_sessions",
"title": "AGENT | Supplier-overlap follow-up keeps the inventory root date",
"question_type": "followup",
"broadness_level": "medium",
"turns": [
{
"user_message": "какие остатки на складе на сентябрь 2021"
},
{
"user_message": "У какого поставщика были куплены товары, которые сейчас лежат на складе Основной склад"
},
{
"user_message": "По какому поставщику проходит текущий товарный остаток на складе Основной склад"
}
]
}
]
}