Связать evidence planner с route candidate handoff
This commit is contained in:
parent
f34ae5d6df
commit
d64d7f84cc
|
|
@ -57,6 +57,24 @@ function providedAxesFromMeaning(meaning) {
|
|||
function missingAxes(requiredAxes, providedAxes) {
|
||||
return requiredAxes.filter((axis) => !providedAxes.includes(axis));
|
||||
}
|
||||
const USER_ACTIONABLE_AXIS_SET = new Set([
|
||||
"counterparty",
|
||||
"business_entity",
|
||||
"organization",
|
||||
"period",
|
||||
"as_of_date",
|
||||
"item",
|
||||
"supplier",
|
||||
"buyer",
|
||||
"warehouse",
|
||||
"document",
|
||||
"contract",
|
||||
"metadata_scope",
|
||||
"lane_family_choice"
|
||||
]);
|
||||
function userActionableMissingAxes(axes) {
|
||||
return axes.filter((axis) => USER_ACTIONABLE_AXIS_SET.has(axis));
|
||||
}
|
||||
function coverageExpectationFor(graph) {
|
||||
if (graph?.proof_expectation === "bounded_inference") {
|
||||
return "bounded_inference";
|
||||
|
|
@ -100,7 +118,9 @@ function buildAssistantEvidencePlanner(input) {
|
|||
const requiredAxes = uniqueStrings(plan.required_axes);
|
||||
const providedAxes = providedAxesFromMeaning(turnMeaning);
|
||||
const graphClarificationGaps = uniqueStrings(graph?.clarification_gaps ?? []);
|
||||
const axisGaps = missingAxes(requiredAxes, providedAxes);
|
||||
const additionalAxisGaps = uniqueStrings(input.additionalMissingAxes ?? []).filter((axis) => !providedAxes.includes(axis) && (requiredAxes.includes(axis) || USER_ACTIONABLE_AXIS_SET.has(axis)));
|
||||
const axisGaps = uniqueStrings([...additionalAxisGaps, ...missingAxes(requiredAxes, providedAxes)]);
|
||||
const actionableAxisGaps = userActionableMissingAxes(axisGaps);
|
||||
const clarificationGaps = uniqueStrings([...graphClarificationGaps, ...axisGaps]);
|
||||
const coverageExpectation = coverageExpectationFor(graph);
|
||||
const answerMode = answerModeFor({
|
||||
|
|
@ -135,6 +155,7 @@ function buildAssistantEvidencePlanner(input) {
|
|||
required_axes: requiredAxes,
|
||||
provided_axes: providedAxes,
|
||||
missing_axes: axisGaps,
|
||||
user_actionable_missing_axes: actionableAxisGaps,
|
||||
clarification_gaps: clarificationGaps
|
||||
},
|
||||
primitive_plan: {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,9 @@ function buildAssistantMcpDiscoveryDebugAttachmentFields(input) {
|
|||
mcp_discovery_route_candidate_fact_family: toNonEmptyString(routeCandidate?.business_fact_family),
|
||||
mcp_discovery_route_candidate_action_family: toNonEmptyString(routeCandidate?.action_family),
|
||||
mcp_discovery_route_candidate_proof_expectation: toNonEmptyString(routeCandidate?.proof_expectation),
|
||||
mcp_discovery_route_candidate_evidence_plan_status: toNonEmptyString(routeCandidate?.evidence_plan_status),
|
||||
mcp_discovery_route_candidate_evidence_answer_mode: toNonEmptyString(routeCandidate?.evidence_answer_mode),
|
||||
mcp_discovery_route_candidate_evidence_expected_coverage: toNonEmptyString(routeCandidate?.evidence_expected_coverage),
|
||||
mcp_discovery_route_candidate_missing_axes: toStringArray(routeCandidate?.missing_axes),
|
||||
mcp_discovery_route_candidate_provided_axes: toStringArray(routeCandidate?.provided_axes),
|
||||
mcp_discovery_route_candidate_executable_now: routeCandidate?.executable_now === true,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,16 @@ function pushAllUnique(target, values) {
|
|||
pushUnique(target, value);
|
||||
}
|
||||
}
|
||||
function uniqueStringList(values) {
|
||||
const result = [];
|
||||
for (const value of values) {
|
||||
const text = toNonEmptyString(value);
|
||||
if (text) {
|
||||
pushUnique(result, text);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function pushCatalogChainTemplateAlignmentReasons(target, alignment) {
|
||||
if (alignment.alignment_status === "selected_matches_top") {
|
||||
pushReason(target, "planner_catalog_chain_template_alignment_evaluated");
|
||||
|
|
@ -1078,6 +1088,55 @@ function statusFrom(plan, review) {
|
|||
}
|
||||
return "ready_for_execution";
|
||||
}
|
||||
function providedAxesFromPlanTurnMeaning(plan) {
|
||||
const result = [];
|
||||
const meaning = plan.turn_meaning_ref;
|
||||
if ((meaning?.explicit_entity_candidates?.length ?? 0) > 0) {
|
||||
pushUnique(result, "counterparty");
|
||||
pushUnique(result, "business_entity");
|
||||
}
|
||||
if (toNonEmptyString(meaning?.explicit_organization_scope)) {
|
||||
pushUnique(result, "organization");
|
||||
}
|
||||
if (toNonEmptyString(meaning?.explicit_date_scope)) {
|
||||
pushUnique(result, "period");
|
||||
}
|
||||
if (toNonEmptyString(meaning?.asked_aggregation_axis)) {
|
||||
pushUnique(result, "aggregate_axis");
|
||||
}
|
||||
if (toNonEmptyString(meaning?.metadata_scope_hint)) {
|
||||
pushUnique(result, "metadata_scope");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function preferredClarificationAxesForRecipe(input) {
|
||||
if (input.recipe.chainId === "value_flow_ranking" ||
|
||||
input.recipe.chainId === "value_flow_comparison" ||
|
||||
input.recipe.chainId === "business_overview") {
|
||||
return ["organization"];
|
||||
}
|
||||
if (input.dataNeedGraph?.business_fact_family === "value_flow" && !hasSubjectCandidates(input.dataNeedGraph)) {
|
||||
return ["organization"];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
function missingAxesFromCatalogReview(review, input) {
|
||||
const result = [];
|
||||
for (const options of Object.values(review.missing_axes_by_primitive)) {
|
||||
const candidates = options
|
||||
.map((option) => uniqueStringList(option).filter((axis) => !input.providedAxes.includes(axis)))
|
||||
.filter((option) => option.length > 0);
|
||||
const preferredCandidate = candidates.find((option) => option.some((axis) => input.preferredAxes.includes(axis)));
|
||||
const candidate = preferredCandidate ?? candidates.sort((left, right) => left.length - right.length)[0];
|
||||
if (!candidate) {
|
||||
continue;
|
||||
}
|
||||
for (const axis of candidate) {
|
||||
pushUnique(result, axis);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function planAssistantMcpDiscovery(input) {
|
||||
const recipe = recipeFor(input);
|
||||
const budgetOverride = budgetOverrideFor(input, recipe);
|
||||
|
|
@ -1145,7 +1204,11 @@ function planAssistantMcpDiscovery(input) {
|
|||
plannerStatus,
|
||||
semanticDataNeed,
|
||||
dataNeedGraph,
|
||||
discoveryPlan: plan
|
||||
discoveryPlan: plan,
|
||||
additionalMissingAxes: missingAxesFromCatalogReview(adjustedReview, {
|
||||
providedAxes: providedAxesFromPlanTurnMeaning(plan),
|
||||
preferredAxes: preferredClarificationAxesForRecipe({ recipe, dataNeedGraph })
|
||||
})
|
||||
});
|
||||
return {
|
||||
schema_version: exports.ASSISTANT_MCP_DISCOVERY_PLANNER_SCHEMA_VERSION,
|
||||
|
|
|
|||
|
|
@ -185,8 +185,13 @@ function routeCandidateNextAction(status) {
|
|||
}
|
||||
function buildRouteCandidate(planner, pilot, bridgeStatus) {
|
||||
const plannerClarificationGaps = planner.discovery_plan.clarification_gaps ?? [];
|
||||
const providedAxes = flattenAxes(pilot, "provided_axes");
|
||||
const missingAxes = plannerClarificationGaps.length > 0 ? plannerClarificationGaps : flattenAxes(pilot, "missing_axis_options");
|
||||
const evidenceAxes = planner.evidence_plan.evidence_axes;
|
||||
const providedAxes = uniqueStrings([...evidenceAxes.provided_axes, ...flattenAxes(pilot, "provided_axes")]);
|
||||
const missingAxes = plannerClarificationGaps.length > 0
|
||||
? plannerClarificationGaps
|
||||
: evidenceAxes.user_actionable_missing_axes.length > 0
|
||||
? evidenceAxes.user_actionable_missing_axes
|
||||
: flattenAxes(pilot, "missing_axis_options");
|
||||
const missingProofFamily = routeCandidateMissingProofFamily(planner, pilot);
|
||||
const candidateStatus = routeCandidateStatusFor(bridgeStatus, pilot, missingProofFamily);
|
||||
return {
|
||||
|
|
@ -197,9 +202,12 @@ function buildRouteCandidate(planner, pilot, bridgeStatus) {
|
|||
selected_chain_summary: planner.selected_chain_summary,
|
||||
nearest_catalog_chain_template: planner.catalog_chain_template_alignment.top_chain_template_match,
|
||||
catalog_alignment_status: planner.catalog_chain_template_alignment.alignment_status,
|
||||
business_fact_family: planner.data_need_graph?.business_fact_family ?? null,
|
||||
action_family: planner.data_need_graph?.action_family ?? null,
|
||||
proof_expectation: planner.data_need_graph?.proof_expectation ?? null,
|
||||
business_fact_family: planner.evidence_plan.data_need.business_fact_family,
|
||||
action_family: planner.evidence_plan.data_need.action_family,
|
||||
proof_expectation: planner.evidence_plan.data_need.proof_expectation,
|
||||
evidence_plan_status: planner.evidence_plan.planner_status,
|
||||
evidence_answer_mode: planner.evidence_plan.answer_contract.answer_mode,
|
||||
evidence_expected_coverage: planner.evidence_plan.coverage_gate.expected_coverage,
|
||||
required_axes: [...planner.required_axes],
|
||||
provided_axes: providedAxes,
|
||||
missing_axes: missingAxes,
|
||||
|
|
@ -207,7 +215,7 @@ function buildRouteCandidate(planner, pilot, bridgeStatus) {
|
|||
enablement_reason: routeCandidateEnablementReason(candidateStatus, pilot, missingAxes, missingProofFamily),
|
||||
recommended_next_action: routeCandidateNextAction(candidateStatus),
|
||||
forbidden_overclaim_flags: uniqueStrings([
|
||||
...(planner.data_need_graph?.forbidden_overclaim_flags ?? []),
|
||||
...planner.evidence_plan.answer_contract.forbidden_overclaim_flags,
|
||||
...(missingProofFamily ? [missingProofFamily.must_not_claim] : [])
|
||||
])
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export interface AssistantEvidenceAxesContract {
|
|||
required_axes: string[];
|
||||
provided_axes: string[];
|
||||
missing_axes: string[];
|
||||
user_actionable_missing_axes: string[];
|
||||
clarification_gaps: string[];
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ export interface BuildAssistantEvidencePlannerInput {
|
|||
semanticDataNeed?: string | null;
|
||||
dataNeedGraph?: AssistantMcpDiscoveryDataNeedGraphContract | null;
|
||||
discoveryPlan: AssistantMcpDiscoveryPlanContract;
|
||||
additionalMissingAxes?: string[] | null;
|
||||
}
|
||||
|
||||
function toNonEmptyString(value: unknown): string | null {
|
||||
|
|
@ -136,6 +138,26 @@ function missingAxes(requiredAxes: string[], providedAxes: string[]): string[] {
|
|||
return requiredAxes.filter((axis) => !providedAxes.includes(axis));
|
||||
}
|
||||
|
||||
const USER_ACTIONABLE_AXIS_SET = new Set([
|
||||
"counterparty",
|
||||
"business_entity",
|
||||
"organization",
|
||||
"period",
|
||||
"as_of_date",
|
||||
"item",
|
||||
"supplier",
|
||||
"buyer",
|
||||
"warehouse",
|
||||
"document",
|
||||
"contract",
|
||||
"metadata_scope",
|
||||
"lane_family_choice"
|
||||
]);
|
||||
|
||||
function userActionableMissingAxes(axes: string[]): string[] {
|
||||
return axes.filter((axis) => USER_ACTIONABLE_AXIS_SET.has(axis));
|
||||
}
|
||||
|
||||
function coverageExpectationFor(
|
||||
graph: AssistantMcpDiscoveryDataNeedGraphContract | null
|
||||
): AssistantEvidenceCoverageExpectation {
|
||||
|
|
@ -189,7 +211,11 @@ export function buildAssistantEvidencePlanner(
|
|||
const requiredAxes = uniqueStrings(plan.required_axes);
|
||||
const providedAxes = providedAxesFromMeaning(turnMeaning);
|
||||
const graphClarificationGaps = uniqueStrings(graph?.clarification_gaps ?? []);
|
||||
const axisGaps = missingAxes(requiredAxes, providedAxes);
|
||||
const additionalAxisGaps = uniqueStrings(input.additionalMissingAxes ?? []).filter(
|
||||
(axis) => !providedAxes.includes(axis) && (requiredAxes.includes(axis) || USER_ACTIONABLE_AXIS_SET.has(axis)),
|
||||
);
|
||||
const axisGaps = uniqueStrings([...additionalAxisGaps, ...missingAxes(requiredAxes, providedAxes)]);
|
||||
const actionableAxisGaps = userActionableMissingAxes(axisGaps);
|
||||
const clarificationGaps = uniqueStrings([...graphClarificationGaps, ...axisGaps]);
|
||||
const coverageExpectation = coverageExpectationFor(graph);
|
||||
const answerMode = answerModeFor({
|
||||
|
|
@ -226,6 +252,7 @@ export function buildAssistantEvidencePlanner(
|
|||
required_axes: requiredAxes,
|
||||
provided_axes: providedAxes,
|
||||
missing_axes: axisGaps,
|
||||
user_actionable_missing_axes: actionableAxisGaps,
|
||||
clarification_gaps: clarificationGaps
|
||||
},
|
||||
primitive_plan: {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ export interface AssistantMcpDiscoveryDebugAttachmentFields {
|
|||
mcp_discovery_route_candidate_fact_family: string | null;
|
||||
mcp_discovery_route_candidate_action_family: string | null;
|
||||
mcp_discovery_route_candidate_proof_expectation: string | null;
|
||||
mcp_discovery_route_candidate_evidence_plan_status: string | null;
|
||||
mcp_discovery_route_candidate_evidence_answer_mode: string | null;
|
||||
mcp_discovery_route_candidate_evidence_expected_coverage: string | null;
|
||||
mcp_discovery_route_candidate_missing_axes: string[];
|
||||
mcp_discovery_route_candidate_provided_axes: string[];
|
||||
mcp_discovery_route_candidate_executable_now: boolean;
|
||||
|
|
@ -135,6 +138,9 @@ export function buildAssistantMcpDiscoveryDebugAttachmentFields(
|
|||
mcp_discovery_route_candidate_fact_family: toNonEmptyString(routeCandidate?.business_fact_family),
|
||||
mcp_discovery_route_candidate_action_family: toNonEmptyString(routeCandidate?.action_family),
|
||||
mcp_discovery_route_candidate_proof_expectation: toNonEmptyString(routeCandidate?.proof_expectation),
|
||||
mcp_discovery_route_candidate_evidence_plan_status: toNonEmptyString(routeCandidate?.evidence_plan_status),
|
||||
mcp_discovery_route_candidate_evidence_answer_mode: toNonEmptyString(routeCandidate?.evidence_answer_mode),
|
||||
mcp_discovery_route_candidate_evidence_expected_coverage: toNonEmptyString(routeCandidate?.evidence_expected_coverage),
|
||||
mcp_discovery_route_candidate_missing_axes: toStringArray(routeCandidate?.missing_axes),
|
||||
mcp_discovery_route_candidate_provided_axes: toStringArray(routeCandidate?.provided_axes),
|
||||
mcp_discovery_route_candidate_executable_now: routeCandidate?.executable_now === true,
|
||||
|
|
|
|||
|
|
@ -158,6 +158,17 @@ function pushAllUnique(target: string[], values: string[]): void {
|
|||
}
|
||||
}
|
||||
|
||||
function uniqueStringList(values: unknown[]): string[] {
|
||||
const result: string[] = [];
|
||||
for (const value of values) {
|
||||
const text = toNonEmptyString(value);
|
||||
if (text) {
|
||||
pushUnique(result, text);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function pushCatalogChainTemplateAlignmentReasons(
|
||||
target: string[],
|
||||
alignment: AssistantMcpDiscoveryCatalogChainTemplateAlignment
|
||||
|
|
@ -1360,6 +1371,69 @@ function statusFrom(
|
|||
return "ready_for_execution";
|
||||
}
|
||||
|
||||
function providedAxesFromPlanTurnMeaning(plan: AssistantMcpDiscoveryPlanContract): string[] {
|
||||
const result: string[] = [];
|
||||
const meaning = plan.turn_meaning_ref;
|
||||
if ((meaning?.explicit_entity_candidates?.length ?? 0) > 0) {
|
||||
pushUnique(result, "counterparty");
|
||||
pushUnique(result, "business_entity");
|
||||
}
|
||||
if (toNonEmptyString(meaning?.explicit_organization_scope)) {
|
||||
pushUnique(result, "organization");
|
||||
}
|
||||
if (toNonEmptyString(meaning?.explicit_date_scope)) {
|
||||
pushUnique(result, "period");
|
||||
}
|
||||
if (toNonEmptyString(meaning?.asked_aggregation_axis)) {
|
||||
pushUnique(result, "aggregate_axis");
|
||||
}
|
||||
if (toNonEmptyString(meaning?.metadata_scope_hint)) {
|
||||
pushUnique(result, "metadata_scope");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function preferredClarificationAxesForRecipe(input: {
|
||||
recipe: PlannerRecipe;
|
||||
dataNeedGraph: AssistantMcpDiscoveryDataNeedGraphContract | null;
|
||||
}): string[] {
|
||||
if (
|
||||
input.recipe.chainId === "value_flow_ranking" ||
|
||||
input.recipe.chainId === "value_flow_comparison" ||
|
||||
input.recipe.chainId === "business_overview"
|
||||
) {
|
||||
return ["organization"];
|
||||
}
|
||||
if (input.dataNeedGraph?.business_fact_family === "value_flow" && !hasSubjectCandidates(input.dataNeedGraph)) {
|
||||
return ["organization"];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function missingAxesFromCatalogReview(
|
||||
review: AssistantMcpCatalogPlanReview,
|
||||
input: {
|
||||
providedAxes: string[];
|
||||
preferredAxes: string[];
|
||||
}
|
||||
): string[] {
|
||||
const result: string[] = [];
|
||||
for (const options of Object.values(review.missing_axes_by_primitive)) {
|
||||
const candidates = options
|
||||
.map((option) => uniqueStringList(option).filter((axis) => !input.providedAxes.includes(axis)))
|
||||
.filter((option) => option.length > 0);
|
||||
const preferredCandidate = candidates.find((option) => option.some((axis) => input.preferredAxes.includes(axis)));
|
||||
const candidate = preferredCandidate ?? candidates.sort((left, right) => left.length - right.length)[0];
|
||||
if (!candidate) {
|
||||
continue;
|
||||
}
|
||||
for (const axis of candidate) {
|
||||
pushUnique(result, axis);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function planAssistantMcpDiscovery(
|
||||
input: AssistantMcpDiscoveryPlannerInput
|
||||
): AssistantMcpDiscoveryPlannerContract {
|
||||
|
|
@ -1432,7 +1506,11 @@ export function planAssistantMcpDiscovery(
|
|||
plannerStatus,
|
||||
semanticDataNeed,
|
||||
dataNeedGraph,
|
||||
discoveryPlan: plan
|
||||
discoveryPlan: plan,
|
||||
additionalMissingAxes: missingAxesFromCatalogReview(adjustedReview, {
|
||||
providedAxes: providedAxesFromPlanTurnMeaning(plan),
|
||||
preferredAxes: preferredClarificationAxesForRecipe({ recipe, dataNeedGraph })
|
||||
})
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ export interface AssistantMcpRouteCandidateContract {
|
|||
business_fact_family: string | null;
|
||||
action_family: string | null;
|
||||
proof_expectation: string | null;
|
||||
evidence_plan_status: string | null;
|
||||
evidence_answer_mode: string | null;
|
||||
evidence_expected_coverage: string | null;
|
||||
required_axes: string[];
|
||||
provided_axes: string[];
|
||||
missing_axes: string[];
|
||||
|
|
@ -326,8 +329,14 @@ function buildRouteCandidate(
|
|||
bridgeStatus: AssistantMcpDiscoveryRuntimeBridgeStatus
|
||||
): AssistantMcpRouteCandidateContract {
|
||||
const plannerClarificationGaps = planner.discovery_plan.clarification_gaps ?? [];
|
||||
const providedAxes = flattenAxes(pilot, "provided_axes");
|
||||
const missingAxes = plannerClarificationGaps.length > 0 ? plannerClarificationGaps : flattenAxes(pilot, "missing_axis_options");
|
||||
const evidenceAxes = planner.evidence_plan.evidence_axes;
|
||||
const providedAxes = uniqueStrings([...evidenceAxes.provided_axes, ...flattenAxes(pilot, "provided_axes")]);
|
||||
const missingAxes =
|
||||
plannerClarificationGaps.length > 0
|
||||
? plannerClarificationGaps
|
||||
: evidenceAxes.user_actionable_missing_axes.length > 0
|
||||
? evidenceAxes.user_actionable_missing_axes
|
||||
: flattenAxes(pilot, "missing_axis_options");
|
||||
const missingProofFamily = routeCandidateMissingProofFamily(planner, pilot);
|
||||
const candidateStatus = routeCandidateStatusFor(bridgeStatus, pilot, missingProofFamily);
|
||||
return {
|
||||
|
|
@ -338,9 +347,12 @@ function buildRouteCandidate(
|
|||
selected_chain_summary: planner.selected_chain_summary,
|
||||
nearest_catalog_chain_template: planner.catalog_chain_template_alignment.top_chain_template_match,
|
||||
catalog_alignment_status: planner.catalog_chain_template_alignment.alignment_status,
|
||||
business_fact_family: planner.data_need_graph?.business_fact_family ?? null,
|
||||
action_family: planner.data_need_graph?.action_family ?? null,
|
||||
proof_expectation: planner.data_need_graph?.proof_expectation ?? null,
|
||||
business_fact_family: planner.evidence_plan.data_need.business_fact_family,
|
||||
action_family: planner.evidence_plan.data_need.action_family,
|
||||
proof_expectation: planner.evidence_plan.data_need.proof_expectation,
|
||||
evidence_plan_status: planner.evidence_plan.planner_status,
|
||||
evidence_answer_mode: planner.evidence_plan.answer_contract.answer_mode,
|
||||
evidence_expected_coverage: planner.evidence_plan.coverage_gate.expected_coverage,
|
||||
required_axes: [...planner.required_axes],
|
||||
provided_axes: providedAxes,
|
||||
missing_axes: missingAxes,
|
||||
|
|
@ -348,7 +360,7 @@ function buildRouteCandidate(
|
|||
enablement_reason: routeCandidateEnablementReason(candidateStatus, pilot, missingAxes, missingProofFamily),
|
||||
recommended_next_action: routeCandidateNextAction(candidateStatus),
|
||||
forbidden_overclaim_flags: uniqueStrings([
|
||||
...(planner.data_need_graph?.forbidden_overclaim_flags ?? []),
|
||||
...planner.evidence_plan.answer_contract.forbidden_overclaim_flags,
|
||||
...(missingProofFamily ? [missingProofFamily.must_not_claim] : [])
|
||||
])
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ function entryPointContract(overrides: Record<string, unknown> = {}) {
|
|||
business_fact_family: "value_flow",
|
||||
action_family: "turnover",
|
||||
proof_expectation: "coverage_checked_fact",
|
||||
evidence_plan_status: "ready_for_execution",
|
||||
evidence_answer_mode: "confirmed_business_answer",
|
||||
evidence_expected_coverage: "confirmed_coverage",
|
||||
required_axes: ["organization", "period"],
|
||||
provided_axes: ["organization", "period"],
|
||||
missing_axes: [],
|
||||
|
|
@ -95,6 +98,9 @@ describe("assistant MCP discovery debug attachment", () => {
|
|||
expect(debug.mcp_discovery_route_candidate_status).toBe("ready_for_reviewed_execution");
|
||||
expect(debug.mcp_discovery_route_candidate_fact_family).toBe("value_flow");
|
||||
expect(debug.mcp_discovery_route_candidate_action_family).toBe("turnover");
|
||||
expect(debug.mcp_discovery_route_candidate_evidence_plan_status).toBe("ready_for_execution");
|
||||
expect(debug.mcp_discovery_route_candidate_evidence_answer_mode).toBe("confirmed_business_answer");
|
||||
expect(debug.mcp_discovery_route_candidate_evidence_expected_coverage).toBe("confirmed_coverage");
|
||||
expect(debug.mcp_discovery_route_candidate_missing_axes).toEqual([]);
|
||||
expect(debug.mcp_discovery_route_candidate_provided_axes).toEqual(["organization", "period"]);
|
||||
expect(debug.mcp_discovery_route_candidate_executable_now).toBe(true);
|
||||
|
|
@ -130,6 +136,9 @@ describe("assistant MCP discovery debug attachment", () => {
|
|||
expect(debug.mcp_discovery_catalog_chain_selected_matches_top).toBe(false);
|
||||
expect(debug.mcp_discovery_route_candidate_v1).toBeNull();
|
||||
expect(debug.mcp_discovery_route_candidate_status).toBeNull();
|
||||
expect(debug.mcp_discovery_route_candidate_evidence_plan_status).toBeNull();
|
||||
expect(debug.mcp_discovery_route_candidate_evidence_answer_mode).toBeNull();
|
||||
expect(debug.mcp_discovery_route_candidate_evidence_expected_coverage).toBeNull();
|
||||
expect(debug.mcp_discovery_route_candidate_missing_axes).toEqual([]);
|
||||
expect(debug.mcp_discovery_route_candidate_provided_axes).toEqual([]);
|
||||
expect(debug.mcp_discovery_route_candidate_executable_now).toBe(false);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ describe("assistant MCP discovery planner", () => {
|
|||
]);
|
||||
expect(result.evidence_plan.evidence_axes.provided_axes).toEqual(["counterparty", "business_entity", "period"]);
|
||||
expect(result.evidence_plan.evidence_axes.missing_axes).toEqual(["aggregate_axis", "amount", "coverage_target"]);
|
||||
expect(result.evidence_plan.evidence_axes.user_actionable_missing_axes).toEqual([]);
|
||||
expect(result.data_need_graph?.business_fact_family).toBe("value_flow");
|
||||
expect(result.catalog_chain_template_matches[0]).toBe("value_flow");
|
||||
expect(result.catalog_chain_template_alignment).toMatchObject({
|
||||
|
|
|
|||
|
|
@ -163,6 +163,13 @@ describe("assistant MCP discovery runtime bridge", () => {
|
|||
});
|
||||
expect(result.loop_state.pending_axes).toContain("organization");
|
||||
expect(result.loop_state.provided_axes).toContain("aggregate_axis");
|
||||
expect(result.planner.evidence_plan.evidence_axes.user_actionable_missing_axes).toEqual(["organization"]);
|
||||
expect(result.planner.evidence_plan.evidence_axes.missing_axes).toEqual([
|
||||
"organization",
|
||||
"aggregate_axis",
|
||||
"amount",
|
||||
"coverage_target"
|
||||
]);
|
||||
expect(result.loop_state.catalog_chain_template_matches[0]).toBe("value_flow_ranking");
|
||||
expect(result.loop_state.catalog_chain_template_alignment.alignment_status).toBe("selected_matches_top");
|
||||
expect(result.loop_state.catalog_chain_template_alignment.selected_chain_matches_top).toBe(true);
|
||||
|
|
@ -174,10 +181,15 @@ describe("assistant MCP discovery runtime bridge", () => {
|
|||
catalog_alignment_status: "selected_matches_top",
|
||||
business_fact_family: "value_flow",
|
||||
action_family: "turnover",
|
||||
evidence_plan_status: "needs_clarification",
|
||||
evidence_answer_mode: "clarification_required",
|
||||
evidence_expected_coverage: "confirmed_coverage",
|
||||
executable_now: false
|
||||
});
|
||||
expect(result.route_candidate.missing_axes).toContain("organization");
|
||||
expect(result.route_candidate.provided_axes).toContain("aggregate_axis");
|
||||
expect(result.route_candidate.missing_axes).not.toContain("amount");
|
||||
expect(result.route_candidate.missing_axes).not.toContain("coverage_target");
|
||||
expect(result.route_candidate.recommended_next_action).toBe(
|
||||
"Ask the user for the missing scope axes before MCP execution."
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue