Уточнить оси доказательств Autonomy Core 1С

This commit is contained in:
dctouch 2026-05-23 18:14:47 +03:00
parent f7314b0212
commit 4d1b25cca7
3 changed files with 92 additions and 6 deletions

View File

@ -34,7 +34,10 @@ function uniqueStrings(values) {
}
return result;
}
function providedAxesFromMeaning(meaning) {
function isExplicitDate(value) {
return Boolean(value && /^\d{4}-\d{2}-\d{2}$/.test(value));
}
function providedAxesFromMeaning(meaning, graph) {
const result = [];
if ((meaning?.explicit_entity_candidates?.length ?? 0) > 0) {
result.push("counterparty");
@ -43,8 +46,15 @@ function providedAxesFromMeaning(meaning) {
if (toNonEmptyString(meaning?.explicit_organization_scope)) {
result.push("organization");
}
if (toNonEmptyString(meaning?.explicit_date_scope)) {
const explicitDateScope = toNonEmptyString(meaning?.explicit_date_scope);
if (explicitDateScope) {
result.push("period");
if (isExplicitDate(explicitDateScope)) {
result.push("as_of_date");
}
}
if (graph?.time_scope_need === "all_time_scope") {
result.push("all_time_scope");
}
if (toNonEmptyString(meaning?.asked_aggregation_axis)) {
result.push("aggregate_axis");
@ -116,7 +126,7 @@ function buildAssistantEvidencePlanner(input) {
const plan = input.discoveryPlan;
const turnMeaning = plan.turn_meaning_ref;
const requiredAxes = uniqueStrings(plan.required_axes);
const providedAxes = providedAxesFromMeaning(turnMeaning);
const providedAxes = providedAxesFromMeaning(turnMeaning, graph);
const graphClarificationGaps = uniqueStrings(graph?.clarification_gaps ?? []);
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)]);

View File

@ -113,7 +113,14 @@ function uniqueStrings(values: unknown[]): string[] {
return result;
}
function providedAxesFromMeaning(meaning: AssistantMcpDiscoveryTurnMeaningRef | null): string[] {
function isExplicitDate(value: string | null): boolean {
return Boolean(value && /^\d{4}-\d{2}-\d{2}$/.test(value));
}
function providedAxesFromMeaning(
meaning: AssistantMcpDiscoveryTurnMeaningRef | null,
graph: AssistantMcpDiscoveryDataNeedGraphContract | null
): string[] {
const result: string[] = [];
if ((meaning?.explicit_entity_candidates?.length ?? 0) > 0) {
result.push("counterparty");
@ -122,8 +129,15 @@ function providedAxesFromMeaning(meaning: AssistantMcpDiscoveryTurnMeaningRef |
if (toNonEmptyString(meaning?.explicit_organization_scope)) {
result.push("organization");
}
if (toNonEmptyString(meaning?.explicit_date_scope)) {
const explicitDateScope = toNonEmptyString(meaning?.explicit_date_scope);
if (explicitDateScope) {
result.push("period");
if (isExplicitDate(explicitDateScope)) {
result.push("as_of_date");
}
}
if (graph?.time_scope_need === "all_time_scope") {
result.push("all_time_scope");
}
if (toNonEmptyString(meaning?.asked_aggregation_axis)) {
result.push("aggregate_axis");
@ -209,7 +223,7 @@ export function buildAssistantEvidencePlanner(
const plan = input.discoveryPlan;
const turnMeaning = plan.turn_meaning_ref;
const requiredAxes = uniqueStrings(plan.required_axes);
const providedAxes = providedAxesFromMeaning(turnMeaning);
const providedAxes = providedAxesFromMeaning(turnMeaning, graph);
const graphClarificationGaps = uniqueStrings(graph?.clarification_gaps ?? []);
const additionalAxisGaps = uniqueStrings(input.additionalMissingAxes ?? []).filter(
(axis) => !providedAxes.includes(axis) && (requiredAxes.includes(axis) || USER_ACTIONABLE_AXIS_SET.has(axis)),

View File

@ -95,6 +95,68 @@ describe("assistant MCP discovery planner", () => {
expect(result.reason_codes).toContain("planner_selected_chain_matches_catalog_top");
});
it("treats an explicit date as a provided as-of-date evidence axis", () => {
const result = planAssistantMcpDiscovery({
dataNeedGraph: {
schema_version: "assistant_data_need_graph_v1",
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
subject_candidates: [],
business_fact_family: "inventory_stock_snapshot",
action_family: "stock_snapshot",
aggregation_need: null,
time_scope_need: "as_of_date_required",
comparison_need: null,
ranking_need: null,
proof_expectation: "coverage_checked_fact",
clarification_gaps: [],
decomposition_candidates: [],
forbidden_overclaim_flags: ["no_raw_model_claims"],
reason_codes: ["data_need_graph_built"]
},
turnMeaning: {
asked_action_family: "stock_snapshot",
explicit_organization_scope: "Org",
explicit_date_scope: "2020-05-31"
}
});
expect(result.selected_chain_id).toBe("inventory_stock_snapshot");
expect(result.evidence_plan.evidence_axes.required_axes).toContain("as_of_date");
expect(result.evidence_plan.evidence_axes.provided_axes).toContain("period");
expect(result.evidence_plan.evidence_axes.provided_axes).toContain("as_of_date");
expect(result.evidence_plan.evidence_axes.missing_axes).not.toContain("as_of_date");
});
it("treats graph all-time scope as a provided evidence axis", () => {
const result = planAssistantMcpDiscovery({
dataNeedGraph: {
schema_version: "assistant_data_need_graph_v1",
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
subject_candidates: ["SVK"],
business_fact_family: "value_flow",
action_family: "net_value_flow",
aggregation_need: null,
time_scope_need: "all_time_scope",
comparison_need: "incoming_vs_outgoing",
ranking_need: null,
proof_expectation: "coverage_checked_fact",
clarification_gaps: [],
decomposition_candidates: [],
forbidden_overclaim_flags: ["no_raw_model_claims"],
reason_codes: ["data_need_graph_built"]
},
turnMeaning: {
asked_action_family: "net_value_flow",
explicit_entity_candidates: ["SVK"]
}
});
expect(result.selected_chain_id).toBe("value_flow_comparison");
expect(result.evidence_plan.evidence_axes.required_axes).toContain("all_time_scope");
expect(result.evidence_plan.evidence_axes.provided_axes).toContain("all_time_scope");
expect(result.evidence_plan.evidence_axes.missing_axes).not.toContain("all_time_scope");
});
it("keeps representative graph-selected chains aligned with top catalog template matches", () => {
const graph = (
businessFactFamily: string,