ARCH: добавить вывод длительности активности MCP discovery
This commit is contained in:
parent
72804557aa
commit
e85d456576
|
|
@ -1045,6 +1045,52 @@ Known next quality gap:
|
|||
|
||||
- the guarded candidate is now honest and safe, but it still does not compute and verbalize the exact activity duration such as "5 years N months" from first/latest confirmed rows. That belongs to the next evidence-derivation slice, not to the response gate itself.
|
||||
|
||||
## Progress Update - 2026-04-20 MCP Discovery Activity Duration Derivation
|
||||
|
||||
The fifteenth implementation slice of Big Block 5 closed the next quality gap in the guarded discovery answer:
|
||||
|
||||
- `assistantMcpDiscoveryPilotExecutor.ts`
|
||||
- `assistantMcpDiscoveryAnswerAdapter.ts`
|
||||
- `assistantMcpDiscoveryPilotExecutor.test.ts`
|
||||
- `assistantMcpDiscoveryAnswerAdapter.test.ts`
|
||||
- strengthened `address_truth_harness_phase19_mcp_discovery_response_gate.json`
|
||||
|
||||
The pilot now extracts a structured `derived_activity_period` from confirmed lifecycle rows:
|
||||
|
||||
- `first_activity_date`;
|
||||
- `latest_activity_date`;
|
||||
- `matched_rows`;
|
||||
- `duration_total_months`;
|
||||
- `duration_years`;
|
||||
- `duration_months_remainder`;
|
||||
- `duration_human_ru`;
|
||||
- `inference_basis=first_and_latest_confirmed_1c_activity_rows`.
|
||||
|
||||
The answer adapter now verbalizes this as a user-facing bounded inference.
|
||||
|
||||
Example from the successful replay:
|
||||
|
||||
- first activity: `2014-10-06`;
|
||||
- latest activity: `2022-04-13`;
|
||||
- derived duration: `7 лет 6 месяцев`;
|
||||
- answer wording: "По подтвержденным строкам активности в 1С период взаимодействия можно оценить примерно как 7 лет 6 месяцев... Это вывод по данным 1С, а не юридически подтвержденный возраст регистрации."
|
||||
|
||||
The generic inference sentence is suppressed when the structured duration line exists, so the final answer stays compact instead of repeating the same idea twice.
|
||||
|
||||
Replay result:
|
||||
|
||||
- `address_truth_harness_phase19_mcp_discovery_response_gate_live_rerun2` passed 4/4 after adding duration acceptance;
|
||||
- `address_truth_harness_phase19_mcp_discovery_response_gate_live_rerun3` passed 4/4 after removing duplicate generic inference wording;
|
||||
- final status stayed `accepted`;
|
||||
- lifecycle answer source stayed `mcp_discovery_response_candidate_guarded`;
|
||||
- debug confirmed `mcp_discovery_response_applied=true` and populated `derived_activity_period`.
|
||||
|
||||
Validation:
|
||||
|
||||
- `npm test -- assistantMcpDiscoveryPilotExecutor.test.ts assistantMcpDiscoveryAnswerAdapter.test.ts assistantMcpDiscoveryResponseCandidate.test.ts assistantMcpDiscoveryResponsePolicy.test.ts assistantLivingChatRuntimeAdapter.test.ts` passed 28/28;
|
||||
- `npm run build` passed;
|
||||
- `python scripts/domain_truth_harness.py run-live --spec docs/orchestration/address_truth_harness_phase19_mcp_discovery_response_gate.json --output-dir artifacts/domain_runs/address_truth_harness_phase19_mcp_discovery_response_gate_live_rerun3 --timeout-seconds 180` passed 4/4, final status `accepted`.
|
||||
|
||||
## Execution Rule
|
||||
|
||||
Do not implement this plan as:
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@
|
|||
"(?i)свк",
|
||||
"(?i)1с|активност|подтвержд",
|
||||
"(?i)вывод|оцен|инфер|можно оцен",
|
||||
"(?i)лет|год|месяц",
|
||||
"(?i)юридическ|регистрац|не подтвержд|не доказ"
|
||||
],
|
||||
"forbidden_answer_patterns": [
|
||||
|
|
|
|||
|
|
@ -97,6 +97,17 @@ function buildMustNotClaim(pilot) {
|
|||
}
|
||||
return claims;
|
||||
}
|
||||
function derivedActivityInferenceLine(pilot) {
|
||||
const period = pilot.derived_activity_period;
|
||||
if (!period) {
|
||||
return null;
|
||||
}
|
||||
return [
|
||||
`По подтвержденным строкам активности в 1С период взаимодействия можно оценить примерно как ${period.duration_human_ru}.`,
|
||||
`Первая найденная активность: ${period.first_activity_date}; последняя найденная активность: ${period.latest_activity_date}.`,
|
||||
"Это вывод по данным 1С, а не юридически подтвержденный возраст регистрации."
|
||||
].join(" ");
|
||||
}
|
||||
function buildAssistantMcpDiscoveryAnswerDraft(pilot) {
|
||||
const mode = modeFor(pilot);
|
||||
const reasonCodes = [...pilot.reason_codes, ...pilot.evidence.reason_codes];
|
||||
|
|
@ -107,13 +118,17 @@ function buildAssistantMcpDiscoveryAnswerDraft(pilot) {
|
|||
if (pilot.evidence.inferred_facts.length > 0) {
|
||||
pushReason(reasonCodes, "answer_contains_bounded_inference");
|
||||
}
|
||||
const derivedInferenceLine = derivedActivityInferenceLine(pilot);
|
||||
const inferenceLines = derivedInferenceLine
|
||||
? [derivedInferenceLine]
|
||||
: pilot.evidence.inferred_facts;
|
||||
return {
|
||||
schema_version: exports.ASSISTANT_MCP_DISCOVERY_ANSWER_DRAFT_SCHEMA_VERSION,
|
||||
policy_owner: "assistantMcpDiscoveryAnswerAdapter",
|
||||
answer_mode: mode,
|
||||
headline: headlineFor(mode),
|
||||
confirmed_lines: uniqueStrings(pilot.evidence.confirmed_facts),
|
||||
inference_lines: uniqueStrings(pilot.evidence.inferred_facts),
|
||||
inference_lines: uniqueStrings(inferenceLines),
|
||||
unknown_lines: uniqueStrings(pilot.evidence.unknown_facts),
|
||||
limitation_lines: userFacingLimitations([...pilot.query_limitations, ...pilot.evidence.query_limitations]),
|
||||
next_step_line: nextStepFor(mode, pilot),
|
||||
|
|
|
|||
|
|
@ -116,6 +116,74 @@ function summarizeRows(result) {
|
|||
}
|
||||
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched lifecycle scope`;
|
||||
}
|
||||
function rowDateValue(row) {
|
||||
const candidates = [
|
||||
row["Период"],
|
||||
row["Period"],
|
||||
row["period"],
|
||||
row["Дата"],
|
||||
row["Date"],
|
||||
row["date"]
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
const text = toNonEmptyString(candidate);
|
||||
const match = text?.match(/(\d{4})-(\d{2})-(\d{2})/);
|
||||
if (match) {
|
||||
return `${match[1]}-${match[2]}-${match[3]}`;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function monthDiff(firstIsoDate, latestIsoDate) {
|
||||
const first = new Date(`${firstIsoDate}T00:00:00.000Z`);
|
||||
const latest = new Date(`${latestIsoDate}T00:00:00.000Z`);
|
||||
if (Number.isNaN(first.getTime()) || Number.isNaN(latest.getTime()) || latest < first) {
|
||||
return 0;
|
||||
}
|
||||
let months = (latest.getUTCFullYear() - first.getUTCFullYear()) * 12;
|
||||
months += latest.getUTCMonth() - first.getUTCMonth();
|
||||
if (latest.getUTCDate() < first.getUTCDate()) {
|
||||
months -= 1;
|
||||
}
|
||||
return Math.max(0, months);
|
||||
}
|
||||
function formatDurationHumanRu(totalMonths) {
|
||||
const years = Math.floor(totalMonths / 12);
|
||||
const months = totalMonths % 12;
|
||||
const parts = [];
|
||||
if (years > 0) {
|
||||
parts.push(`${years} ${years === 1 ? "год" : years >= 2 && years <= 4 ? "года" : "лет"}`);
|
||||
}
|
||||
if (months > 0) {
|
||||
parts.push(`${months} ${months === 1 ? "месяц" : months >= 2 && months <= 4 ? "месяца" : "месяцев"}`);
|
||||
}
|
||||
return parts.length > 0 ? parts.join(" ") : "меньше месяца";
|
||||
}
|
||||
function deriveActivityPeriod(result) {
|
||||
if (!result || result.error || result.matched_rows <= 0) {
|
||||
return null;
|
||||
}
|
||||
const dates = result.rows
|
||||
.map((row) => rowDateValue(row))
|
||||
.filter((value) => Boolean(value))
|
||||
.sort();
|
||||
if (dates.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const first = dates[0];
|
||||
const latest = dates[dates.length - 1];
|
||||
const totalMonths = monthDiff(first, latest);
|
||||
return {
|
||||
first_activity_date: first,
|
||||
latest_activity_date: latest,
|
||||
matched_rows: result.matched_rows,
|
||||
duration_total_months: totalMonths,
|
||||
duration_years: Math.floor(totalMonths / 12),
|
||||
duration_months_remainder: totalMonths % 12,
|
||||
duration_human_ru: formatDurationHumanRu(totalMonths),
|
||||
inference_basis: "first_and_latest_confirmed_1c_activity_rows"
|
||||
};
|
||||
}
|
||||
function buildConfirmedFacts(result, counterparty) {
|
||||
if (result.error || result.matched_rows <= 0) {
|
||||
return [];
|
||||
|
|
@ -166,6 +234,7 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: null,
|
||||
derived_activity_period: null,
|
||||
query_limitations: ["MCP discovery pilot was blocked before execution"],
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
@ -185,6 +254,7 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: null,
|
||||
derived_activity_period: null,
|
||||
query_limitations: ["MCP discovery pilot needs more scope before execution"],
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
@ -208,6 +278,7 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: null,
|
||||
derived_activity_period: null,
|
||||
query_limitations: ["MCP discovery pilot scope is not implemented yet"],
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
@ -231,6 +302,7 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: null,
|
||||
derived_activity_period: null,
|
||||
query_limitations: ["Lifecycle recipe is not available"],
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
@ -258,6 +330,10 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
|||
}
|
||||
}
|
||||
const sourceRowsSummary = queryResult ? summarizeRows(queryResult) : null;
|
||||
const derivedActivityPeriod = deriveActivityPeriod(queryResult);
|
||||
if (derivedActivityPeriod) {
|
||||
pushReason(reasonCodes, "pilot_derived_activity_period_from_confirmed_rows");
|
||||
}
|
||||
const evidence = (0, assistantMcpDiscoveryPolicy_1.resolveAssistantMcpDiscoveryEvidence)({
|
||||
plan: planner.discovery_plan,
|
||||
probeResults,
|
||||
|
|
@ -280,6 +356,7 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: sourceRowsSummary,
|
||||
derived_activity_period: derivedActivityPeriod,
|
||||
query_limitations: queryLimitations,
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
|
|||
|
|
@ -130,6 +130,18 @@ function buildMustNotClaim(pilot: AssistantMcpDiscoveryPilotExecutionContract):
|
|||
return claims;
|
||||
}
|
||||
|
||||
function derivedActivityInferenceLine(pilot: AssistantMcpDiscoveryPilotExecutionContract): string | null {
|
||||
const period = pilot.derived_activity_period;
|
||||
if (!period) {
|
||||
return null;
|
||||
}
|
||||
return [
|
||||
`По подтвержденным строкам активности в 1С период взаимодействия можно оценить примерно как ${period.duration_human_ru}.`,
|
||||
`Первая найденная активность: ${period.first_activity_date}; последняя найденная активность: ${period.latest_activity_date}.`,
|
||||
"Это вывод по данным 1С, а не юридически подтвержденный возраст регистрации."
|
||||
].join(" ");
|
||||
}
|
||||
|
||||
export function buildAssistantMcpDiscoveryAnswerDraft(
|
||||
pilot: AssistantMcpDiscoveryPilotExecutionContract
|
||||
): AssistantMcpDiscoveryAnswerDraftContract {
|
||||
|
|
@ -142,6 +154,10 @@ export function buildAssistantMcpDiscoveryAnswerDraft(
|
|||
if (pilot.evidence.inferred_facts.length > 0) {
|
||||
pushReason(reasonCodes, "answer_contains_bounded_inference");
|
||||
}
|
||||
const derivedInferenceLine = derivedActivityInferenceLine(pilot);
|
||||
const inferenceLines = derivedInferenceLine
|
||||
? [derivedInferenceLine]
|
||||
: pilot.evidence.inferred_facts;
|
||||
|
||||
return {
|
||||
schema_version: ASSISTANT_MCP_DISCOVERY_ANSWER_DRAFT_SCHEMA_VERSION,
|
||||
|
|
@ -149,7 +165,7 @@ export function buildAssistantMcpDiscoveryAnswerDraft(
|
|||
answer_mode: mode,
|
||||
headline: headlineFor(mode),
|
||||
confirmed_lines: uniqueStrings(pilot.evidence.confirmed_facts),
|
||||
inference_lines: uniqueStrings(pilot.evidence.inferred_facts),
|
||||
inference_lines: uniqueStrings(inferenceLines),
|
||||
unknown_lines: uniqueStrings(pilot.evidence.unknown_facts),
|
||||
limitation_lines: userFacingLimitations([...pilot.query_limitations, ...pilot.evidence.query_limitations]),
|
||||
next_step_line: nextStepFor(mode, pilot),
|
||||
|
|
|
|||
|
|
@ -29,6 +29,17 @@ export interface AssistantMcpDiscoveryPilotExecutorDeps {
|
|||
executeAddressMcpQuery: typeof executeAddressMcpQuery;
|
||||
}
|
||||
|
||||
export interface AssistantMcpDiscoveryDerivedActivityPeriod {
|
||||
first_activity_date: string;
|
||||
latest_activity_date: string;
|
||||
matched_rows: number;
|
||||
duration_total_months: number;
|
||||
duration_years: number;
|
||||
duration_months_remainder: number;
|
||||
duration_human_ru: string;
|
||||
inference_basis: "first_and_latest_confirmed_1c_activity_rows";
|
||||
}
|
||||
|
||||
export interface AssistantMcpDiscoveryPilotExecutionContract {
|
||||
schema_version: typeof ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION;
|
||||
policy_owner: "assistantMcpDiscoveryPilotExecutor";
|
||||
|
|
@ -41,6 +52,7 @@ export interface AssistantMcpDiscoveryPilotExecutionContract {
|
|||
probe_results: AssistantMcpDiscoveryProbeResult[];
|
||||
evidence: AssistantMcpDiscoveryEvidenceContract;
|
||||
source_rows_summary: string | null;
|
||||
derived_activity_period: AssistantMcpDiscoveryDerivedActivityPeriod | null;
|
||||
query_limitations: string[];
|
||||
reason_codes: string[];
|
||||
}
|
||||
|
|
@ -173,6 +185,80 @@ function summarizeRows(result: AddressMcpQueryExecutorResult): string | null {
|
|||
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched lifecycle scope`;
|
||||
}
|
||||
|
||||
function rowDateValue(row: Record<string, unknown>): string | null {
|
||||
const candidates = [
|
||||
row["Период"],
|
||||
row["Period"],
|
||||
row["period"],
|
||||
row["Дата"],
|
||||
row["Date"],
|
||||
row["date"]
|
||||
];
|
||||
for (const candidate of candidates) {
|
||||
const text = toNonEmptyString(candidate);
|
||||
const match = text?.match(/(\d{4})-(\d{2})-(\d{2})/);
|
||||
if (match) {
|
||||
return `${match[1]}-${match[2]}-${match[3]}`;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function monthDiff(firstIsoDate: string, latestIsoDate: string): number {
|
||||
const first = new Date(`${firstIsoDate}T00:00:00.000Z`);
|
||||
const latest = new Date(`${latestIsoDate}T00:00:00.000Z`);
|
||||
if (Number.isNaN(first.getTime()) || Number.isNaN(latest.getTime()) || latest < first) {
|
||||
return 0;
|
||||
}
|
||||
let months = (latest.getUTCFullYear() - first.getUTCFullYear()) * 12;
|
||||
months += latest.getUTCMonth() - first.getUTCMonth();
|
||||
if (latest.getUTCDate() < first.getUTCDate()) {
|
||||
months -= 1;
|
||||
}
|
||||
return Math.max(0, months);
|
||||
}
|
||||
|
||||
function formatDurationHumanRu(totalMonths: number): string {
|
||||
const years = Math.floor(totalMonths / 12);
|
||||
const months = totalMonths % 12;
|
||||
const parts: string[] = [];
|
||||
if (years > 0) {
|
||||
parts.push(`${years} ${years === 1 ? "год" : years >= 2 && years <= 4 ? "года" : "лет"}`);
|
||||
}
|
||||
if (months > 0) {
|
||||
parts.push(`${months} ${months === 1 ? "месяц" : months >= 2 && months <= 4 ? "месяца" : "месяцев"}`);
|
||||
}
|
||||
return parts.length > 0 ? parts.join(" ") : "меньше месяца";
|
||||
}
|
||||
|
||||
function deriveActivityPeriod(
|
||||
result: AddressMcpQueryExecutorResult | null
|
||||
): AssistantMcpDiscoveryDerivedActivityPeriod | null {
|
||||
if (!result || result.error || result.matched_rows <= 0) {
|
||||
return null;
|
||||
}
|
||||
const dates = result.rows
|
||||
.map((row) => rowDateValue(row))
|
||||
.filter((value): value is string => Boolean(value))
|
||||
.sort();
|
||||
if (dates.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const first = dates[0];
|
||||
const latest = dates[dates.length - 1];
|
||||
const totalMonths = monthDiff(first, latest);
|
||||
return {
|
||||
first_activity_date: first,
|
||||
latest_activity_date: latest,
|
||||
matched_rows: result.matched_rows,
|
||||
duration_total_months: totalMonths,
|
||||
duration_years: Math.floor(totalMonths / 12),
|
||||
duration_months_remainder: totalMonths % 12,
|
||||
duration_human_ru: formatDurationHumanRu(totalMonths),
|
||||
inference_basis: "first_and_latest_confirmed_1c_activity_rows"
|
||||
};
|
||||
}
|
||||
|
||||
function buildConfirmedFacts(result: AddressMcpQueryExecutorResult, counterparty: string | null): string[] {
|
||||
if (result.error || result.matched_rows <= 0) {
|
||||
return [];
|
||||
|
|
@ -236,6 +322,7 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: null,
|
||||
derived_activity_period: null,
|
||||
query_limitations: ["MCP discovery pilot was blocked before execution"],
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
@ -256,6 +343,7 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: null,
|
||||
derived_activity_period: null,
|
||||
query_limitations: ["MCP discovery pilot needs more scope before execution"],
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
@ -280,6 +368,7 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: null,
|
||||
derived_activity_period: null,
|
||||
query_limitations: ["MCP discovery pilot scope is not implemented yet"],
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
@ -304,6 +393,7 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: null,
|
||||
derived_activity_period: null,
|
||||
query_limitations: ["Lifecycle recipe is not available"],
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
@ -332,6 +422,10 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|||
}
|
||||
|
||||
const sourceRowsSummary = queryResult ? summarizeRows(queryResult) : null;
|
||||
const derivedActivityPeriod = deriveActivityPeriod(queryResult);
|
||||
if (derivedActivityPeriod) {
|
||||
pushReason(reasonCodes, "pilot_derived_activity_period_from_confirmed_rows");
|
||||
}
|
||||
const evidence = resolveAssistantMcpDiscoveryEvidence({
|
||||
plan: planner.discovery_plan,
|
||||
probeResults,
|
||||
|
|
@ -355,6 +449,7 @@ export async function executeAssistantMcpDiscoveryPilot(
|
|||
probe_results: probeResults,
|
||||
evidence,
|
||||
source_rows_summary: sourceRowsSummary,
|
||||
derived_activity_period: derivedActivityPeriod,
|
||||
query_limitations: queryLimitations,
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ describe("assistant MCP discovery answer adapter", () => {
|
|||
expect(draft.internal_mechanics_allowed).toBe(false);
|
||||
expect(draft.headline).toContain("подтвержденная активность");
|
||||
expect(draft.confirmed_lines[0]).toContain("SVK");
|
||||
expect(draft.inference_lines[0]).toContain("may be inferred");
|
||||
expect(draft.inference_lines[0]).toContain("меньше месяца");
|
||||
expect(draft.inference_lines.join("\n")).toContain("Первая найденная активность: 2020-01-15");
|
||||
expect(draft.inference_lines.join("\n")).toContain("не юридически подтвержденный возраст регистрации");
|
||||
expect(draft.unknown_lines).toContain("Legal registration date is not proven by this MCP discovery pilot");
|
||||
expect(draft.must_not_claim).toContain("Do not present inferred activity duration as a formally confirmed legal fact.");
|
||||
expect(draft.reason_codes).toContain("answer_contains_unknown_fact_boundary");
|
||||
|
|
@ -106,4 +108,30 @@ describe("assistant MCP discovery answer adapter", () => {
|
|||
expect(userFacing).not.toContain("ВЫБРАТЬ");
|
||||
expect(userFacing).not.toContain("primitive");
|
||||
});
|
||||
|
||||
it("verbalizes activity duration from first and latest confirmed 1C rows", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "counterparty_lifecycle",
|
||||
asked_action_family: "activity_duration",
|
||||
explicit_entity_candidates: ["SVK"]
|
||||
}
|
||||
});
|
||||
const pilot = await executeAssistantMcpDiscoveryPilot(
|
||||
planner,
|
||||
buildDeps([
|
||||
{ Period: "2020-01-15T00:00:00", Counterparty: "SVK" },
|
||||
{ Period: "2023-12-20T00:00:00", Counterparty: "SVK" }
|
||||
])
|
||||
);
|
||||
|
||||
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
|
||||
const inferenceText = draft.inference_lines.join("\n");
|
||||
|
||||
expect(inferenceText).toContain("3 года 11 месяцев");
|
||||
expect(inferenceText).toContain("2020-01-15");
|
||||
expect(inferenceText).toContain("2023-12-20");
|
||||
expect(inferenceText).toContain("не юридически подтвержденный возраст регистрации");
|
||||
expect(draft.reason_codes).toContain("pilot_derived_activity_period_from_confirmed_rows");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -39,7 +39,18 @@ describe("assistant MCP discovery pilot executor", () => {
|
|||
expect(result.evidence.inferred_facts[0]).toContain("may be inferred");
|
||||
expect(result.evidence.unknown_facts).toContain("Legal registration date is not proven by this MCP discovery pilot");
|
||||
expect(result.source_rows_summary).toBe("2 MCP document rows fetched, 2 matched lifecycle scope");
|
||||
expect(result.derived_activity_period).toEqual({
|
||||
first_activity_date: "2020-01-15",
|
||||
latest_activity_date: "2023-12-20",
|
||||
matched_rows: 2,
|
||||
duration_total_months: 47,
|
||||
duration_years: 3,
|
||||
duration_months_remainder: 11,
|
||||
duration_human_ru: "3 года 11 месяцев",
|
||||
inference_basis: "first_and_latest_confirmed_1c_activity_rows"
|
||||
});
|
||||
expect(result.reason_codes).toContain("pilot_query_documents_mcp_executed");
|
||||
expect(result.reason_codes).toContain("pilot_derived_activity_period_from_confirmed_rows");
|
||||
|
||||
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
|
||||
const call = deps.executeAddressMcpQuery.mock.calls[0]?.[0];
|
||||
|
|
@ -100,6 +111,7 @@ describe("assistant MCP discovery pilot executor", () => {
|
|||
expect(result.mcp_execution_performed).toBe(true);
|
||||
expect(result.evidence.evidence_status).toBe("insufficient");
|
||||
expect(result.evidence.confirmed_facts).toEqual([]);
|
||||
expect(result.derived_activity_period).toBeNull();
|
||||
expect(result.query_limitations).toContain("MCP fetch failed: timeout");
|
||||
expect(result.reason_codes).toContain("pilot_query_documents_mcp_error");
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue