ARCH: замкнуть metadata-scoped clarification recovery loops

This commit is contained in:
2026-04-23 13:42:14 +03:00
parent c96c9bab86
commit cddd6667fb
20 changed files with 993 additions and 43 deletions
@@ -14,6 +14,8 @@ export interface AssistantMcpDiscoveryDataNeedGraphContract {
schema_version: typeof ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION;
policy_owner: "assistantMcpDiscoveryDataNeedGraph";
subject_candidates: string[];
metadata_scope_hint?: string | null;
subject_resolution_optional?: boolean;
business_fact_family: string | null;
action_family: string | null;
aggregation_need: string | null;
@@ -205,6 +207,16 @@ function allowsOpenScopeWithoutSubject(input: {
);
}
function allowsMetadataScopedOpenLaneWithoutSubject(input: {
family: string | null;
subjectResolutionOptional: boolean;
}): boolean {
return Boolean(
input.subjectResolutionOptional &&
(input.family === "movement_evidence" || input.family === "document_evidence")
);
}
function rankingNeedFromRawUtterance(value: string): string | null {
const text = lower(value);
if (!text) {
@@ -249,6 +261,7 @@ function decompositionCandidatesFor(input: {
comparisonNeed: string | null;
rankingNeed: string | null;
openScopeWithoutSubject: boolean;
metadataScopedOpenLaneWithoutSubject: boolean;
}): string[] {
const result: string[] = [];
if (input.family === "schema_surface") {
@@ -295,13 +308,17 @@ function decompositionCandidatesFor(input: {
return result;
}
if (input.family === "movement_evidence") {
pushUnique(result, "resolve_entity_reference");
if (!input.metadataScopedOpenLaneWithoutSubject) {
pushUnique(result, "resolve_entity_reference");
}
pushUnique(result, "fetch_scoped_movements");
pushUnique(result, "probe_coverage");
return result;
}
if (input.family === "document_evidence") {
pushUnique(result, "resolve_entity_reference");
if (!input.metadataScopedOpenLaneWithoutSubject) {
pushUnique(result, "resolve_entity_reference");
}
pushUnique(result, "fetch_scoped_documents");
pushUnique(result, "probe_coverage");
return result;
@@ -345,6 +362,8 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
const seededRankingNeed = toNonEmptyString(turnMeaning?.seeded_ranking_need);
const explicitDateScope = toNonEmptyString(turnMeaning?.explicit_date_scope);
const explicitOrganizationScope = toNonEmptyString(turnMeaning?.explicit_organization_scope);
const metadataScopeHint = toNonEmptyString(turnMeaning?.metadata_scope_hint);
const subjectResolutionOptional = turnMeaning?.subject_resolution_optional === true;
const subjectCandidates = (turnMeaning?.explicit_entity_candidates ?? [])
.map((item) => toNonEmptyString(item))
.filter((item): item is string => Boolean(item));
@@ -369,6 +388,12 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
rankingNeed,
oneSidedOpenScopeTotalHint
});
const metadataScopedOpenLaneWithoutSubject =
subjectCandidates.length === 0 &&
allowsMetadataScopedOpenLaneWithoutSubject({
family: businessFactFamily,
subjectResolutionOptional
});
const clarificationGaps: string[] = [];
if (unsupported === "metadata_lane_choice_clarification" || action === "resolve_next_lane") {
pushUnique(clarificationGaps, "lane_family_choice");
@@ -380,7 +405,18 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
!explicitOrganizationScope
) {
pushUnique(clarificationGaps, "organization");
} else if (subjectCandidates.length === 0 && businessFactFamily !== "schema_surface" && !openScopeWithoutSubject) {
} else if (
subjectCandidates.length === 0 &&
metadataScopedOpenLaneWithoutSubject &&
!explicitOrganizationScope
) {
pushUnique(clarificationGaps, "organization");
} else if (
subjectCandidates.length === 0 &&
businessFactFamily !== "schema_surface" &&
!openScopeWithoutSubject &&
!metadataScopedOpenLaneWithoutSubject
) {
pushUnique(clarificationGaps, "subject");
}
const timeScopeNeed = timeScopeNeedFor({
@@ -393,12 +429,13 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
}
const decompositionCandidates = decompositionCandidatesFor({
family: businessFactFamily,
action,
aggregationNeed,
comparisonNeed,
rankingNeed,
openScopeWithoutSubject
});
action,
aggregationNeed,
comparisonNeed,
rankingNeed,
openScopeWithoutSubject,
metadataScopedOpenLaneWithoutSubject
});
const reasonCodes: string[] = [];
pushReason(reasonCodes, "data_need_graph_built");
if (businessFactFamily) {
@@ -418,6 +455,9 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
if (openScopeWithoutSubject && !rankingNeed && !comparisonNeed) {
pushReason(reasonCodes, "data_need_graph_open_scope_total_without_subject");
}
if (metadataScopedOpenLaneWithoutSubject) {
pushReason(reasonCodes, "data_need_graph_metadata_scoped_open_lane_without_subject");
}
if (allTimeScopeHint) {
pushReason(reasonCodes, "data_need_graph_all_time_scope_hint");
}
@@ -432,6 +472,8 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
schema_version: ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION,
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
subject_candidates: subjectCandidates,
metadata_scope_hint: metadataScopeHint,
subject_resolution_optional: subjectResolutionOptional || undefined,
business_fact_family: businessFactFamily,
action_family: toNonEmptyString(turnMeaning?.asked_action_family),
aggregation_need: aggregationNeed,